Tutorial zum NS-3-Netzwerksimulator. Kapitel 5

Tutorial zum NS-3-Netzwerksimulator. Kapitel 5
Kapitel 1,2
Kapitel 3
Kapitel 4

5 Einstellungen
5.1 Verwendung des Protokollierungsmoduls
5.1.1 Protokollierungsübersicht
5.1.2 Protokollierung aktivieren
5.1.3 Protokollierung zu Ihrem Code hinzufügen
5.2 Verwendung von Befehlszeilenargumenten
5.2.1 Standardattributwerte überschreiben
5.2.2 Eigene Befehle erfassen
5.3 Verwendung des Rückverfolgungssystems
5.3.1 ASCII-Ablaufverfolgung
Parsen von ASCII-Spuren
5.3.2 PCAP-Trace

Kapitel 5

Einstellung

5.1 Verwendung des Protokollierungsmoduls

Wir haben uns das NS-3-Logging-Modul bereits kurz anhand des Skripts angeschaut zuerst.cc. In diesem Kapitel werfen wir einen genaueren Blick auf mögliche Einsatzmöglichkeiten des Logging-Subsystems.

5.1.1 Protokollierungsübersicht

Viele große Systeme unterstützen eine Art Nachrichtenprotokollierungsfunktion, und ns-3 ist keine Ausnahme. In einigen Fällen werden nur Fehlermeldungen an die „Operatorkonsole“ geschrieben (bei Unix-basierten Systemen normalerweise stderr). Auf anderen Systemen werden möglicherweise Warnmeldungen sowie detailliertere Informationen angezeigt. In einigen Fällen werden Protokollierungstools zur Ausgabe von Debugmeldungen verwendet, die die Ausgabe schnell verfälschen können.

Das in NS-3 verwendete subHRD geht davon aus, dass alle diese Ebenen des Informationsinhalts nützlich sind, und wir bieten einen selektiven, mehrschichtigen Ansatz für die Nachrichtenprotokollierung. Die Protokollierung kann vollständig deaktiviert, komponentenweise oder global aktiviert werden. Hierzu werden einstellbare Informationsinhalte eingesetzt. Das NS-3-Protokollierungsmodul bietet eine relativ einfache Möglichkeit, nützliche Informationen aus Ihrer Simulation zu erhalten.

Sie sollten verstehen, dass wir einen Allzweckmechanismus – die Ablaufverfolgung – zum Extrahieren von Daten aus Ihren Modellen bereitstellen, die die bevorzugte Ausgabe für Simulationen sein sollten (weitere Informationen zu unserem Ablaufverfolgungssystem finden Sie im Tutorial-Abschnitt 5.3). Die Protokollierung sollte die bevorzugte Methode sein, um Debugging-Informationen, Warnungen und Fehlermeldungen zu erhalten oder jederzeit schnell Meldungen aus Ihren Skripten oder Modellen auszugeben.

Derzeit definiert das System sieben Ebenen (Typen) von Protokollmeldungen in aufsteigender Reihenfolge des Informationsgehalts.

  • LOG_ERROR – Fehlermeldungen protokollieren (zugehöriges Makro: NS_LOG_ERROR);
  • LOG_WARN – Warnmeldungen protokollieren (zugehöriges Makro: NS_LOG_WARN);
  • LOG_DEBUG – Relativ seltene spezielle Debug-Meldungen protokollieren (zugehöriges Makro: NS_LOG_DEBUG);
  • LOG_INFO – Registrierung von Informationsmeldungen über den Fortschritt des Programms (zugehöriges Makro: NS_LOG_INFO);
  • LOG_FUNCTION – Protokolliert Meldungen, die jede aufgerufene Funktion beschreiben (zwei verwandte Makros: NS_LOG_FUNCTION, verwendet für Mitgliedsfunktionen, und NS_LOG_FUNCTION_NOARGS, verwendet für statische Funktionen);
  • LOG_LOGIC – Protokollierung von Nachrichten, die den logischen Ablauf innerhalb einer Funktion beschreiben (zugehöriges Makro: NS_LOG_LOGIC);
  • LOG_ALL – Protokolliert alles, was oben erwähnt wurde (kein zugehöriges Makro).
    Für jeden Typ (LOG_TYPE) gibt es auch einen LOG_LEVEL_TYPE, der bei Verwendung zusätzlich zur eigenen Ebene die Protokollierung aller darüber liegenden Ebenen ermöglicht. (Daher sind LOG_ERROR und LOG_LEVEL_ERROR sowie LOG_ALL und LOG_LEVEL_ALL funktional gleichwertig.) Wenn Sie beispielsweise LOG_INFO aktivieren, werden nur Nachrichten zugelassen, die vom Makro NS_LOG_INFO bereitgestellt werden, während die Aktivierung von LOG_LEVEL_INFO auch Nachrichten umfasst, die von den Makros NS_LOG_DEBUG, NS_LOG_WARN und NS_LOG_ERROR bereitgestellt werden.

Wir stellen außerdem ein bedingungsloses Protokollierungsmakro zur Verfügung, das immer angezeigt wird, unabhängig von der Protokollierungsstufe oder der Auswahlkomponente.

  • NS_LOG_UNCOND – Unbedingte Protokollierung der zugehörigen Nachricht (keine zugehörige Protokollierungsstufe).

Jede Ebene kann einzeln oder kumulativ abgefragt werden. Die Protokollierung kann mithilfe der sh-Umgebungsvariablen NS_LOG oder durch Protokollierung eines Systemfunktionsaufrufs konfiguriert werden. Wie bereits gezeigt, verfügt das Protokollierungssystem über eine Doxygen-Dokumentation und jetzt ist ein guter Zeitpunkt, diese zu überprüfen, falls Sie dies noch nicht getan haben.

Nachdem Sie die Dokumentation nun ausführlich gelesen haben, wollen wir dieses Wissen nutzen, um einige interessante Informationen aus dem Beispielskript zu gewinnen scratch/myfirst.ccdie Sie bereits zusammengestellt haben.

5.1.2 Protokollierung aktivieren

Lassen Sie uns die Umgebungsvariable NS_LOG verwenden, um weitere Protokolle auszuführen. Führen Sie jedoch zunächst zur Orientierung das letzte Skript aus, wie Sie es zuvor getan haben.

$ ./waf --run scratch/myfirst

Sie sollten die bekannte Ausgabe des ersten NS-3-Beispielprogramms sehen

$ Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' 'build'
finished successfully (0.413s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

Es stellt sich heraus, dass es sich bei den „gesendeten“ und „empfangenen“ Nachrichten, die Sie oben sehen, tatsächlich um protokollierte Nachrichten von handelt UdpEchoClient-Anwendung и UdpEchoServer-Anwendung. Beispielsweise können wir die Clientanwendung auffordern, zusätzliche Informationen zu drucken, indem wir ihre Protokollierungsebene über die Umgebungsvariable NS_LOG festlegen.

Von nun an gehe ich davon aus, dass Sie eine SH-ähnliche Shell verwenden, die die Syntax „VARIABLE=value“ verwendet. Wenn Sie eine csh-ähnliche Shell verwenden, müssen Sie meine Beispiele in die für diese Shells erforderliche Syntax „setenv-Variablenwert“ konvertieren.

Derzeit antwortet die UDP-Echo-Clientanwendung auf die folgende Codezeile in scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Es aktiviert die Protokollierungsebene LOG_LEVEL_INFO. Wenn wir ein Flag für die Protokollierungsebene übergeben, aktivieren wir tatsächlich diese Ebene und alle niedrigeren Ebenen. In diesem Fall haben wir NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN und NS_LOG_ERROR aktiviert. Wir können die Protokollierungsstufe erhöhen und mehr Informationen erhalten, ohne Skriptänderungen und Neukompilierung, indem wir die Umgebungsvariable NS_LOG wie folgt festlegen:

$ export NS_LOG=UdpEchoClientApplication=level_all

Also setzen wir die sh-Shell-Variable NS_LOG auf den folgenden Wert:

UdpEchoClientApplication=level_all

Die linke Seite der Zuweisung ist der Name der protokollierten Komponente, die wir konfigurieren möchten, und die rechte Seite ist das Flag, das wir dafür anwenden möchten. In diesem Fall werden wir alle Debugging-Ebenen in der Anwendung aktivieren. Wenn Sie das Skript mit dieser Einstellung für NS_LOG ausführen, akzeptiert das NS-3-Protokollierungssystem die Änderungen und Sie sollten die folgende Ausgabe sehen:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Zusätzliche Debugging-Informationen, die von der Anwendung bereitgestellt werden, befinden sich jetzt auf der Ebene NS_LOG_FUNCTION. Es zeigt jede Instanz eines Funktionsaufrufs während der Skriptausführung. Als allgemeine Regel gilt, dass in Methodenfunktionen die Verwendung (mindestens) vorzuziehen ist.NS_LOG_FUNCTION (this)... Benutzen NS_LOG_FUNCTION_NOARGS ()
nur in statischen Funktionen. Beachten Sie jedoch, dass das NS-3-System keine Protokollierungsfunktionen unterstützen muss. Die Entscheidung darüber, wie viele Informationen aufgezeichnet werden, bleibt dem einzelnen Modellentwickler überlassen. Bei Echo-Anwendungen steht eine große Menge an Protokollierungsausgaben zur Verfügung.

Sie können jetzt ein Protokoll der von der Anwendung durchgeführten Funktionsaufrufe anzeigen. Wenn Sie genau hinschauen, werden Sie einen Doppelpunkt zwischen der Zeile bemerken UdpEchoClient-Anwendung und den Namen der Methode, in der Sie möglicherweise den C++-Bereichsoperator erwarten (: :). Das ist Absicht.

Dabei handelt es sich eigentlich nicht um den Namen der Klasse, sondern um den Namen der Protokollierungskomponente. Wenn es eine Übereinstimmung zwischen einer Quelldatei und einer Klasse gibt, handelt es sich normalerweise um den Namen der Klasse. Sie sollten sich jedoch darüber im Klaren sein, dass es sich nicht tatsächlich um den Namen der Klasse handelt und dass anstelle eines Doppelpunkts ein einzelner Doppelpunkt vorhanden ist. Auf diese Weise können Sie den Namen der Logging-Bean konzeptionell und auf relativ subtile Weise vom Klassennamen trennen.

In manchen Fällen kann es jedoch schwierig sein, festzustellen, welche Methode tatsächlich die Protokollmeldung generiert. Wenn Sie sich den Text oben ansehen, fragen Sie sich vielleicht, wo die Zeile „Received 1024 bytes from 10.1.1.2" Sie können dieses Problem lösen, indem Sie den Pegel festlegen prefix_func zur Umgebungsvariablen NS_LOG hinzufügen. Versuche Folgendes:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Beachten Sie, dass die Anführungszeichen notwendig sind, da der vertikale Balken, den wir zur Darstellung der ODER-Verknüpfung verwenden, auch ein Unix-Pipe-Anschluss ist. Wenn Sie nun das Skript ausführen, werden Sie feststellen, dass das Protokollierungssystem dafür sorgt, dass jeder Nachricht in einem bestimmten Protokoll der Komponentenname vorangestellt wird.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Jetzt können Sie sehen, dass alle Nachrichten, die von der UDP-Echo-Client-Anwendung kommen, als solche gekennzeichnet sind. Nachricht "Received 1024 bytes from 10.1.1.2„ wird nun eindeutig als von der Echo-Client-Anwendung stammend identifiziert. Die verbleibende Nachricht muss von der UDP-Echo-Serveranwendung stammen. Wir können diese Komponente aktivieren, indem wir eine durch Doppelpunkte getrennte Liste von Komponenten in die Umgebungsvariable NS_LOG eingeben.

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
               UdpEchoServerApplication=level_all|prefix_func'

Warnung: Im obigen Beispieltext müssen Sie das Zeilenumbruchzeichen nach dem Doppelpunkt (:) entfernen, es wird zum Formatieren des Dokuments verwendet. Wenn Sie nun das Skript ausführen, sehen Sie alle Protokollmeldungen der Client- und Server-Echo-Anwendungen. Sie sehen, dass dies beim Debuggen sehr nützlich sein kann.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
UdpEchoServerApplication:HandleRead(): Echoing packet
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Manchmal ist es auch nützlich, den Simulationszeitpunkt zu sehen, zu dem die Protokollmeldung generiert wurde. Sie können dies tun, indem Sie das OR-Bit hinzufügen präfix_zeit:

$ 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 nun das Skript ausführen, sollten Sie die folgende Ausgabe sehen:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (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(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Bitte beachten Sie, dass der Konstruktor für UdpEchoServer wurde während der Simulation 0 Sekunden aufgerufen. Dies geschieht tatsächlich vor Beginn der Simulation, die Zeit wird jedoch mit null Sekunden angezeigt. Das Gleiche gilt für die Konstruktornachricht UdpEchoClient.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (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(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Denken Sie daran, dass das Skript Scratch/first.cc hat die Echo-Server-Anwendung eine Sekunde vor Beginn der Simulation gestartet. Jetzt können Sie sehen, dass die Methode Bewerbung starten Der Server wird tatsächlich in der ersten Sekunde aufgerufen. Möglicherweise stellen Sie auch fest, dass der Echo-Client in der zweiten Sekunde der Simulation startet, wie wir es im Skript verlangt haben.

Sie können den Simulationsfortschritt nun per Abruf verfolgen ZeitplanTransmit im Client, der den HandleRead-Rückruf Send in der Echo-Server-Anwendung aufruft. Beachten Sie, dass die zum Senden eines Pakets über eine Punkt-zu-Punkt-Verbindung benötigte Zeit 3,69 Millisekunden beträgt. Sie können sehen, dass der Echo-Server eine Meldung protokolliert, dass er auf das Paket geantwortet hat, und dann, nach einer Kanalverzögerung, sehen Sie, dass der Echo-Client das Echo-Paket in seiner HandleRead-Methode empfängt.

In dieser Simulation passiert vieles, ohne dass Sie es merken. Sie können den gesamten Prozess jedoch sehr einfach verfolgen, indem Sie alle Protokollierungskomponenten im System aktivieren. Versuchen Sie, die Variable NS_LOG auf den folgenden Wert zu setzen:

$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'

Das Sternchen oben ist ein Platzhalterzeichen für die Protokollierungskomponente. Dies umfasst alle Einträge in allen in der Simulation verwendeten Komponenten. Ich werde die Ausgabe hier nicht reproduzieren (zum Zeitpunkt des Schreibens erzeugt sie 1265 Ausgabezeilen für ein einzelnes Echopaket), aber Sie können diese Informationen in eine Datei umleiten und sie in Ihrem bevorzugten Editor anzeigen.

$ ./waf --run scratch/myfirst > log.out 2>&1

Ich persönlich verwende diese äußerst ausführliche Version der Protokollierung, wenn ich ein Problem habe und keine Ahnung habe, wo etwas schief gelaufen ist. Ich kann die Codeausführung ganz einfach verfolgen, ohne Haltepunkte zu setzen und den Code im Debugger schrittweise durchzugehen. Ich kann die Ausgabe einfach in meinem Lieblingseditor bearbeiten und nach dem suchen, was ich erwarte, und sehen, dass etwas passiert, das ich nicht erwartet habe. Sobald ich eine allgemeine Vorstellung davon habe, was falsch läuft, springe ich in den Debugger, um das Problem genauer 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, verpassen Sie möglicherweise eine Wendung völlig. Durch die Registrierung werden solche Wendungen spürbar.

5.1.3 Protokollierung zu Ihrem Code hinzufügen

Sie können Ihren Simulationen neue Einträge hinzufügen, indem Sie die Protokollkomponente von mehreren Makros aus aufrufen. Machen wir es in einem Skript myfirst.cc, die wir im Verzeichnis „clean“ haben. Denken Sie daran, dass wir in diesem Szenario eine Protokollierungskomponente definiert haben:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Sie wissen, dass Sie die Protokollierung aller Nachrichten dieser Komponente aktivieren können, indem Sie die Umgebungsvariable NS_LOG auf verschiedenen Ebenen festlegen. Lassen Sie uns fortfahren und einige Einträge zum Skript hinzufügen. Das zum Hinzufügen von Nachrichten auf Informationsebene zum Protokoll verwendete Makro ist NS_LOG_INFO. Fügen wir eine Meldung hinzu (kurz bevor wir mit der Knotenerstellung beginnen), die Ihnen mitteilt, dass sich das Skript in der Phase „Topologie erstellen“ befindet. Dies geschieht im folgenden Codeausschnitt:
Öffnen scratch/myfirst.cc in Ihrem Lieblingseditor und fügen Sie die Zeile hinzu,
NS_LOG_INFO ("Creating Topology");
direkt vor den Linien,

NodeContainer nodes;
nodes.Create (2);

Kompilieren Sie nun das Skript mit waf, und löschen Sie die Variable NS_LOG, um den Protokollierungsstream zu deaktivieren, den wir zuvor aktiviert haben:

$ ./waf
$ export NS_LOG=
Теперь, если вы запустите скрипт,
$ ./waf --run scratch/myfirst

Die neue Nachricht wird nicht angezeigt, da die zugehörige Protokollierungskomponente (FirstScriptExample) nicht aktiviert wurde. Um Ihre Nachricht zu sehen, müssen Sie die Protokollierungskomponente aktivieren Erstes SkriptBeispiel mit einer Ebene nicht niedriger als NS_LOG_INFO. Wenn Sie nur diese spezielle Protokollierungsstufe sehen möchten, können Sie sie wie folgt aktivieren:

$ export NS_LOG=FirstScriptExample=info

Wenn Sie das Skript jetzt ausführen, wird die neue Meldung „Topologie wird erstellt“ angezeigt.

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
Creating Topology
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

5.2 Verwendung von Befehlszeilenargumenten

5.2.1 Standardattributwerte überschreiben

Eine weitere Möglichkeit, das Verhalten von NS-3-Skripten ohne Bearbeitung oder Erstellung zu ändern, ist die Verwendung von Befehlszeilenargumenten. Wir bieten einen Mechanismus zum Parsen von Befehlszeilenargumenten und zum automatischen Festlegen lokaler und globaler Variablen basierend auf den Ergebnissen.

Der erste Schritt bei der Verwendung des Befehlszeilenargumentsystems besteht darin, einen Befehlszeilenparser zu deklarieren. Dies ist ganz einfach (in Ihrem Hauptprogramm) zu bewerkstelligen, wie im folgenden Code:

int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}

Dieser einfache zweizeilige Ausschnitt ist an sich schon sehr nützlich. Es öffnet die Tür zum globalen Variablen- und Attributsystem von ns-3. Fügen wir am Anfang der Hauptskriptfunktion zwei Codezeilen hinzu scratch/myfirst.cc. Anschließend kompilieren wir das Skript und führen es aus. Beim Ausführen stellen wir eine Hilfeanfrage wie folgt:

$ ./waf --run "scratch/myfirst --PrintHelp"

Dieser Befehl fragt Waf Skript ausführen kratzen/myfirst und übergeben Sie ihm ein Befehlszeilenargument – Hilfe drucken. Die Anführungszeichen sind erforderlich, um anzugeben, für welches Programm das Argument gedacht ist. Der Befehlszeilenparser erkennt das Argument – Hilfe drucken und zeigt die Antwort an,

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.

Schauen wir uns nun die Option an – Druckattribute. Wir haben das NS-3-Attributsystem bereits beim Studium des first.cc-Skripts erwähnt. Wir haben die folgenden Codezeilen gesehen:

PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

und das haben sie gesagt Datenrate ist eigentlich ein Attribut PointToPointNetDevice. Lassen Sie uns den Befehlszeilenargument-Parser verwenden, um die Attribute anzuzeigen PointToPointNetDevice. In der Hilfeliste steht, was wir bereitstellen müssen Typ-ID. Dies ist der Name der Klasse, zu der die interessierenden Attribute gehören. In unserem Fall wird es so sein ns3::PointToPointNetDevice. Lasst uns weiter voranschreiten, eintreten,

$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"

Das System druckt alle Attribute dieses Netzwerkgerätetyps. Sie werden sehen, dass zu den Attributen in der Liste gehören:

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
The default data rate for point to point links

Dies ist der Standardwert, den das System beim Erstellen des Objekts verwendet PointToPointNetDevice. Wir werden diesen Standardwert mit dem Parameter überschreiben Attribut в PointToPointHelper höher. Lassen Sie uns die Standardwerte für Punkt-zu-Punkt-Geräte und Kanäle verwenden. Dazu löschen wir Anrufe SetDeviceAttribute и SetChannelAttribute von myfirst.cc, die wir in einem sauberen Verzeichnis haben.

Ihr Skript sollte jetzt einfach deklariert werden PointToPointHelper und führen Sie keine Installationsvorgänge durch, wie im folgenden Beispiel gezeigt.

...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...

Machen Sie weiter und erstellen Sie ein neues Skript mit Waf (./waff) und gehen wir zurück und fügen einen Eintrag aus der UDP-Echo-Server-Anwendung sowie das Zeitpräfix ein.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Wenn Sie das Skript ausführen, sollten Sie die folgende Ausgabe sehen:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Denken Sie daran, dass die Simulationszeit, als wir uns das letzte Mal angesehen haben, als das Paket vom Echo-Server empfangen wurde, 2,00369 Sekunden betrug.

2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1

Jetzt empfängt er das Paket in 2.25732 Sekunden. Dies liegt daran, dass wir einfach die PointToPointNetDevice-Datenrate von fünf Megabit pro Sekunde auf den Standardwert zurückgesetzt haben, der 32768 Bit pro Sekunde beträgt. Wenn wir über die Befehlszeile eine neue DataRate ersetzen würden, könnten wir unsere Simulation noch einmal beschleunigen. Wir werden dies wie folgt tun, gemäß der Formel, die das Element help impliziert:

$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"

Dadurch wird das DataRate-Attribut auf seinen Standardwert von fünf Megabit pro Sekunde zurückgesetzt. Sind Sie vom Ergebnis überrascht? Es stellt sich heraus, dass wir, um das ursprüngliche Verhalten des Skripts wiederherzustellen, auch die Kanalverzögerung so einstellen müssen, dass sie der Lichtgeschwindigkeit entspricht. Wir können das Befehlszeilensystem auffordern, die Kanalattribute auszudrucken, genau 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 eingestellt ist:

--ns3::PointToPointChannel::Delay=[0ns]:
Transmission delay through the channel

Anschließend können wir über das Befehlszeilensystem diese beiden Standardwerte festlegen.

$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"

In diesem Fall stellen wir die Zeit wieder her, die wir hatten, als wir DataRate und Delay explizit im Skript festgelegt haben:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.00369s Received 1024 bytes from 10.1.1.1
2.00369s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Beachten Sie, dass das Paket nach 2,00369 Sekunden erneut vom Server empfangen wird. Auf diese Weise könnten wir tatsächlich jedes der im Skript verwendeten Attribute festlegen. Insbesondere könnten wir die MaxPackets-Attribute auf Nicht-Eins-Werte setzen UdpEchoClient.

Wie würden Sie es verwenden? Versuche es. Denken Sie daran, dass Sie die Stelle auskommentieren müssen, an der wir den Standardattributwert überschreiben und explizit festlegen MaxPakete im Drehbuch. Anschließend müssen Sie das Skript neu erstellen. Sie können auch die Befehlszeile verwenden, um Syntaxhilfe zum Festlegen eines neuen Standardattributwerts zu erhalten. Sobald Sie dies verstanden haben, können Sie die Anzahl der in der Befehlszeile angezeigten Pakete steuern. Da wir fleißige Leute sind, sollte unsere Befehlszeile etwa so aussehen:

$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms
--ns3::UdpEchoClient::MaxPackets=2"

An diesem Punkt stellt sich natürlich die Frage, wie man über die Existenz all dieser Attribute Bescheid weiß. Auch hierfür verfügt das Kommandozeilensystem über eine Hilfefunktion. Wenn wir die Befehlszeile um Hilfe bitten, sollten wir Folgendes sehen:

$ ./waf --run "scratch/myfirst --PrintHelp"
myfirst [Program Arguments] [General Arguments]
General Arguments:
--PrintGlobals: Print the list of globals.
--PrintGroups: Print the list of groups.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintTypeIds: Print all TypeIds.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintHelp: Print this help message.

Wenn Sie das Argument „PrintGroups“ auswählen, sollten Sie eine Liste aller registrierten Gruppen sehen Typ-ID. Die Gruppennamen stimmen mit den Namen der Module im Quellverzeichnis überein (allerdings in Großschreibung). Das Drucken aller Informationen auf einmal würde zu umfangreich sein, daher steht ein zusätzlicher Filter zum Drucken von Informationen nach Gruppen zur Verfügung. Konzentrieren wir uns also noch einmal auf das Punkt-zu-Punkt-Modul:

./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in group PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeader

Hier finden Sie verfügbare TypeId-Namen für Attributsuchen, zum Beispiel in
--PrintAttributes = ns3 :: PointToPointChannelwie oben gezeigt.

Eine weitere Möglichkeit, mehr über Attribute zu erfahren, ist Doxygen ns-3. Es gibt eine Seite, die alle im Simulator registrierten Attribute auflistet.

5.2.2 Eigene Befehle erfassen

Sie können auch Ihre eigenen Hooks über das Befehlszeilensystem hinzufügen. Dies geschieht ganz einfach über die Kommandozeilen-Parser-Methode AddValue.
Mit dieser Funktion können wir die Anzahl der anzuzeigenden Pakete auf ganz andere Weise festlegen. Fügen wir eine lokale Variable namens hinzu nPakete in eine Funktion umwandeln Haupt-. Wir werden es auf eins setzen, um unserem vorherigen Standardverhalten zu entsprechen. Damit der Befehlszeilenparser diesen Wert ändern kann, müssen wir diesen Wert im Parser erfassen. Wir tun dies, indem wir einen Anruf hinzufügen AddValue. Gehen Sie und ändern Sie das Skript scratch/myfirst.cc Beginnen Sie also mit dem folgenden Code:

int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
cmd.Parse (argc, argv);
...

Scrollen Sie nach unten zu dem Punkt im Skript, an dem wir das MaxPackets-Attribut festlegen, und ändern Sie es so, dass es auf die Variable nPackets anstelle der Konstante 1 gesetzt wird, wie unten gezeigt.

echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));

Wenn Sie nun das Skript ausführen und das Argument -PrintHelp angeben, sollte das neue Benutzerargument angezeigt werden. werden in der Hilfeanzeige aufgeführt. Eingeben,

$ ./waf --run "scratch/myfirst --PrintHelp"
Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.403s)
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.
User Arguments:
--nPackets: Number of packets to echo

Wenn Sie die Anzahl der übertragenen Pakete ändern möchten, können Sie dies tun, indem Sie das Befehlszeilenargument - -nPackets setzen.

$ ./waf --run "scratch/myfirst --nPackets=2"

Jetzt sollten Sie sehen

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
Sent 1024 bytes to 10.1.1.2
3.25732s Received 1024 bytes from 10.1.1.1
3.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Sie haben jetzt zwei Pakete verschickt. Ziemlich einfach, nicht wahr?
Sie können sehen, dass Sie als NS-3-Benutzer das Befehlszeilenargumentsystem verwenden können, um globale Werte und Attribute zu manipulieren. Wenn Sie der Modellautor sind, können Sie Ihren Objekten neue Attribute hinzufügen und diese stehen Ihren Benutzern automatisch über das Befehlszeilensystem zur Konfiguration zur Verfügung. Wenn Sie ein Skriptautor sind, können Sie Ihren Skripten neue Variablen hinzufügen und diese nahtlos in Ihr Befehlszeilensystem integrieren.

5.3 Verwendung des Rückverfolgungssystems

Der Sinn der Modellierung besteht darin, eine Ausgabe für weitere Untersuchungen zu generieren, und das NS-3-Trace-System ist der Hauptmechanismus hierfür. Da es sich bei ns-3 um ein C++-Programm handelt, können Standardmittel zum Generieren der Ausgabe eines C++-Programms verwendet werden:

#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}

Sie können sogar ein Protokollierungsmodul verwenden, um Ihrer Lösung eine kleine Struktur zu verleihen. Es gibt viele bekannte Probleme, die durch diesen Ansatz verursacht werden, und deshalb haben wir ein allgemeines Subsystem zur Ereignisverfolgung bereitgestellt, um diese Probleme zu lösen.

Die Hauptziele des NS-3-Rückverfolgungssystems sind:

  • Für grundlegende Aufgaben sollte das Tracing-System es dem Benutzer ermöglichen, einen Standard-Trace für gängige Quellen zu erstellen und Objekte auszuwählen, die den Trace generieren.

  • Fortgeschrittene Benutzer sollten in der Lage sein, das Tracing-System zu erweitern, um das generierte Ausgabeformat zu ändern oder neue Trace-Quellen einzufügen, ohne den Simulatorkern zu verändern;

  • Fortgeschrittene Benutzer können den Simulatorkern ändern, um neue Trace-Quellen und -Senken 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-Tracing-System basiert auf den Prinzipien der unabhängigen Tracing-Quellen und -Empfänger sowie einem einheitlichen Mechanismus zum Verbinden von Quellen mit Empfängern. Trace-Quellen sind Objekte, die in der Simulation auftretende Ereignisse signalisieren und Zugriff auf die zugrunde liegenden interessierenden Daten ermöglichen können. Beispielsweise kann eine Trace-Quelle anzeigen, wann ein Netzwerkgerät ein Paket empfangen hat, und den Inhalt des Pakets interessierten Trace-Empfängern verfügbar machen.

Trace-Quellen allein sind nutzlos, es sei denn, sie sind mit anderen Teilen des Codes „gekoppelt“, die mit den von der Senke bereitgestellten Informationen tatsächlich etwas Nützliches tun. Tracer sind Konsumenten von Ereignissen und Daten, die von Trace-Quellen bereitgestellt werden. Sie können beispielsweise eine Trace-Senke erstellen, die (bei Verbindung mit der Trace-Quelle des vorherigen Beispiels) die interessierenden Teile des empfangenen Pakets ausgibt.

Der Grund für diese explizite Trennung besteht darin, Benutzern die Möglichkeit zu geben, neue Senkentypen mit vorhandenen Trace-Quellen zu verbinden, ohne den Simulatorkern bearbeiten und neu kompilieren zu müssen. Im obigen Beispiel kann der Benutzer also nur durch Bearbeiten des Benutzerskripts einen neuen Tracer in seinem Skript definieren und ihn mit einer vorhandenen Trace-Quelle verbinden, die im Simulationskern definiert ist.

In diesem Tutorial gehen wir einige der vordefinierten Quellen und Senken durch und zeigen, wie sie mit dem geringsten Aufwand für den Benutzer konfiguriert werden können. Informationen zur erweiterten Trace-Konfiguration, einschließlich der Erweiterung des Trace-Namespace und der Erstellung neuer Trace-Quellen, finden Sie im NS-3-Handbuch oder in den Anleitungsabschnitten.

5.3.1 ASCII-Ablaufverfolgung

ns-3 bietet Hilfsfunktionen, die ein Low-Level-Tracing-System bereitstellen, das Sie bei der Einrichtung einfacher Paket-Trace-Informationen bei den Details unterstützt. Wenn Sie diese Funktion aktivieren, wird die Ausgabe in ASCII-Dateien angezeigt. Für diejenigen, die mit der NS-2-Ausgabe vertraut sind: Diese Art von Ablaufverfolgung ähnelt aus.tr, das von vielen Skripten generiert wird.

Kommen wir zur Sache und fügen unserem Scratch/myfirst.cc-Skript einige ASCII-Tracing-Ergebnisse hinzu. Kurz vor dem Anruf Simulator :: Run (), fügen Sie die folgenden Codezeilen hinzu:
AsciiTraceHelper ascii;

pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Wie viele andere NS-3-Redewendungen verwendet dieser Code ein Hilfsobjekt, um ASCII-Traces zu erstellen. Die zweite Zeile enthält zwei verschachtelte Methodenaufrufe. „Inside“-Methode CreateFileStream() verwendet die anonyme Objektsprache, um ein Dateistreamobjekt auf dem Stapel zu erstellen (ohne Objektnamen) und übergibt es an die aufgerufene Methode. Wir werden in Zukunft tiefer darauf eingehen, aber alles, was Sie an dieser Stelle wissen müssen, ist, dass Sie ein Objekt erstellen, das eine Datei namens „ meineerste.tr und übertrage es auf NS-3. Wir betrauen ns-3 mit der Pflege des erstellten Objekts während seiner gesamten Lebensdauer und lösen dabei Probleme, die durch eine wenig bekannte (absichtliche) Einschränkung im Zusammenhang mit C++-Stream-Objektkopiekonstruktoren verursacht werden.

Externer Anruf EnableAsciiAll() teilt dem Assistenten mit, dass Sie die ASCII-Ablaufverfolgung in Ihre Simulation für alle Punkt-zu-Punkt-Geräteverbindungen einbeziehen möchten und dass (angegebene) Ablaufverfolgungsempfänger Paketbewegungsinformationen im ASCII-Format aufzeichnen sollen.

Für diejenigen, die mit NS-2 vertraut sind, entsprechen verfolgte Ereignisse den bekannten Tracepoints, die die Ereignisse „+“, „-“, „d“ und „r“ protokollieren.
Jetzt können Sie das Skript erstellen und über die Befehlszeile ausführen:

$ ./waf --run scratch/myfirst

Wie so oft zuvor sehen Sie mehrere Meldungen von Waf und dann „‚Build‘ erfolgreich abgeschlossen“ mit einigen Meldungen vom laufenden Programm.

Beim Ausführen erstellt das Programm eine Datei mit dem Namen meineerste.tr. Aufgrund der Art der Arbeit Waf, standardmäßig wird die Datei nicht im lokalen Verzeichnis, sondern im Verzeichnis der obersten Ebene des Repositorys erstellt. Wenn Sie den Pfad ändern möchten, in dem Traces gespeichert werden, können Sie ihn mit dem Waf-Parameter angeben --cwd. Wir haben dies noch nicht getan. Um die ASCII-Trace-Datei myfirst.tr in Ihrem bevorzugten Editor anzuzeigen, müssen wir zum Verzeichnis der obersten Ebene unseres Repositorys navigieren.

Parsen von ASCII-Spuren

Es sind dort viele Informationen in ziemlich dichter Form enthalten, aber das erste, was Sie bemerken müssen, ist, dass die Datei aus einzelnen Zeilen besteht. Dies wird deutlich sichtbar, wenn Sie das Sichtfenster weiter vergrößern.

Jede Zeile in der Datei entspricht einem Trace-Ereignis. In diesem Fall verfolgen wir Ereignisse in der Übertragungswarteschlange, die in jedem Punkt-zu-Punkt-Netzwerkgerät in der Simulation vorhanden sind. Die Übertragungswarteschlange ist die Warteschlange, die jedes Paket für eine Punkt-zu-Punkt-Verbindung durchlaufen muss. Beachten Sie, dass jede Zeile in der Trace-Datei mit einem einzelnen Zeichen beginnt (und ein Leerzeichen dahinter steht). Dieses Symbol hat folgende Bedeutung:

+: In der Gerätewarteschlange ist ein Warteschlangenvorgang aufgetreten.
-: In der Gerätewarteschlange ist ein Elementabrufvorgang aufgetreten.
d: Das Paket wurde verworfen, normalerweise weil die Warteschlange voll war;
r: Das Paket wurde von einem Netzwerkgerät empfangen.

Schauen wir uns die erste Zeile der Trace-Datei genauer an. Ich werde es in Teile zerlegen (aus Gründen der Übersichtlichkeit mit Einrückungen) und die Zeilennummer auf der linken Seite angeben:

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 der Vorgang. Wir haben hier ein +-Symbol, das dem Vorgang des Anstehens für die Übertragung entspricht. Der zweite Abschnitt (Zeile 1) ist die Simulationszeit, ausgedrückt in Sekunden. Sie erinnern sich vielleicht an unsere Frage UdpEchoClient-Anwendung Beginnen Sie in zwei Sekunden mit dem Senden von Paketen. Hier sehen wir die Bestätigung, dass dies tatsächlich geschieht.

Der nächste Abschnitt des Trace-Beispiels (ab Zeile 2) zeigt, welche Trace-Quelle dieses Ereignis generiert hat (und gibt den Namespace-Trace an). Sie können sich den Trace-Namespace ähnlich wie einen Dateisystem-Namespace vorstellen. Die Wurzel des Namespace ist Knotenliste. Dies entspricht dem im Haupt-NS-3-Code verwalteten Container. Es enthält alle Knoten, die im Skript erstellt werden. So wie ein Dateisystem Verzeichnisse im Stammverzeichnis haben kann, Knotenliste Wir können viele Knoten haben. Die Zeile /NodeList/0 bezieht sich also auf den Nullknoten in der NodeList, den wir uns normalerweise als „Knoten 0“ vorstellen. Jeder Knoten verfügt über eine Liste der installierten Geräte. Diese Liste befindet sich als nächstes im Namensraum. Sie können sehen, dass dieses Trace-Ereignis von stammt Geräteliste/0, das ist das im Knoten installierte Nullgerät.

Nächster Teilstring, $ ns3 :: PointToPointNetDeviceGibt an, welches Gerät sich an Position Null befindet: die Geräteliste von Knoten Null. Denken Sie daran, dass die +-Operation in Zeile 0 bedeutete, dass ein Element zur Übertragungswarteschlange des Geräts hinzugefügt wurde. Dies spiegelt sich in den letzten Abschnitten des „Gleispfads“ wider: TxQueue/Enqueue.

Die übrigen Abschnitte im Trace sollten ziemlich intuitiv sein. Die Zeilen 3–4 zeigen an, dass das Paket in einem Punkt-zu-Punkt-Protokoll gekapselt ist. Die Zeilen 5–7 zeigen, dass das Paket einen IP4-Versionsheader hat und von der IP-Adresse stammt 10.1.1.1 und ist dafür gedacht 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 die erwarteten 1024 Bytes beträgt.

Die nächste Zeile in der Trace-Datei zeigt, dass dasselbe Paket aus der Übertragungswarteschlange auf demselben Knoten abgerufen wurde.

Die dritte Zeile in der Trace-Datei zeigt, dass das Paket von einem Netzwerkgerät auf dem Echo-Server-Host empfangen wurde. Ich habe das 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)

Beachten Sie, dass der Trace-Vorgang jetzt r ist und die Simulationszeit auf 2,25732 Sekunden erhöht wurde. Wenn Sie das Tutorial sorgfältig befolgt haben, bedeutet dies, dass Sie die Standardwerte für DataRate und Link Delay der Netzwerkgeräte beibehalten haben. Diese Zeitform sollte Ihnen bekannt vorkommen, wie Sie im vorherigen Abschnitt gesehen haben.

Der Namespace-Eintrag der Trace-Quelle (Zeile 2) wurde geändert, um widerzuspiegeln, dass dieses Ereignis von Knoten 1 stammt (/Knotenliste/1) und das Paket wird von der Trace-Quelle empfangen (/MacRx). Es sollte für Sie ziemlich einfach sein, die Bewegung des Pakets durch die Topologie zu verfolgen, indem Sie sich die verbleibenden Spuren in der Datei ansehen.

5.3.2 PCAP-Trace

Mit den ns-3 Device Helpers können auch Trace-Dateien im .pcap-Format erstellt werden. Akronym ppc (normalerweise in Kleinbuchstaben geschrieben) steht für Paketerfassung und ist eigentlich eine API, die die Definition des .pcap-Dateiformats umfasst. Das beliebteste Programm, das dieses Format lesen und anzeigen kann, ist Wireshark (früher genannt Ethereal). Es gibt jedoch viele Traffic-Trace-Analysatoren, die dieses Paketformat verwenden. Wir empfehlen Benutzern, die zahlreichen verfügbaren Tools zur Analyse von PCAP-Spuren zu verwenden. In diesem Tutorial konzentrieren wir uns auf die Anzeige von PCAP-Traces mit tcpdump.

Die Aktivierung der PCAP-Ablaufverfolgung erfolgt mit einer Codezeile.

pointToPoint.EnablePcapAll ("myfirst");

Fügen Sie diese Codezeile nach dem ASCII-Trace-Code ein, den wir gerade hinzugefügt haben scratch/myfirst.cc. Beachten Sie, dass wir nur die Zeichenfolge „myfirst“ übergeben haben, nicht „myfirst.pcap“ oder etwas Ähnliches. Dies liegt daran, dass es sich bei dem Parameter um ein Präfix und nicht um einen vollständigen Dateinamen handelt. Während der Simulation erstellt der Assistent tatsächlich eine Trace-Datei für jedes Punkt-zu-Punkt-Gerät. Dateinamen werden aus dem Präfix, der Knotennummer, der Gerätenummer und dem Suffix „ erstellt.ppc".

Für unser Beispielskript sehen wir am Ende Dateien mit dem Namen „myfirst-0-0.pcap"Und"myfirst-1-0.pcap", bei denen es sich um PCAP-Traces für Knoten 0-Gerät 0 bzw. Knoten 1-Gerät 0 handelt. Nachdem Sie die Codezeile zum Aktivieren der PCAP-Ablaufverfolgung hinzugefügt haben, können Sie das Skript wie gewohnt ausführen:

$ ./waf --run scratch/myfirst

Wenn Sie im obersten Verzeichnis Ihrer Distribution nachsehen, sollten Sie drei Dateien sehen: eine ASCII-Trace-Datei meineerste.tr, die wir zuvor untersucht haben, Dateien myfirst-0-0.pcap и myfirst-1-0.pcap - neue PCAP-Dateien, die wir gerade generiert haben.

Ausgabe mit tcpdump lesen

Der einfachste Weg, PCAP-Dateien anzuzeigen, ist derzeit die Verwendung von tcpdump.

$ 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 1024

Auf der Müllkippe myfirst-0-0.pcap (Clientgerät) Sie können sehen, dass das Echopaket nach 2 Sekunden Simulation gesendet wird. Wenn Sie sich den zweiten Dump ansehen (myfirst-1-0.pcap), werden Sie sehen, dass das Paket nach 2,257324 Sekunden empfangen wird. Im zweiten Dump sehen Sie, dass das Paket bei 2.257324 Sekunden zurückgegeben wird, und schließlich, dass das Paket im ersten Dump bei 2.514648 Sekunden vom Client zurückerhalten wurde.

Ausgabe mit Wireshark lesen

сли вы не знакомы с Wiresharkgibt es eine Website, von der Sie Programme und Dokumentation herunterladen können: http://www.wireshark.org/. Wireshark ist eine GUI, mit der diese Trace-Dateien angezeigt werden können. Wenn Sie Wireshark haben, können Sie jede der Trace-Dateien öffnen und den Inhalt anzeigen, als hätten Sie die Pakete mit einem Paket-Sniffer erfasst.

Source: habr.com

Kommentar hinzufügen