
5 Einstellungen
5.1 Verwendung des Protokollierungsmoduls
5.1.1 Überblick über die Protokollierung
5.1.2 Aktivierung der Protokollierung
5.1.3 Hinzufügen von Protokollierungen zu Ihrem Code
5.2 Verwendung von Befehlszeilenargumenten
5.2.1 Überschreiben von Standardattributwerten
5.2.2 Erfassen Ihrer eigenen Befehle
5.3 Verwendung des Trace-Systems
5.3.1 ASCII-Traces
Parsing von ASCII-Traces
5.3.2 PCAP-Tracing
Kapitel 5
Konfiguration
5.1 Verwendung des Protokollierungsmoduls
Wir haben bereits kurz das Protokollierungsmodul ns-3 im Skript betrachtet. first.ccIn diesem Kapitel werden wir die möglichen Verwendungsmöglichkeiten der Protokollierungsunterstützung näher untersuchen.
5.1.1 Überblick über die Protokollierung
Viele große Systeme bieten ein gewisses Maß an Protokollierungsmitteln, und ns-3 ist da keine Ausnahme. In einigen Fällen werden im 'Betriebsfenster' (das normalerweise stderr in Unix-basierten Systemen ist) nur Fehlermeldungen protokolliert. In anderen Systemen können Warnmeldungen sowie detailliertere Informationen ausgegeben werden. In einigen Fällen werden die Protokollierungswerkzeuge verwendet, um Debugging-Nachrichten auszugeben, die die Ausgaben schnell 'verwischen' können.
Das Protokoll, das in ns‑3 verwendet wird, geht davon aus, dass all diese Informationsniveaus nützlich sind, und bietet einen selektiven, mehrstufigen Ansatz zur Protokollierung von Nachrichten. Die Protokollierung kann vollständig deaktiviert, für bestimmte Komponenten aktiviert oder global umgesetzt werden. Dafür stehen anpassbare Informationsniveaus zur Verfügung. Das ns‑3-Protokollmodul bietet eine relativ einfache Möglichkeit, nützliche Informationen aus Ihrer Simulation zu erhalten.
Sie sollten verstehen, dass wir einen allgemein verwendbaren Mechanismus - die Nachverfolgung - zur Extraktion von Daten aus Ihren Modellen bereitstellen, der bei der Modellierung bevorzugt verwendet werden sollte (für detailliertere Informationen über unser Nachverfolgungssystem siehe Abschnitt 5.3 des Handbuchs). Die Protokollierung sollte die bevorzugte Methode sein, um Debugging-Informationen, Warnungen, Fehlermeldungen oder schnelle Ausgaben von Nachrichten aus Ihren Skripten oder Modellen jederzeit zu erhalten.
Derzeit sind im System sieben Protokollebene (Typen) definiert, die nach steigender Informativität geordnet sind.
- LOG_ERROR — Registrierung von Fehlermeldungen (assoziierter Makro: NS_LOG_ERROR);
- LOG_WARN — Registrierung von Warnmeldungen (assoziierter Makro: NS_LOG_WARN);
- LOG_DEBUG — Registrierung von relativ seltenen speziellen Debug-Nachrichten (assoziierter Makro: NS_LOG_DEBUG);
- LOG_INFO — Registrierung von Informationsmeldungen über den Programmverlauf (assoziierter Makro: NS_LOG_INFO);
- LOG_FUNCTION — Registrierung von Nachrichten, die jede aufgerufene Funktion beschreiben (zwei assoziierte Makros: NS_LOG_FUNCTION, verwendet für Mitgliedsfunktionen, und NS_LOG_FUNCTION_NOARGS, verwendet für statische Funktionen);
- LOG_LOGIC — Registrierung von Nachrichten, die den logischen Fluss innerhalb einer Funktion beschreiben (assoziierter Makro: NS_LOG_LOGIC);
- LOG_ALL — Registrierung aller oben genannten (kein assoziierter Makro).
Für jeden Typ (LOG_TYPE) gibt es auch einen LOG_LEVEL_TYPE, der, falls verwendet, es ermöglicht, zusätzlich zu seinem eigenen Level alle darüber liegenden Levels zu protokollieren. (Folglich sind LOG_ERROR und LOG_LEVEL_ERROR sowie LOG_ALL und LOG_LEVEL_ALL funktional gleichwertig.) Beispielsweise ermöglicht das Aktivieren von LOG_INFO nur die Anzeige von Nachrichten, die durch das Makro NS_LOG_INFO bereitgestellt werden, während bei Aktivierung von LOG_LEVEL_INFO auch Nachrichten, die durch die Makros NS_LOG_DEBUG, NS_LOG_WARN und NS_LOG_ERROR bereitgestellt werden, einbezogen werden.
Wir bieten auch ein bedingungsloses Protokollierungs-Makro an, das immer angezeigt wird, unabhängig von der Protokollierungsebene oder der Komponente der Auswahl.
- NS_LOG_UNCOND — bedingungslose Registrierung der zugehörigen Nachricht (ohne zugehörige Protokollierungsebene).
Jede Ebene kann einzeln oder kumulativ angefordert werden. Das Protokollieren kann über die Umgebungsvariable sh NS_LOG oder durch den Aufruf einer Systemfunktion konfiguriert werden. Wie zuvor gezeigt, hat das Protokollierungssystem eine Doxygen-Dokumentation, und jetzt ist der beste Zeitpunkt, sie zu überprüfen, falls Sie das noch nicht getan haben.
Jetzt, da Sie die Dokumentation sehr ausführlich gelesen haben, lassen Sie uns dieses Wissen nutzen, um einige interessante Informationen aus dem Beispielszenario zu gewinnen. scratch/myfirst.cc, das Sie bereits kompiliert haben.
5.1.2 Aktivierung der Protokollierung
Lassen Sie uns die Umgebungsvariable NS_LOG verwenden, um noch einige Protokolle zu starten. Aber zuerst, nur um sich zu orientieren, führen Sie das letzte Skript so aus, wie Sie es zuvor getan haben.
$ ./waf --run scratch/myfirstSie sollten bereits die vertraute Ausgabe des ersten Beispiels ns-3-Programms sehen.
$ Waf: Betritt Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Verließ Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' 'build'
Erfolgreich abgeschlossen (0.413s)
1024 Bytes an 10.1.1.2 gesendet
1024 Bytes von 10.1.1.1 empfangen
1024 Bytes von 10.1.1.2 empfangenEs stellt sich heraus, dass die „gesendeten“ und „empfangenen“ Nachrichten, die Sie oben sehen, tatsächlich protokollierte Nachrichten von UdpEchoClientApplication und UdpEchoServerApplication. Zum Beispiel können wir die Clientanwendung bitten, zusätzliche Informationen auszudrucken, indem wir ihr Protokollierungslevel über die Umgebungsvariable NS_LOG festlegen.
Ab diesem Zeitpunkt gehe ich davon aus, dass Sie eine sh-ähnliche Shell verwenden, die die Syntax „VARIABLE = Wert“ verwendet. Wenn Sie eine csh-ähnliche Shell verwenden, müssen Sie meine Beispiele in die Syntax „setenv VARIABLE WERT“ umwandeln, die von diesen Shells benötigt wird.
Momentan reagiert die UDP Echo-Client-Anwendung auf die folgende Codezeile in scratch/myfirst.cc,
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);Dies aktiviert das Protokollierungslevel LOG_LEVEL_INFO. Wenn wir das Logging-Level-Flag setzen, aktivieren wir tatsächlich dieses Level und alle niedrigeren Levels. In diesem Fall haben wir NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN und NS_LOG_ERROR aktiviert. Wir können das Protokollierungslevel erhöhen und mehr Informationen erhalten, ohne das Skript zu ändern oder neu zu kompilieren, indem wir die Umgebungsvariable NS_LOG wie folgt setzen:
$ export NS_LOG=UdpEchoClientApplication=level_allSo setzen wir den folgenden Wert der NS_LOG-Variablen in der sh-Shell:
UdpEchoClientApplication=level_allDie linke Seite der Zuordnung ist der Name der protokollierten Komponente, die wir konfigurieren möchten, und die rechte Seite ist das Flag, das wir dafür anwenden wollen. In diesem Fall werden wir alle Debugging-Stufen in der Anwendung aktivieren. Wenn Sie das Skript mit dem so gesetzten NS_LOG ausführen, wird das ns-3-Loggingsystem die Änderungen annehmen und Sie sollten die folgende Ausgabe sehen:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich abgeschlossen (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
1024 Bytes an 10.1.1.2 gesendet
1024 Bytes von 10.1.1.1 empfangen
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
1024 Bytes von 10.1.1.2 empfangen
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()Zusätzliche Debug-Informationen, die von der Anwendung bereitgestellt werden, entsprechen jetzt dem Niveau NS_LOG_FUNCTION. Er zeigt jeden Fall eines Funktionsaufrufs während der Ausführung des Skripts. In der Regel ist es empfehlenswert, in Methodenfunktionen (mindestens) zu verwendenNS_LOG_FUNCTION (this). Verwenden Sie NS_LOG_FUNCTION_NOARGS ()
nur in statischen Funktionen. Beachten Sie jedoch, dass es im ns-3-System keine Anforderungen gibt, eine bestimmte Protokollierungsfunktionalität zu unterstützen. Die Entscheidung darüber, wie viele Informationen protokolliert werden, liegt im Ermessen des Modellentwicklers. Bei Echo-Anwendungen sind eine Vielzahl von Ausgaben zur Protokollierung verfügbar.
Jetzt können Sie das Protokoll der Funktionen einsehen, die von der Anwendung aufgerufen wurden. Wenn Sie genau hinsehen, werden Sie den Doppelpunkt zwischen der Zeile UdpEchoClientApplication und dem Methodennamen bemerken, an der Stelle, an der Sie möglicherweise den C++-Gültigkeitsbereichsoperator (::) erwartet hätten. Dies ist absichtlich so gestaltet.
Tatsächlich handelt es sich nicht um den Klassennamen, sondern um den Namen der Protokollierungskomponente. Wenn ein Bezug zwischen der Quelldatei und der Klasse besteht, ist dies normalerweise der Klassenname, aber Sie müssen verstehen, dass es sich tatsächlich nicht um den Klassennamen handelt, und es dort einen Doppelpunkt anstelle von zwei Doppelpunkten gibt. Dies soll Ihnen einen relativ subtilen Weg bieten, um den Namen der Protokollierungskomponente vom Klassennamen konzeptionell zu trennen.
Dennoch kann es in einigen Fällen schwierig sein zu bestimmen, welche Methode tatsächlich die Protokollnachricht generiert. Wenn Sie sich den obigen Text ansehen, werden Sie sich fragen, wo die Zeile „Received 1024 bytes from 10.1.1.2„ herkommt. Sie können dieses Problem lösen, indem Sie das Niveau prefix_func in die Umgebungsvariable NS_LOG setzen. Versuchen Sie Folgendes:
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'Bitte beachten Sie, dass die Anführungszeichen erforderlich sind, da das vertikale Strichzeichen, das wir zur Kennzeichnung der ODER-Operation verwenden, auch der Verbinder für Unix-Pipelines ist. Jetzt, wenn Sie das Skript ausführen, werden Sie sehen, dass das Protokollierungssystem sicherstellt, dass jede Nachricht aus diesem Protokoll ein Präfix mit dem Namen der Komponente hat.
Waf: Betrete Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Verlasse Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0,417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): 1024 Bytes an 10.1.1.2 gesendet
Erhaltene 1024 Bytes von 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 erhalten
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()Jetzt können Sie sehen, dass alle Nachrichten, die vom UDP Echo-Client-Anwendung empfangen werden, als solche identifiziert sind. Die Nachricht „Received 1024 bytes from 10.1.1.2“ ist jetzt klar als von der Echo-Client-Anwendung stammend definiert. Die verbleibende Nachricht sollte von der UDP Echo-Server-Anwendung kommen. Wir können diese Komponente aktivieren, indem wir eine Liste von Komponenten, getrennt durch Doppelpunkte, in der Umgebungsvariable NS_LOG eingeben.
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
UdpEchoServerApplication=level_all|prefix_func'Warnung: In dem obigen Textbeispiel müssen Sie das Zeilenumbruchzeichen nach dem Doppelpunkt (:) entfernen, da es zur Formatierung des Dokuments verwendet wird. Wenn Sie das Skript jetzt ausführen, werden Sie alle Protokollmeldungen aus der Client- und Server-Echo-Anwendung sehen. Dies kann sich als sehr nützlich bei der Fehlersuche erweisen.
Waf: Betritt Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build`
Waf: Verlässt Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build`
`build` erfolgreich abgeschlossen (0.406s)
UdpEchoServerApplication: UdpEchoServer()
UdpEchoClientApplication: UdpEchoClient()
UdpEchoClientApplication: SetDataSize(1024)
UdpEchoServerApplication: StartApplication()
UdpEchoClientApplication: StartApplication()
UdpEchoClientApplication: ScheduleTransmit()
UdpEchoClientApplication: Send()
UdpEchoClientApplication: Send(): 1024 Bytes an 10.1.1.2 gesendet
UdpEchoServerApplication: HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
UdpEchoServerApplication: HandleRead(): Paket wird wiederholt
UdpEchoClientApplication: HandleRead(0x624920, 0x625160)
UdpEchoClientApplication: HandleRead(): 1024 Bytes von 10.1.1.2 empfangen
UdpEchoServerApplication: StopApplication()
UdpEchoClientApplication: StopApplication()
UdpEchoClientApplication: DoDispose()
UdpEchoServerApplication: DoDispose()
UdpEchoClientApplication: ~UdpEchoClient()
UdpEchoServerApplication: ~UdpEchoServer()Es kann auch manchmal nützlich sein, die Simulationszeit zu sehen, zu der die Protokollnachricht erstellt wurde. Sie können dies erreichen, indem Sie ein BIT hinzufügen. prefix_time:
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: UdpEchoServerApplication=level_all|prefix_func|prefix_time'Auch hier müssen Sie das obige Zeilenumbruchzeichen entfernen. Wenn Sie das Skript jetzt ausführen, sollten Sie die folgende Ausgabe sehen:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich abgeschlossen (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): 1024 Bytes an 10.1.1.2 gesendet
2.00369s UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
2.00369s UdpEchoServerApplication:HandleRead(): Paket wird zurückgegeben
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 empfangen
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()Bitte beachten Sie, dass der Konstruktor für UdpEchoServer während der Simulation bei 0 Sekunden aufgerufen wurde. Das passiert tatsächlich vor Beginn der Simulation, aber diese Zeit wird als null Sekunden angezeigt. Das Gleiche gilt für die Nachricht des Konstruktors UdpEchoClient.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich abgeschlossen (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): 1024 Bytes an 10.1.1.2 gesendet
2.00369s UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
2.00369s UdpEchoServerApplication:HandleRead(): Paket wird zurückgegeben
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 empfangen
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()Erinnern wir uns, dass das Skript scratch/first.cc Die Echo-Server-Anwendung wurde eine Sekunde vor Beginn der Simulation gestartet. Jetzt können Sie sehen, dass die Methode StartApplication des Servers tatsächlich in der ersten Sekunde aufgerufen wird. Sie werden auch feststellen, dass der Echo-Client in der zweiten Sekunde der Simulation gestartet wird, wie wir im Skript angefordert haben.
Jetzt können Sie den Fortschritt der Simulation über den Aufruf ScheduleTransmit im Client verfolgen, der den Rückruf Send HandleRead in der Echo-Server-Anwendung aufruft. Beachten Sie, dass die verstrichene Zeit für das Senden des Pakets über die Zwei-Punkte-Verbindung 3,69 Millisekunden beträgt. Es ist zu sehen, dass der Echo-Server eine Nachricht protokolliert, dass er auf das Paket reagiert hat, und nachdem die Kanalverzögerung vergangen ist, sehen Sie, dass der Echo-Client das Echo-Paket in seiner Methode HandleRead erhält.
In dieser Simulation passiert viel, ohne dass Sie es bemerken. Aber Sie können den gesamten Prozess sehr leicht verfolgen, indem Sie alle Logging-Komponenten im System aktivieren. Versuchen Sie, den folgenden Wert in der Variablen NS_LOG festzulegen:
$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'Das Sternchen oben ist ein Platzhalter für die Protokollierungs-Komponente. Es aktiviert alle Aufzeichnungen in allen Komponenten, die in der Simulation verwendet werden. Ich werde die Ausgabe hier nicht reproduzieren (zum Zeitpunkt der Erstellung dieses Artikels erzeugt sie 1265 Zeilen Ausgabe für ein Echo-Paket), aber Sie können diese Informationen in eine Datei umleiten und sie in Ihrem bevorzugten Editor anzeigen.
$ ./waf --run scratch/myfirst > log.out 2>&1Ich persönlich verwende diese äußerst detaillierte Protokollierungsversion, wenn ich ein Problem habe und keine Ahnung habe, wo es schiefgelaufen ist. Ich kann den Codeausführungsablauf ganz einfach verfolgen, ohne Haltepunkte zu setzen und Schritt für Schritt im Debugger zu arbeiten. Ich kann einfach die Ausgabe in meinem bevorzugten Editor bearbeiten und nach dem suchen, was ich erwarte, und sehen, was passiert, das ich nicht erwartet habe. Wenn ich ein allgemeines Verständnis davon habe, was schiefgeht, gehe ich zum Debugger über, um das Problem detaillierter zu untersuchen. Diese Art der Ausgabe kann besonders nützlich sein, wenn Ihr Skript etwas völlig Unerwartetes tut. Wenn Sie nur den Debugger verwenden, könnten Sie einen unerwarteten Dreh vollständig übersehen. Die Protokollierung macht solche Wendungen deutlich.
5.1.3 Hinzufügen von Protokollierungen zu Ihrem Code
Sie können neue Einträge in Ihre Simulationen hinzufügen, indem Sie den Protokollierungsbaustein aus mehreren Makros aufrufen. Lassen Sie uns das im Skript myfirst.cc, das wir im „sauberen“ Verzeichnis haben, tun. Erinnern wir uns, dass wir in diesem Skript die Protokollierungskomponente definiert haben:
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");Wussten Sie, dass Sie das Logging aller Nachrichten dieses Components aktivieren können, indem Sie die Umgebungsvariable NS_LOG auf verschiedenen Ebenen setzen? Lassen Sie uns fortfahren und einige Einträge in das Skript hinzufügen. Das Macro, das zum Hinzufügen von Informationslevel-Nachrichten verwendet wird, ist NS_LOG_INFO. Lassen Sie uns eine Nachricht einfügen (direkt bevor wir anfangen, Knoten zu erstellen), die Ihnen sagt, dass das Skript sich im Stadium der Topologieerstellung befindet ("Creating Topology"). Dies wird im folgenden Codefragment gemacht,
Öffnen Sie den scratch/myfirst.cc in Ihrem bevorzugten Editor und fügen Sie die Zeile hinzu,
NS_LOG_INFO ("Creating Topology");
direkt vor den Zeilen,
NodeContainer nodes;
nodes.Create(2);Nun kompilieren Sie das Skript mit waf, und setzen Sie die NS_LOG-Variable zurück, um den Logging-Stream zu deaktivieren, den wir zuvor aktiviert haben:
$ ./waf
$ export NS_LOG=
Jetzt, wenn Sie das Skript ausführen,
$ ./waf --run scratch/myfirstwerden Sie die neue Nachricht nicht sehen, da das zugehörige Logging-Component (FirstScriptExample) nicht aktiviert wurde. Um Ihre Nachricht zu sehen, müssen Sie das Logging-Component aktivieren FirstScriptExample auf mindestens NS_LOG_INFO Niveau. Wenn Sie nur diesen speziellen Logging-Level sehen möchten, können Sie ihn so aktivieren,
$ export NS_LOG=FirstScriptExample=infoWenn Sie das Skript jetzt ausführen, sehen Sie die neue Nachricht „Topology wird erstellt“.
Waf: Verzeichniseingang `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Verzeichnisverlauf `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' wurde erfolgreich abgeschlossen (0.404s)
Topology wird erstellt
1024 Bytes an 10.1.1.2 gesendet
1024 Bytes von 10.1.1.1 empfangen
1024 Bytes von 10.1.1.2 empfangen5.2 Verwendung von Befehlszeilenargumenten
5.2.1 Überschreiben von Standardattributwerten
Eine andere Möglichkeit, das Verhalten von ns‑3-Skripten zu ändern, ohne diese zu bearbeiten und zu kompilieren, ist die Verwendung von Befehlszeilenargumenten. Wir bieten einen Mechanismus zum Parsen von Befehlszeilenargumenten und zur automatischen Festlegung lokaler und globaler Variablen basierend auf den Ergebnissen.
Der erste Schritt zur Verwendung des Befehlszeilenargumentsystems ist die Deklaration des Befehlszeilenanalysators. Dies ist recht einfach in Ihrem Hauptprogramm, wie im folgenden Code:
int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}Dieser einfache zweizeilige Codeauszug ist tatsächlich sehr nützlich für sich allein. Er öffnet die Tür zu globalen ns‑3-Variablen und dem Attributsystem. Lassen Sie uns zwei Zeilen Code am Anfang der Hauptfunktion des Skripts hinzufügen. scratch/myfirst.cc. Wenn wir fortfahren, kompilieren wir das Skript und führen es aus. Bei der Ausführung machen wir die Anfrage nach Hilfe folgendermaßen:
$ ./waf --run "scratch/myfirst --PrintHelp"Dieser Befehl wird WAF das Skript scratch/myfirst starten und ihm das Kommandozeilenargument --PrintHelpübergeben. Die Anführungszeichen sind notwendig, um zu zeigen, für welches Programm das Argument bestimmt ist. Der Kommandozeilenparser erkennt das Argument --PrintHelp und gibt die Antwort aus,
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich abgeschlossen (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: Diese Hilfe ausgeben.
--PrintGroups: Die Liste der Gruppen ausgeben.
--PrintTypeIds: Alle TypeIds ausgeben.
--PrintGroup=[group]: Alle TypeIds der Gruppe ausgeben.
--PrintAttributes=[typeid]: Alle Attribute des typeid ausgeben.
--PrintGlobals: Die Liste der Globals ausgeben.Nun betrachten wir die Option --PrintAttributes. Wir haben bereits das Attributsystem von ns‑3 erwähnt, als wir das Skript first.cc untersucht haben. Wir haben die folgenden Codezeilen gesehen,
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));und gesagt, dass DataRate es tatsächlich ein Attribut ist. PointToPointNetDeviceLassen Sie uns den Kommandozeilenargumentparser verwenden, um die Attribute anzusehen. PointToPointNetDevice. Die Hilfestelle besagt, dass wir bereitstellen müssen TypeId. Dies ist der Klassenname, zu dem die interessierenden Attribute gehören. In unserem Fall wird das sein ns3::PointToPointNetDevice. Lassen Sie uns fortfahren und eingeben,
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"Das System druckt alle Attribute dieses Netzgerätetyps aus. Sie werden sehen, dass unter den Attributen in der Liste
--ns3::PointToPointNetDevice::DataRate=[32768bps]:
Die Standarddatenrate für Punkt-zu-Punkt-VerbindungenDieser Standardwert wird in dem System verwendet, wenn ein Objekt erstellt wird. PointToPointNetDevice. Wir werden diesen Standardwert mit dem Parameter Attribut in PointToPointHelper darüber überschreiben. Lassen Sie uns die Standardwerte für Punkt-zu-Punkt-Geräte und Kanäle verwenden. Dazu entfernen wir die Aufrufe SetDeviceAttribute und SetChannelAttribute von myfirst.cc, die wir im sauberen Verzeichnis haben.
Ihr Skript sollte jetzt einfach deklarieren PointToPointHelper und keine Setzoperationen durchführen, wie im folgenden Beispiel gezeigt,
...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...Fahren Sie fort und erstellen Sie ein neues Skript mit WAF (./waf) und lassen Sie uns zurückgehen und einige Aufzeichnungen aus der UDP Echo-Serveranwendung einfügen und den Zeitstempel aktivieren.
$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'Wenn Sie das Skript ausführen, sollten Sie die folgende Ausgabe sehen:
Waf: Betrete Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Verlasse Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' wurde erfolgreich abgeschlossen (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
1024 Bytes an 10.1.1.2 gesendet
2.25732s 1024 Bytes von 10.1.1.1 erhalten
2.25732s Paket wird zurückgesendet
1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Erinnern wir uns, dass beim letzten Mal, als wir die Simulationszeit betrachteten, der Moment, in dem das Echo-Server-Paket empfangen wurde, bei 2,00369 Sekunden lag.
2.00369s UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 erhaltenJetzt empfängt er das Paket bei 2.25732 Sekunden. Das liegt daran, dass wir die Übertragungsrate des PointToPointNetDevice von fünf Megabit pro Sekunde auf den Standardwert von 32768 Bit pro Sekunde zurückgesetzt haben. Wenn wir eine neue DataRate über die Befehlszeile festgelegt hätten, könnten wir unsere Simulation wieder beschleunigen. Wir werden das wie folgt tun, gemäß der Formel, die im Hilfselement angedeutet ist:
$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"Infolgedessen wird der Standardwert des Attributs DataRate auf fünf Megabit pro Sekunde zurückgesetzt. Sind Sie von dem Ergebnis überrascht? Um das ursprüngliche Verhalten des Skripts wiederherzustellen, müssen wir auch die Kanallatenz entsprechend der Lichtgeschwindigkeit einstellen. Wir können das System der Befehlszeile bitten, die Kanalattribute auszudrucken, wie wir es für das Netzwerkgerät getan haben:
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"Wir werden feststellen, dass das Kanalverzögerungsattribut wie folgt gesetzt ist:
--ns3::PointToPointChannel::Delay=[0ns]:
Übertragungsverzögerung durch den KanalDann können wir über das System der Befehlszeile beide diese Standardwerte festlegen,
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"In diesem Fall stellen wir die Werte wieder her, die wir hatten, als wir DataRate und Delay im Skript ausdrücklich festgelegt haben:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich abgeschlossen (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
1024 Bytes an 10.1.1.2 gesendet
2.00369s 1024 Bytes von 10.1.1.1 empfangen
2.00369s Paket wird zurückgesendet
1024 Bytes von 10.1.1.2 empfangen
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Bitte beachten Sie, dass das Paket nach 2,00369 Sekunden erneut vom Server empfangen wurde. Wir könnten tatsächlich jeden der im Skript verwendeten Attribute auf diese Weise setzen. Insbesondere könnten wir Werte für die Attribute MaxPackets festlegen, die von eins abweichen. UdpEchoClient.
Wie würden Sie das verwenden? Probieren Sie es aus. Denken Sie daran, dass Sie den Teil kommentieren müssen, in dem wir den Standardwert des Attributs überschreiben und explizit festlegen. MaxPackets im Skript. Dann müssen Sie das Skript neu kompilieren. Sie können auch über die Befehlszeile Hilfe zur Syntax für die Festlegung eines neuen Standardattributwerts erhalten. Wenn Sie das verstanden haben, können Sie die Anzahl der Pakete steuern, die in der Befehlszeile angezeigt werden. Da wir fleißige Leute sind, sollte unsere Befehlszeile ungefähr so aussehen:
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms
--ns3::UdpEchoClient::MaxPackets=2"Eine natürliche Frage, die an dieser Stelle aufkommt, ist, wie man über das Vorhandensein all dieser Attribute informiert wird. Auch hier bietet die Befehlszeile eine Hilfsfunktion dafür. Wenn wir um Hilfe in der Befehlszeile bitten, sollten wir Folgendes sehen:
$ ./waf --run "scratch/myfirst --PrintHelp"
myfirst [Program Arguments] [General Arguments]
General Arguments:
--PrintGlobals: Druckt die Liste der Globals.
--PrintGroups: Druckt die Liste der Gruppen.
--PrintGroup=[group]: Druckt alle TypeIds der Gruppe.
--PrintTypeIds: Druckt alle TypeIds.
--PrintAttributes=[typeid]: Druckt alle Attribute des TypeId.
--PrintHelp: Druckt diese Hilfe-Nachricht.Wenn Sie das Argument „PrintGroups“ wählen, sollten Sie eine Liste aller registrierten Gruppen sehen. TypeIdDie Gruppennamen entsprechen den Namen der Module im Quellverzeichnis (jedoch mit einem Großbuchstaben). Das Drucken aller Informationen auf einmal wäre zu umfangreich, daher steht ein zusätzlicher Filter zur Verfügung, um Informationen nach Gruppen zu drucken. Fokussieren wir uns erneut auf das Modul „Punkt-zu-Punkt“:
./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in der Gruppe PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeaderHier können Sie die verfügbaren TypeId-Namen finden, um nach Attributen zu suchen, zum Beispiel in
--PrintAttributes = ns3::PointToPointChannel, wie oben gezeigt.
Eine weitere Möglichkeit, die Attribute zu erfahren, besteht über Doxygen ns‑3. Dort gibt es eine Seite, die alle im Simulator registrierten Attribute auflistet.
5.2.2 Erfassen Ihrer eigenen Befehle
Sie können auch über das Kommandozeilen-System eigene Hooks hinzufügen. Das ist mit der Methode des Kommandozeilen-Parser ziemlich einfach. AddValue.
Lassen Sie uns diese Gelegenheit nutzen, um die Anzahl der anzuzeigenden Pakete auf eine ganz andere Weise anzugeben. Lassen Sie uns eine lokale Variable mit dem Namen nPackets in die Funktion mainhinzufügen. Wir setzen sie auf eins, um unserem vorherigen Standardverhalten zu entsprechen. Um dem Kommandozeilen-Parser zu ermöglichen, diesen Wert zu ändern, müssen wir ihn im Parser erfassen. Dies geschieht, indem wir. AddValueFügen Sie einen Aufruf hinzu. scratch/myfirst.cc Ändern Sie das Skript so, dass es mit dem folgenden Code beginnt:
int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Anzahl der zu echoenden Pakete", nPackets);
cmd.Parse (argc, argv);
...Scrollen Sie im Skript nach unten bis zu der Stelle, an der wir das Attribut MaxPackets setzen, und ändern Sie es so, dass es auf die Variable nPackets anstelle der Konstante 1 eingestellt ist, wie unten gezeigt.
echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));Jetzt, wenn Sie das Skript ausführen und das Argument —PrintHelp übergeben, sollten Sie das neue Benutzerargument angezeigt sehen, das in der Hilfedisplay aufgeführt ist. Geben Sie ein,
$ ./waf --run "scratch/myfirst --PrintHelp"
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' wird betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' wird verlassen
'build' erfolgreich abgeschlossen (0.403s)
--PrintHelp: Diese Hilfemeldung anzeigen.
--PrintGroups: Liste der Gruppen anzeigen.
--PrintTypeIds: Alle TypeIds anzeigen.
--PrintGroup=[group]: Alle TypeIds der Gruppe anzeigen.
--PrintAttributes=[typeid]: Alle Attribute von typeid anzeigen.
--PrintGlobals: Liste der Globals anzeigen.
Benutzerargumente:
--nPackets: Anzahl der zu sendenden PaketeWenn Sie die Anzahl der gesendeten Pakete ändern möchten, können Sie dies tun, indem Sie in der Befehlszeile das Argument -nPackets festlegen,
$ ./waf --run "scratch/myfirst --nPackets=2"Jetzt sollten Sie sehen,
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' wird betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' wird verlassen
'build' erfolgreich abgeschlossen (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
1024 Bytes an 10.1.1.2 gesendet
2.25732s 1024 Bytes von 10.1.1.1 erhalten
2.25732s Paket wird zurückgesendet
1024 Bytes von 10.1.1.2 erhalten
1024 Bytes an 10.1.1.2 gesendet
3.25732s 1024 Bytes von 10.1.1.1 erhalten
3.25732s Paket wird zurückgesendet
1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Sie haben jetzt zwei Pakete gesendet. Ziemlich einfach, oder?
Als Benutzer von ns‑3 können Sie das System der Kommandozeilenargumente verwenden, um globale Werte und Attribute zu steuern. Wenn Sie der Modellautor sind, können Sie neue Attribute zu Ihren Objekten hinzufügen, die dann automatisch über das Kommandozeilensystem Ihren Benutzern zur Anpassung zur Verfügung stehen. Wenn Sie der Skriptautor sind, können Sie neue Variablen in Ihre Skripte einfügen und nahtlos mit dem Kommandozeilensystem verbinden.
5.3 Verwendung des Trace-Systems
Der gesamte Sinn der Modellierung besteht darin, Ausgaben zur weiteren Untersuchung zu erzeugen, und das ns‑3-Trace-System ist dabei das wesentliche Werkzeug. Da ns‑3 ein C++-Programm ist, können die Standardmethoden zur Datenausgabe von C++-Programmen verwendet werden:
#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}Sie können sogar das Protokollmodul verwenden, um Ihrem Lösungsansatz etwas Struktur hinzuzufügen. Es sind viele Probleme bekannt, die durch diesen Ansatz entstehen können, und um diese Probleme zu lösen, haben wir ein gemeinsames Ereignistracing-Unterystem bereitgestellt.
Die Hauptziele des ns‑3-Trace-Systems sind:
Für grundlegende Aufgaben sollte das Tracing-System es dem Benutzer ermöglichen, ein Standard-Tracking für gängige Quellen zu generieren und Objekte auszuwählen, die die Trace erzeugen;
Fortgeschrittene Benutzer sollten die Möglichkeit haben, das Tracing-System zu erweitern, um das generierte Ausgabeformat zu ändern oder neue Tracing-Quellen einzufügen, ohne den Kern des Simulators zu modifizieren;
Erfahrene Benutzer können den Kern des Simulators modifizieren, um neue Quellen und Empfänger für das Tracing hinzuzufügen. Das ns-3 Tracing-System basiert auf den Prinzipien unabhängiger Tracking-Quellen und -Empfänger sowie einem einheitlichen Mechanismus zur Verbindung von Quellen mit Verbrauchern.
Das ns-3-Tracking-System basiert auf den Prinzipien unabhängiger Quellen und Empfänger für das Tracking sowie einem einheitlichen Mechanismus zur Verbindung von Quellen mit Empfängern. Die Tracking-Quellen sind Objekte, die Ereignisse signalisieren können, die während der Simulation auftreten, und den Zugriff auf relevante Basisdaten ermöglichen. Zum Beispiel kann eine Tracking-Quelle angeben, wann ein Netzwerkgerät ein Paket erhalten hat und den Empfängern des Trackings Zugriff auf den Inhalt des Pakets gewähren.
Tracking-Quellen sind allein wertlos, wenn sie nicht mit anderen Teilen des Codes „verbunden“ sind, die tatsächlich etwas Nützliches mit den Informationen tun, die der Empfänger bereitstellt. Tracker sind Konsumenten von Ereignissen und Daten, die von den Tracking-Quellen bereitgestellt werden. Zum Beispiel kann ein Tracking-Empfänger erstellt werden, der — wenn er mit der vorherigen Tracking-Quelle verbunden ist — interessante Teile des erhaltenen Pakets ausgibt.
Ein vernünftiger Grund für eine so klare Trennung besteht darin, den Benutzern zu ermöglichen, neue Arten von Empfängern an bestehende Trace-Quellen anzuschließen, ohne dass eine Bearbeitung und Neukompilierung des Simulationkernel erforderlich ist. So kann der Benutzer im obigen Beispiel einen neuen Tracer in seinem Skript definieren und diesen an eine im Simulationskernel definierte Trace-Quelle anschließen, indem er lediglich das Benutzer- Skript bearbeitet.
In diesem Handbuch werden wir einige vordefinierte Quellen und Empfänger durchgehen und zeigen, wie sie mit minimalem Aufwand seitens des Benutzers konfiguriert werden können. Siehe das ns-3-Handbuch oder die Anleitungsabschnitte für Informationen zur erweiterten Trace-Konfiguration, einschließlich der Erweiterung des Trace-Namensraums und der Erstellung neuer Trace-Quellen.
5.3.1 ASCII-Traces
ns‑3 bietet Hilfsfunktionen, die ein Low-Level-Tracking-System bereitstellen, um Ihnen bei den Einzelheiten der Konfiguration einfacher Paketverfolgungen zu helfen. Wenn Sie diese Funktion aktivieren, sehen Sie die Ausgaben in ASCII-Dateien. Für diejenigen, die mit der Ausgabe von ns-2 vertraut sind, ist dieser Typ der Verfolgung ähnlich. out.tr, das von mehreren Skripten generiert wurde.
Lassen Sie uns zur Sache kommen und einige Ergebnisse der ASCII-Verfolgung in unser Skript scratch/myfirst.cc einfügen. Direkt vor dem Aufruf von Simulator::Run(), fügen Sie die folgenden Codezeilen hinzu:
AsciiTraceHelper ascii;
pointToPoint.EnableAsciiAll(ascii.CreateFileStream("myfirst.tr"));Wie in vielen anderen Idiomen von ns‑3 verwendet dieser Code ein Hilfsobjekt zur Erstellung von ASCII-Verfolgungen. Die zweite Zeile enthält zwei geschachtelte Methodeaufrufe. Die Methode „inside“ CreateFileStream() verwendet das Idiom des anonymen Objekts zur Erstellung eines Datei-Stream-Objekts auf dem Stack (ohne Objektname) und übergibt es der aufrufenden Methode. In Zukunft werden wir uns damit ausführlicher beschäftigen, aber alles, was Sie in dieser Phase wissen müssen, ist, dass Sie ein Objekt erstellen, das eine Datei mit dem Namen myfirst.tr und es in ns‑3 zu übergeben. Wir übertragen ns‑3 die Verantwortung für das erstellte Objekt während seiner gesamten Lebensdauer, in der Probleme, die durch ein wenig bekanntes (absichtliches) Limit der Kopierkonstruktoren für Stream-Objekte in C++ verursacht werden, gelöst werden.
Externer Aufruf EnableAsciiAll() teilt dem Assistenten mit, dass Sie die ASCII-Trace für alle Punkt-zu-Punkt-Geräteverbindungen in Ihrer Simulation aktivieren möchten und dass Sie (angegebene) Trace-Empfänger möchten, die Informationen über die Paketbewegung im ASCII-Format aufzeichnen.
Für diejenigen, die mit ns-2 vertraut sind, entsprechen die verfolgten Ereignisse den bekannten Trace-Punkten, die die Ereignisse „+“, „-“, „d“ und „r“ protokollieren.
Jetzt können Sie das Skript zusammenstellen und es aus der Befehlszeile starten:
$ ./waf --run scratch/myfirstWie so oft zuvor werden Sie einige Meldungen von Waf sehen, gefolgt von "'build' finished successfully" (Bau erfolgreich abgeschlossen) mit einer Reihe von Nachrichten von der laufenden Anwendung.
Während der Ausführung wird das Programm eine Datei mit dem Namen myfirst.tr. Aufgrund der Besonderheiten des Betriebs WAF, standardmäßig wird die Datei nicht im lokalen Verzeichnis, sondern im Verzeichnis der obersten Ebene des Repositories erstellt. Wenn Sie den Speicherort ändern möchten, an dem die Protokolle gespeichert werden, können Sie dafür den Parameter für Waf verwenden --cwd. Wir haben das nicht getan; um die ASCII-Protokolldatei myfirst.tr in Ihrem bevorzugten Editor anzusehen, müssen wir in das oberste Verzeichnis unseres Repositories wechseln.
Parsing von ASCII-Traces
Dort gibt es sehr viele Informationen in ziemlich kompakter Form, aber das erste, worauf man achten sollte, ist, dass die Datei aus einzelnen Zeilen besteht. Das wird deutlich, wenn Sie das Ansichtsfenster etwas breiter ziehen.
Jede Zeile in der Datei entspricht einem Protokollereignis. In diesem Fall protokollieren wir Ereignisse in der Übertragungswarteschlange, die in jedem Punkt-zu-Punkt-Netzwerkgerät in der Simulation vorhanden ist. Die Übertragungswarteschlange ist die Warteschlange, durch die jedes Paket für den Punkt-zu-Punkt-Kanal gehen muss. Beachten Sie, dass jede Zeile in der Protokolldatei mit einem einzelnen Zeichen beginnt (und nach diesem ein Leerzeichen hat). Dieses Zeichen hat folgende Bedeutung:
+: In der Geräteschlange wurde eine Warteschlangenoperation durchgeführt;
-: In der Geräteschlange wurde eine Elementextraktionsoperation durchgeführt;
d: Das Paket wurde verworfen, da die Warteschlange in der Regel voll ist;
r: Das Paket wurde vom Netzwerkgerät empfangen.
Lassen Sie uns die erste Zeile der Trace-Datei genauer betrachten. Ich werde sie in Teile aufteilen (mit Einrückungen zur besseren Visualisierung) und mit der Zeilennummer links versehen:
0 +
1 2
2 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
3 ns3::PppHeader (
4 Point-to-Point Protocol: IP (0x0021))
6 ns3::Ipv4Header (
7 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
8 length: 1052 10.1.1.1 > 10.1.1.2)
9 ns3::UdpHeader (
10 length: 1032 49153 > 9)
11 Payload (size=1024)Der erste Abschnitt dieses erweiterten Trace-Ereignisses (Zeile 0) ist die Operation. Hier haben wir das Symbol +, das der Warteschlangenoperation für die Übertragung entspricht. Der zweite Abschnitt (Zeile 1) ist die Simulationszeit, ausgedrückt in Sekunden. Sie erinnern sich sicher, dass wir darum gebeten haben, UdpEchoClientApplication die Pakete nach zwei Sekunden zu senden. Hier sehen wir die Bestätigung, dass dies tatsächlich geschieht.
Im nächsten Abschnitt des Tracing-Beispiels (ab Zeile 2) wird gezeigt, welche Tracing-Quelle dieses Ereignis erzeugt hat (die Namensraum-Tracing wird angegeben). Sie können sich den Namensraum des Tracings ähnlich wie ein Dateisystem-Namensraum vorstellen. Der Wurzelpunkt des Namensraums ist NodeList. Dies entspricht einem Container, der im Hauptcode von ns-3 verwaltet wird. Er enthält alle Knoten, die im Skript erstellt werden. Genauso wie ein Dateisystem mit Verzeichnissen im Wurzelverzeichnis bestehen kann, NodeList kann es bei uns mehrere Knoten geben. Daher bezieht sich die Zeile /NodeList/0 auf den Nullknoten in NodeList, den wir normalerweise als „Knoten 0“ verstehen. In jedem Knoten gibt es eine Liste von Geräten, die installiert wurden. Diese Liste ist im Namensraum folgendermaßen angeordnet. Sie können sehen, dass dieses Tracing-Ereignis von DeviceList/0, dem Nullgerät, das im Knoten installiert ist, ausgeht.
Die nächste Teilzeile, $ ns3::PointToPointNetDevice, berichtet, welches Gerät sich in der Nullposition befindet: Liste der Geräte des Nullknotens. Erinnern wir uns, dass die Operation +, die sich in Zeile 0 befindet, bedeutet, dass ein Element in die Übertragungswarteschlange hinzugefügt wurde. Dies spiegelt sich in den letzten Segmenten des „Trace-Pfades“ wider: TxQueue/Enqueue.
Die anderen Abschnitte der Trace sollten intuitiv verständlich sein. Die Zeilen 3-4 zeigen, dass das Paket in das Punkt-zu-Punkt-Protokoll eingekapselt ist. Die Zeilen 5-7 zeigen, dass das Paket einen Header der Version IPv4 hat und aus der IP-Adresse 10.1.1.1 und bestimmt ist für 10.1.1.2. Die Zeilen 8-9 zeigen, dass dieses Paket einen UDP-Header hat und schließlich zeigt Zeile 10, dass die Nutzlast erwartete 1024 Bytes beträgt.
Die nächste Zeile in der Trace-Datei zeigt, dass dasselbe Paket aus der Übertragungswarteschlange am selben Knoten entnommen wurde.
Die dritte Zeile in der Trace-Datei zeigt, dass das Paket von einem Netzwerkgerät am Knoten mit dem Echo-Server empfangen wurde. Ich habe dieses Ereignis unten reproduziert.
0 r
1 2.25732
2 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
3 ns3::Ipv4Header (
4 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
5 length: 1052 10.1.1.1 > 10.1.1.2)
6 ns3::UdpHeader (
7 length: 1032 49153 > 9)
8 Payload (size=1024)Bitte beachten Sie, dass die Rückverfolgung jetzt r ist und die Simulationszeit auf 2,25732 Sekunden erhöht wurde. Wenn Sie die Anweisungen im Tutorial genau befolgt haben, bedeutet das, dass Sie die DataRate der Netzwerkgeräte und die Verzögerung des Kanals auf den Standardwerten gelassen haben. Diese Zeit sollte Ihnen bekannt sein, da Sie sie bereits im vorherigen Abschnitt gesehen haben.
Die Quell-Namensraum-Aufzeichnung (Zeile 2) wurde geändert, um widerzuspiegeln, dass dieses Ereignis von Knoten 1 stammt (/NodeList/1) и пакет принят источником трассировки (/MacRx). Es sollte Ihnen recht leicht fallen, den Paketfluss durch die Topologie zu verfolgen, indem Sie die restlichen Einträge in der Trace-Datei ansehen.
5.3.2 PCAP-Tracing
Die ns-3 Gerätehilfsprogramme können ebenfalls verwendet werden, um Trace-Dateien im .pcap-Format zu erstellen. Das Akronym pcap beschreibt normalerweise die Erfassung von Paketen und ist tatsächlich eine API, die die Definition des .pcap-Dateiformats umfasst. Das beliebteste Programm, das dieses Format lesen und anzeigen kann, ist Wireshark (früher bekannt als Ethereal). Es gibt jedoch viele Netzwerk-Trace-Analysatoren, die dieses Paketformat nutzen. Wir empfehlen den Nutzern, verschiedene verfügbare Tools zur Analyse von pcap-Traces zu verwenden. In diesem Leitfaden konzentrieren wir uns auf die Anzeige von pcap-Traces mit tcpdump.
Die Aktivierung der pcap-Tracierung erfolgt mit einer einzigen Codezeile.
pointToPoint.EnablePcapAll ("myfirst");Fügen Sie diese Codezeile nach dem ASCII-Tracing-Code ein, den wir gerade hinzugefügt haben scratch/myfirst.cc. Beachten Sie, dass wir nur den String „myfirst“ übergeben haben, nicht „myfirst.pcap“ oder etwas Ähnliches. Dies liegt daran, dass der Parameter ein Präfix und nicht der vollständige Dateiname ist. Während der Simulation erstellt der Assistent tatsächlich eine Trace-Datei für jedes Punkt-zu-Punkt-Gerät. Die Dateinamen werden unter Verwendung des Präfixes, der Knotennummer, der Gerätenummer und des Suffixes „.pcap».
In unserem Beispielszenario werden wir letztendlich Dateien mit den Namen „myfirst-0-0.pcap» und «myfirst-1-0.pcap“, die die pcap-Traces für Knoten 0-Gerät 0 und Knoten 1-Gerät 0 sind. Nachdem Sie die Codezeile zur Aktivierung der pcap-Tracierung hinzugefügt haben, können Sie das Skript wie gewohnt ausführen:
$ ./waf --run scratch/myfirstWenn Sie das Stammverzeichnis Ihrer Distribution ansehen, sollten Sie drei Dateien sehen: die ASCII-Tracedatei myfirst.tr, die wir zuvor betrachtet haben, und die Dateien myfirst-0-0.pcap und myfirst-1-0.pcap — neue pcap-Dateien, die wir gerade erzeugt haben.
Ausgabe mit tcpdump lesen
Bis jetzt ist tcpdump der einfachste Weg, um pcap-Dateien anzusehen.
$ tcpdump -nn -tt -r myfirst-0-0.pcap
reading from file myfirst-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
tcpdump -nn -tt -r myfirst-1-0.pcap
reading from file myfirst-1-0.pcap, link-type PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024In dem Dump myfirst-0-0.pcap (Client-Gerät) können Sie sehen, dass das Echo-Paket nach 2 Sekunden Simulation gesendet wird. Wenn Sie sich den zweiten Dump ansehen (myfirst-1-0.pcap), sehen Sie, dass das Paket zum Zeitpunkt 2,257324 Sekunden empfangen wird. Sie werden im zweiten Dump sehen, dass das Paket beim Zeitpunkt 2.257324 Sekunden zurückgegeben wird und schließlich, dass das Paket im ersten Dump zum Zeitpunkt 2.514648 Sekunden wieder vom Client empfangen wurde.
Ausgabe mit Wireshark lesen
Wenn Sie mit Wiresharknicht vertraut sind, gibt es eine Website, von der Sie die Software und Dokumentation herunterladen können: . Wireshark — ist eine grafische Benutzeroberfläche, die zur Anzeige dieser Trace-Dateien verwendet werden kann. Wenn Sie Wireshark haben, können Sie eine der Trace-Dateien öffnen und den Inhalt anzeigen, als hätten Sie Pakete mit einem Packet-Analyzer erfasst.
Quelle: habr.com
