Handbuch zum ns-3-Netzwerksimulator. Kapitel 4

Handbuch zum ns-3-Netzwerksimulator. Kapitel 4
Kapitel 1,2
Kapitel 3

4 KonzeptĂŒbersicht
4.1 SchlĂŒsselabstraktionen
4.1.1 Knoten (Node)
4.1.2 Anwendung (Application)
4.1.3 Kanal (Channel)
4.1.4 NetzgerÀt (Net Device)
4.1.5 Topologische Helfer
4.2 Erstes ns-3 Skript
4.2.1 Boilerplate-Code
4.2.2 Plug-in-Module
4.2.3 Namensraum ns3
4.2.4 Protokollierung
4.2.5 Hauptfunktion
4.2.6 Verwendung von topologischen Helfern
4.2.7 Verwendung der Anwendung
4.2.8 Simulator
4.2.9 Bereitstellung Ihres Szenarios
4.3 ns-3 Quellcode

Kapitel 4

KonzeptĂŒbersicht

Das Erste, was wir tun mĂŒssen, bevor wir mit dem Lernen oder Schreiben von ns-3-Code beginnen, ist, einige grundlegende Konzepte und Abstraktionen im System zu erklĂ€ren. Vieles davon mag fĂŒr einige offensichtlich erscheinen, aber wir empfehlen, sich Zeit zu nehmen, um diesen Abschnitt zu lesen, um sicherzustellen, dass Sie auf einer soliden Basis beginnen.

4.1 SchlĂŒsselabstraktionen

In diesem Abschnitt werden wir einige Begriffe betrachten, die typischerweise in Netzwerken verwendet werden, aber eine bestimmte Bedeutung in ns-3 haben.

4.1.1 Knoten (Node)

Im Internet-Jargon wird ein ComputergerĂ€t, das mit dem Netzwerk verbunden ist, als Host oder manchmal als Endsystem bezeichnet. Da ns-3 ein Netzwerk-Simulator und kein Internet-Simulator ist, verwenden wir absichtlich nicht den Begriff Host, da dieser eng mit dem Internet und seinen Protokollen verbunden ist. Stattdessen verwenden wir den allgemeineren Begriff, der auch von anderen Simulatoren verwendet wird und aus der Graphentheorie stammt – Knoten (node).

In ns-3 wird die grundlegende Abstraktion eines Rechenzentrums als Knoten bezeichnet. Diese Abstraktion wird in C++ durch die Klasse Node reprÀsentiert. Die Klasse NodeNode (Knoten) bietet Methoden zur Verwaltung der Darstellungen von Rechenzentren in Simulationen.

Sie sollten verstehen Node wie ein Computer, dem Sie FunktionalitĂ€ten hinzufĂŒgen werden. Sie werden Dinge hinzufĂŒgen wie Anwendungen, Protokollstapel und Schnittstellenkarten mit Treibern, die es dem Computer ermöglichen, nĂŒtzliche Arbeit zu verrichten. Wir verwenden dasselbe grundlegende Modell in ns-3.

4.1.2 Anwendung (Application)

In der Regel wird Software in zwei breite Klassen unterteilt. Systemsoftware organisiert verschiedene Computerressourcen wie Speicher, Prozessorzyklen, Festplatte, Netzwerk usw. gemĂ€ĂŸ einem bestimmten Rechenmodell. Systemsoftware nutzt diese Ressourcen normalerweise nicht, um Aufgaben auszufĂŒhren, die dem Benutzer direkt nĂŒtzen. Ein Benutzer startet in der Regel eine Anwendung, um ein bestimmtes Ziel zu erreichen, die die Ressourcen verwendet, die von der Systemsoftware verwaltet werden.

Oft wird die Grenze zwischen System- und Anwendungssoftware beim Wechsel der Berechtigungsstufen gezogen, der in den Ausnahmen des Betriebssystems erfolgt. In ns‑3 gibt es kein echtes Konzept eines Betriebssystems und daher keine Begriffe fĂŒr Berechtigungsstufen oder Systemaufrufe. Wir haben jedoch die Idee Anwendung. Genauso wie im „realen Leben“ zur DurchfĂŒhrung von Aufgaben Anwendungsprogramme auf Computern arbeiten, arbeiten ns‑3-Anwendungen auf ns‑3-Knoten, um Simulationen in einer simulierten Welt zu steuern.

In ns‑3 ist die grundlegende Abstraktion fĂŒr das Benutzerprogramm, das eine gewisse AktivitĂ€t zur Modellierung erzeugt, eine Anwendung. Diese Abstraktion wird in C++ durch die Klasse Application (Anwendung) dargestellt. Die Klasse Application bietet Methoden zur Steuerung unserer Version der Anwendungen auf Benutzerebene in Simulationen. Von den Entwicklern wird erwartet, dass sie zur Erstellung neuer Anwendungen die Klasse Application im Sinne der objektorientierten Programmierung spezialisieren. In diesem Handbuch werden wir SpezialitĂ€ten der Klasse Application verwenden, die genannt werden UdpEchoClientApplication und UdpEchoServerApplication. Wie zu erwarten war, bilden diese Anwendungen eine Sammlung von Client-/Server-Anwendungen, die zur Generierung und Echo-Simulation von Netzwerkpaketen verwendet werden.

4.1.3 Kanal (Channel)

In der realen Welt kann man einen Computer mit einem Netzwerk verbinden. HĂ€ufig werden die Umgebungen, ĂŒber die Daten in diesen Netzwerken ĂŒbertragen werden, als KanĂ€le bezeichnet. Wenn Sie ein Ethernet-Kabel an die Wandsteckdose anschließen, verbinden Sie den Computer mit dem Ethernet-Kommunikationskanal. In der simulierten Welt von ns-3 wird ein Knoten mit einem Objekt verbunden, das den Kommunikationskanal reprĂ€sentiert. Hier wird die grundlegende Abstraktion des Kommunikationsunternetzes als Kanal bezeichnet und durch die C++-Klasse Channel reprĂ€sentiert.

Klasse ChannelChannel stellt Methoden zur Verwaltung der Interaktion von Objekten im Unternetz und zur Verbindung mit ihnen zur VerfĂŒgung. KanĂ€le können auch von Entwicklern im Sinne der objektorientierten Programmierung spezialisiert werden. Eine Spezialisierung des Kanals kann etwas Einfaches wie einen Draht modellieren. Ein spezialisierter Kanal kann auch komplexe Dinge wie einen großen Ethernet-Switch oder einen dreidimensionalen Raum voller Hindernisse im Fall von drahtlosen Netzwerken modellieren.

In diesem Handbuch werden wir spezialisierte Versionen des Kanals verwenden, die als CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel und WifiChannelWifiChannel. CsmaChannel, zum Beispiel, modelliert eine Version des Kommunikationsunternetzes, die eine Kommunikationsumgebung mit mehreren Zugriffssteuerungen umsetzt. Dies gibt uns eine Ethernet-Àhnliche FunktionalitÀt.

4.1.4 NetzgerÀt (Net Device)

FrĂŒher war es so, dass, wenn Sie einen Computer mit einem Netzwerk verbinden wollten, Sie ein bestimmtes Netzwerkkabel und ein HardwaregerĂ€t kaufen mussten, das in der PC-Terminologie als Peripheriekarte bezeichnet wird, das im Computer installiert werden musste. Wenn auf der Peripheriekarte bestimmte Netzwerkfunktionen umgesetzt wurden, wurden diese als Netzwerkinterfacekarten oder Netzwerkkarten bezeichnet. Heute werden die meisten Computer mit integriertem Netzwerkinterface-Hardware geliefert, und die Benutzer sehen sie nicht mehr als separate GerĂ€te.

Eine Netzwerkkarte funktioniert nicht ohne einen Softwaretreiber, der die Hardware steuert. In Unix (oder Linux) wird ein Teil der Peripherie als GerĂ€t klassifiziert. GerĂ€te werden mit Hilfe von GerĂ€tetreibern verwaltet, wĂ€hrend NetzwerkgerĂ€te (NIC) unter Verwendung von Treibern fĂŒr NetzwerkgerĂ€te verwaltet werden (network device drivers) und haben die Sammelbezeichnung NetzwerkgerĂ€te (net devices). In Unix und Linux greifen Sie auf NetzwerkgerĂ€te ĂŒber Namen wie zum Beispiel zu eth0.

In ns‑3 umfasst die Abstraktion des NetzwerkgerĂ€ts sowohl den Softwaretreiber als auch die modellierte Hardware. WĂ€hrend der Simulation wird das NetzwerkgerĂ€t im Knoten 'installiert', um ihm zu ermöglichen, sich ĂŒber KanĂ€le mit anderen Knoten zu verbinden. Wie bei einem echten Computer kann der Knoten ĂŒber mehrere GerĂ€te mit mehreren KanĂ€len verbunden sein. NetDevices.

Die Netzwerkabstraktion des GerĂ€ts wird in C++ durch die Klasse NetDevice. Die Klasse NetDevice stellt Methoden zur Verwaltung von Verbindungen zu den Objekten Node und Channel bereit; und kann von Entwicklern im Sinne der objektorientierten Programmierung spezialisiert werden. In diesem Handbuch werden wir mehrere spezialisierte Versionen von NetDevice verwenden, die die Namen CsmaNetDevice, PointToPointNetDevice und WifiNetDevice. So wie ein Ethernet-Netzwerkadapter fĂŒr den Betrieb mit Ethernet, CsmaNetDevice fĂŒr den Betrieb mit CsmaChannel, PointToPointNetDevice fĂŒr den Betrieb mit PointToPointChannel, und WifiNetDevice – fĂŒr den Betrieb mit WifiChannel.

4.1.5 Topologische Helfer

In einem echten Netzwerk finden Sie Host-Computer mit hinzugefĂŒgten (oder integrierten) Netzwerkkarten. In ns‑3 wĂŒrden wir sagen, dass Sie Knoten mit angeschlossenen NetDevices sehen werden. In einem großen modellierten Netzwerk mĂŒssen Sie Verbindungen zwischen vielen Objekten organisieren. Node, NetDevice und Channel.

Da das Verbinden von NetDevices mit Knoten, NetDevices mit KanĂ€len, das Zuweisen von IP-Adressen usw. in ns‑3 eine alltĂ€gliche Aufgabe ist, stellen wir sogenannte topologische Hilfsmittel bereit, um dies so einfach wie möglich zu gestalten. Zum Beispiel erfordert das Erstellen eines NetDevice eine Vielzahl von Kernoperationen in ns‑3, das HinzufĂŒgen einer MAC-Adresse, die Einrichtung dieses NetzwerkgerĂ€ts im Node, die Konfiguration des Protokollstacks des Knotens und anschließend das Verbinden des NetDevice mit dem Channel. Noch mehr Operationen sind erforderlich, um mehrere GerĂ€te mit MehrpunktkanĂ€len zu verbinden und dann separate Netzwerke zu einem zusammenhĂ€ngenden Netzwerk (Internetworks) zu verbinden. Wir bieten Hilfsobjekte fĂŒr die Topologie, die diese zahlreichen Operationen zu einem benutzerfreundlichen Modell zusammenfassen.

4.2 Erstes ns-3 Skript

Wenn Sie das System wie oben vorgeschlagen installiert haben, befindet sich das ns‑3 Release im Verzeichnis mit dem Namen repos in Ihrem Home-Verzeichnis. Wechseln Sie in das Verzeichnis release

Wenn Sie kein solches Verzeichnis haben, haben Sie beim Bau der Release-Version von ns-3 kein Ausgabeverzeichnis angegeben. FĂŒhren Sie den Build wie folgt aus:
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf build

Dort sollten Sie eine Verzeichnisstruktur sehen, die ungefÀhr wie folgt aussieht:

AUTHORS       examples      scratch       utils       waf.bat*
bindings      LICENSE       src           utils.py    waf-tools
build         ns3           test.py*      utils.pyc   wscript
CHANGES.html  README        testpy-output VERSION     wutils.py
doc           RELEASE_NOTES testpy.supp   waf*        wutils.pyc

Wechseln Sie in das Verzeichnis examples/tutorial. Dort sollten Sie eine Datei mit dem Namen first.ccfinden. Dies ist ein Skript, das eine einfache Punkt-zu-Punkt-Verbindung zwischen zwei Knoten erstellt und ein Paket zwischen diesen Knoten ĂŒbertrĂ€gt. Lassen Sie uns dieses Skript Zeile fĂŒr Zeile durchgehen, indem wir first.cc in Ihrem bevorzugten Editor öffnen.

4.2.1 Boilerplate-Code
Die erste Zeile in der Datei ist die Editor-Modus-Zeile Eclipse. Sie informiert emacs ĂŒber die Formatierungsvereinbarungen (Codestil), die wir in unserem Quellcode verwenden.

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */

Dies ist immer eine ziemlich umstrittene Frage, daher sollten wir klarstellen, um sie gleich aus dem Weg zu rĂ€umen. Das Projekt ns-3 hat, wie viele große Projekte, einen Codestil angenommen, dem der gesamte bereitgestellte Code entsprechen muss. Wenn Sie Ihren Code in das Projekt einbringen möchten, mĂŒssen Sie letztendlich den ns-3-Codestandard einhalten, wie er in der Datei doc/codingstd.txt beschrieben ist oder auf der Projektwebseite gezeigt wird: https://www.nsnam.org/develop/contributing-code/coding-style/.

Wir empfehlen Ihnen, sich an das Aussehen des ns-3-Codes zu gewöhnen und diesen Standard immer anzuwenden, wenn Sie mit unserem Code arbeiten. Das gesamte Entwicklerteam und die Mitwirkenden haben sich nach einiger Diskussion darauf geeinigt. Die oben angegebene emacs-Moduszeile erleichtert die korrekte Formatierung, wenn Sie den Editor emacs verwenden.

Der Simulator ns-3 wird unter Verwendung der GNU General Public Licenselizenziert. Sie werden in jeder Datei des ns-3-Distros einen entsprechenden juristischen GNU-Kopf sehen. Oft können Sie ĂŒber dem GPL-Text und dem Autor, der unten angegeben ist, einen Copyright-Hinweis fĂŒr eine der beteiligten Institutionen im ns-3-Projekt sehen.

/* 
* This program is free software; you can redistribute it and/or modify 
* it under the terms of the GNU General Public License version 2 as 
* published by the Free Software Foundation; 
*
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

4.2.2 Plug-in-Module

Der eigentliche Code beginnt mit einer Reihe von Include-Anweisungen (include).

#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"

Um unseren Nutzern von Hochsprache-Skripten zu helfen, mit der Vielzahl an Header-Dateien in unserem System umzugehen, gruppieren wir diese nach ihrer Verwendung in großen Modulen. Wir stellen eine Header-Datei bereit, die rekursiv alle in diesem Modul verwendeten Header-Dateien lĂ€dt. Anstatt zu suchen, welches genau Header Sie benötigen und möglicherweise die richtigen AbhĂ€ngigkeiten zu erhalten, geben wir Ihnen die Möglichkeit, eine Gruppe von Dateien mit einer hohen Detailgenauigkeit zu laden. Dies ist nicht der effizienteste Ansatz, aber er macht das Schreiben von Skripten auf jeden Fall einfacher.

Jede der eingeschlossenen ns-3-Dateien wird in ein Verzeichnis mit dem Namen ns3 untergebracht, um wĂ€hrend des Build-Prozesses Namenskonflikte zu vermeiden. Die Datei ns3/core-module.h entspricht dem ns-3-Modul, das Sie im Verzeichnis src/core in der von Ihnen installierten Version finden. In der Auflistung dieses Verzeichnisses finden Sie eine große Anzahl von Header-Dateien. Wenn Sie einen Build durchfĂŒhren, Waf werden die öffentlichen Header-Dateien in das ns3-Verzeichnis im Unterverzeichnis build/debug

Wenn Sie kein solches Verzeichnis haben, haben Sie beim Bau der Release-Version von ns-3 kein Ausgabeverzeichnis angegeben. FĂŒhren Sie den Build wie folgt aus:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf build
oder
$ ./waf configure --build-profile=optimized --out=build/optimized
$ ./waf build

oder build/optimized, je nach Ihrer Konfiguration. Waf Wird auch automatisch eine Header-Datei fĂŒr das Modul generiert, um alle öffentlichen Header-Dateien zu laden. Da Sie diesem Handbuch natĂŒrlich konsequent folgen, haben Sie bereits

$ ./waf -d debug --enable-examples --enable-tests configure

ausgefĂŒhrt, um das Projekt fĂŒr Debug-Bauten mit aktivierten Beispielen und Tests zu konfigurieren. Sie haben auch

$ ./waf

ausgefĂŒhrt, um das Projekt zu erstellen. Wenn Sie jetzt also im Verzeichnis ../..//build/debug/ns3nachsehen, finden Sie dort unter anderem die Header-Dateien der vier oben genannten Module. Sie können den Inhalt dieser Dateien ĂŒberprĂŒfen und feststellen, dass sie alle öffentlichen Dateien der entsprechenden Module enthalten.

4.2.3 Namensraum ns3

Die nÀchste Zeile im Skript first.cc ist die Deklaration des Namensraums.

using namespace ns3;

Das ns‑3-Projekt wird im C++-Namensraum implementiert, der ns3 genannt wird. Dies gruppiert alle ns‑3-bezogenen Deklarationen in einem Sichtbarkeitsbereich außerhalb des globalen Namensraums, was, wie wir hoffen, die Integration mit anderem Code erleichtert. Die Verwendung des C++-Operators fĂŒhrt den ns‑3-Namensraum in den aktuellen (globalen) deklarierten Bereich ein. Das ist eine etwas seltsame Art zu sagen, dass Sie nach dieser Deklaration den ns3::Scope-Operator nicht mehr vor jedem ns‑3-Code einfĂŒgen mĂŒssen, um ihn zu verwenden. Wenn Sie mit NamensrĂ€umen nicht vertraut sind, schauen Sie in jedes beliebige C++-Lehrbuch und vergleichen Sie den Namensraum ns3 mit dem Verwendung des Namensraums std und der Deklarationen. using namespace std; in Beispielen mit dem Ausgabesystem cout und Streams.

4.2.4 Protokollierung

Die nÀchste Zeile des Skripts lautet:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Wir werden diese Aussage als praktischen Ort verwenden, um ĂŒber unser Dokumentationssystem zu sprechen. DoxygenWenn Sie die Website des ns‑3-Projekts besuchen, finden Sie im Navigationsbereich einen Link "Dokumentation". Wenn Sie diesen Link auswĂ€hlen, gelangen Sie zu unserer Dokumentationsseite. Es gibt einen Link zu "Letzte Version", die Sie zur Dokumentation der neuesten stabilen Version von ns‑3 fĂŒhrt. Wenn Sie den Link zu "API-Dokumentation" auswĂ€hlen, gelangen Sie zur API-Dokumentationsseite von ns‑3.

Auf der linken Seite der Seite finden Sie eine grafische Darstellung der Dokumentationsstruktur. Ein guter Ausgangspunkt ist das "Modulbuch" fĂŒr ns‑3 im Navigationsbaum von ns‑3. Wenn Sie das aufklappen Module, sehen Sie eine Liste der Dokumentation der ns‑3-Module. Wie oben erwĂ€hnt, hĂ€ngt das Konzept eines Moduls hier direkt von den in das Modul eingebundenen Dateien ab. Das ns‑3-Logging-System wird im Abschnitt Verwendung des Logging-Moduls, die wir spĂ€ter in diesem Handbuch erneut besuchen werden, aber Sie können die oben genannte Aussage ĂŒberprĂŒfen, indem Sie das Modul ansehen Kern, und dann das Buch Debugging-Tools, und dann die Seite auswĂ€hlen Logging. Klicken Sie auf Logging.

Jetzt sollten Sie die Dokumentation Doxygen fĂŒr das Modul durchsehen. Logging. In der Makroliste oben auf der Seite sehen Sie den Eintrag fĂŒr NS_LOG_COMPONENT_DEFINE. Bevor Sie den Link anklicken, sollten Sie die "Detaillierte Beschreibung" des Registrierungsmoduls lesen, um dessen Funktionsweise zu verstehen. Dazu können Sie nach unten scrollen oder "Mehr
" unter dem Diagramm auswĂ€hlen.

Sobald Sie einen allgemeinen Überblick darĂŒber haben, was passiert, fahren Sie fort und sehen Sie sich die Dokumentation zu den spezifischen NS_LOG_COMPONENT_DEFINE an. Ich werde die Dokumentation hier nicht duplizieren, aber zusammenfassend kann ich sagen, dass diese Zeile einen Registrierungsbestandteil mit dem Namen FirstScriptExample, der das Aktivieren und Deaktivieren der Konsolenregistrierung von Nachrichten ĂŒber einen Namenslink ermöglicht.

4.2.5 Hauptfunktion

In den folgenden Zeilen des Skripts werden Sie sehen,

int 
main (int argc, char *argv[])
{ 

Dies ist einfach die Deklaration der Hauptfunktion Ihres Programms (Skripts). Wie in jedem C++-Programm mĂŒssen Sie die Hauptfunktion definieren, sie wird als erstes ausgefĂŒhrt. Hier gibt es nichts Besonderes. Ihr ns-3-Skript ist einfach ein C++-Programm. Die folgende Zeile setzt die Zeitauflösung auf 1 Nanosekunde, was der Standardwert ist:

Time::SetResolution (Time::NS);

Die Zeitauflösung oder einfach Auflösung ist der kleinste Zeitwert, der verwendet werden kann (die kleinste darstellbare Differenz zwischen zwei Zeitwerten). Sie können die Auflösung genau einmal Ă€ndern. Der Mechanismus, der diese FlexibilitĂ€t ermöglicht, benötigt Speicherplatz, daher geben wir, sobald die Auflösung ausdrĂŒcklich festgelegt ist, den Speicher frei, um weitere Aktualisierungen zu verhindern. (Wenn Sie die Auflösung nicht ausdrĂŒcklich festlegen, wird sie standardmĂ€ĂŸig auf eine Nanosekunde gesetzt, und der Speicher wird zu Beginn der Simulation freigegeben.)

Die folgenden beiden Zeilen des Skripts dienen dazu, zwei Protokollierungskomponenten zu aktivieren, die in die Anwendungen EchoClient und EchoServer:

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);

Wenn Sie die Dokumentation zur Logging-Komponente gelesen haben, werden Sie feststellen, dass es mehrere Detailstufen der Protokollierung gibt, die Sie fĂŒr jede Komponente aktivieren können. Diese beiden Codezeilen aktivieren die Debug-Protokollierung auf der INFO-Stufe fĂŒr Echo-Clients und -Server. Auf dieser Stufe wird die Anwendung wĂ€hrend der Simulation Nachrichten beim Senden und Empfangen von Paketen ausgeben.

Nun kommen wir direkt zur Erstellung der Topologie und zum Start der Simulation. Wir setzen topologische Hilfsobjekte ein, um diese Arbeit so einfach wie möglich zu gestalten.

4.2.6 Verwendung von topologischen Helfern

Die beiden folgenden Codezeilen in unserem Skript erzeugen tatsÀchlich Node-Objekte ns-3, die Computer in der Simulation darstellen werden.

NodeContainer nodes;
nodes.Create(2);

Bevor wir fortfahren, lassen Sie uns die Dokumentation fĂŒr die Klasse NodeContainer. Ein weiterer Weg, um zur Dokumentation dieser Klasse zu gelangen, erfolgt ĂŒber den Tab Klassen auf den Seiten Doxygen. Wenn Sie Doxygen bereits geöffnet haben, scrollen Sie einfach nach oben zum oberen Ende der Seite und wĂ€hlen Sie den Tab Klassen aus. Sie sollten eine neue Reihe von Tabs sehen, einer davon ist die Liste der Klassen. Unter diesem Tab sehen Sie eine Liste aller Klassen von ns-3. Scrollen Sie nach unten bis zu ns3::NodeContainer. Wenn Sie die Klasse gefunden haben, wĂ€hlen Sie sie aus, um zur Dokumentation fĂŒr die Klasse zu gelangen.

Wie wir uns erinnern, ist eines unserer SchlĂŒsselkonzepte der Knoten. Er stellt den Computer dar, dem wir Dinge wie Protokollstapel, Anwendungen und Schnittstellenkarten hinzufĂŒgen möchten. Der topologische Helfer NodeContainer bietet eine bequeme Möglichkeit zum Erstellen, Verwalten und Zugreifen auf alle Objekte, Nodedie wir zur DurchfĂŒhrung der Simulation erstellen. Die erste Zeile oben deklariert einfach NodeContainer, die wir nodes nennen. Die zweite Zeile ruft die Methode Create fĂŒr das Objekt nodes auf und fordert den Container auf, zwei Knoten zu erstellen. Wie in Doxygenbeschrieben, fordert der Container das ns-3-System auf, zwei Objekte zu erstellen Node und speichert die Zeiger auf diese Objekte intern.

Die im Skript erstellten Knoten tun noch nichts. Der nĂ€chste Schritt beim Aufbau der Topologie ist die Verbindung unserer Knoten mit dem Netzwerk. Die einfachste Form eines Netzwerks, die wir unterstĂŒtzen, ist eine Punkt-zu-Punkt-Verbindung zwischen zwei Knoten. Wir werden jetzt eine solche Verbindung herstellen.

PointToPointHelper

Wir erstellen eine Punkt-zu-Punkt-Verbindung, indem wir einem uns vertrauten Muster folgen, und verwenden ein topologisches Hilfsobjekt fĂŒr die DurchfĂŒhrung der Low-Level-Arbeiten, die zur Verbindung erforderlich sind. Erinnern wir uns daran, dass unsere beiden SchlĂŒsselabstraktionen NetDevice und Channelim realen Leben ungefĂ€hr den Peripheriekarten und Netzwerkkabeln entsprechen. In der Regel sind diese beiden Dinge eng miteinander verbunden, und niemand kann erwarten, beispielsweise GerĂ€te Ethernet ĂŒber einen drahtlosen Kanal auszutauschen. Unsere topologischen Hilfsobjekte folgen dieser engen Beziehung, und daher werden Sie in diesem Szenario ein Objekt PointToPointHelper zum Konfigurieren und Verbinden von ns-3-Objekten verwenden. PointToPointNetDevice und PointToPointChannelDie nĂ€chsten drei Zeilen im Szenario:

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

Die erste Zeile,

PointToPointHelper pointToPoint;

erstellt im Stack eine Instanz des Objekts. PointToPointHelperAus Sicht der oberen Ebene sagt die nÀchste Zeile,

pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));

dem Objekt PointToPointHelper das zu verwendende Wert «5 Mbit/s» (fĂŒnf Megabit pro Sekunde) als «DataRate».

In spezifischerer Sicht entspricht die Zeile «DataRate» dem, was wir einen Attribut nennen. PointToPointNetDeviceWenn Sie sich ansehen, Doxygen fĂŒr die Klasse ns3::PointToPointNetDevice und in der Dokumentation der Methode GetTypeId finden Sie eine Liste der Attribute, die fĂŒr das GerĂ€t definiert sind. Unter ihnen wird es das Attribut «DataRate» geben. Die meisten fĂŒr Benutzer sichtbaren ns-3-Objekte haben Ă€hnliche Listen von Attributen. Wir nutzen diesen Mechanismus fĂŒr eine einfache Konfiguration der Simulation ohne erneute Kompilierung, wie Sie im nĂ€chsten Abschnitt sehen werden.

Ähnlich wie «DataRate» im PointToPointNetDevice finden Sie das Attribut «Delay», das mit PointToPointChannel verbunden ist. Die finale Zeile,

pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));

sagen PointToPointHelper verwendet den Wert «2 ms» (zwei Millisekunden) als Wert fĂŒr die Ausbreitungsverzögerung ĂŒber den Punkt-zu-Punkt-Kanal, den er anschließend erstellt.

NetDeviceContainer

Bis jetzt haben wir im Szenario ein NodeContainer, das zwei Knoten enthĂ€lt. Wir haben ein PointToPointHelper, das bereit ist, um Objekte PointToPointNetDevices zu erstellen und sie mithilfe des Objekts PointToPointChannel zu verbinden. So wie wir ein topologisches Hilfsobjekt NodeContainer verwendet haben, um Knoten zu erstellen, werden wir PointToPointHelper bitten, die mit der Erstellung, Konfiguration und Installation unserer GerĂ€te verbundenen Arbeiten fĂŒr uns zu erledigen. Wir benötigen eine Liste aller erstellten Objekte. NetDevice, deshalb verwenden wir NetDeviceContainer zum Speichern, so wie wir NodeContainer zum Speichern der von uns erstellten Knoten verwendet haben. Die folgenden beiden Codezeilen

NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);

vollenden die Konfiguration der GerĂ€te und des Kanals. Die erste Zeile deklariert den oben genannten GerĂ€tekontainer, und die zweite fĂŒhrt die Hauptarbeit aus. Die Methode Installieren des Objekts PointToPointHelper das gleiche NodeContainer als Parameter. Innerhalb NetDeviceContainer fĂŒr jeden Knoten, der sich in NodeContainer erstellt wird (fĂŒr die Punkt-zu-Punkt-Verbindung muss es genau zwei geben) PointToPointNetDevice geschaffen und im GerĂ€tekontainer gespeichert. PointToPointChannel wird erstellt, und es sind zwei PointToPointNetDevices. Nach der Erstellung der Objekte werden die in PointToPointHelper, gespeicherten Attribute verwendet, um die entsprechenden Attribute in den erstellten Objekten zu initialisieren.

Nach dem Aufruf pointToPoint.Install (nodes) haben wir zwei Knoten, jeder mit einem installierten "Punkt-zu-Punkt"-NetzwerkgerĂ€t und einem "Punkt-zu-Punkt"-Kanal zwischen ihnen. Beide GerĂ€te werden so konfiguriert, dass sie Daten mit einer Geschwindigkeit von fĂŒnf Megabit pro Sekunde mit einer Übertragungslatenz von zwei Millisekunden ĂŒber den Kanal ĂŒbertragen.

InternetStackHelper

Jetzt sind unsere Knoten und GerĂ€te konfiguriert, aber auf unseren Knoten sind keine Protokollstacks installiert. Die folgenden beiden Codezeilen kĂŒmmern sich darum.

InternetStackHelper stack;
stack.Install (nodes);

InternetStackHelper stellt einen topologischen Helfer fĂŒr Internetstacks dar, Ă€hnlich wie PointToPointHelper fĂŒr Punkt-zu-Punkt-NetzwerkgerĂ€te. Die Methode Installieren nimmt NodeContainer als Parameter. Bei der AusfĂŒhrung installiert sie den Internetstack (TCP, UDP, IP usw.) auf jedem Knoten des Containers.

Ipv4AddressHelper

Dann mĂŒssen wir unsere GerĂ€te mit IP-Adressen verknĂŒpfen. Wir stellen einen topologischen Helfer zur Verwaltung der IP-Adressverteilung bereit. Die einzige fĂŒr den Benutzer sichtbare API besteht darin, die Basis-IP-Adresse und die Netzwerkmaske festzulegen, die bei der tatsĂ€chlichen Adressverteilung verwendet werden (dies geschieht auf niedrigerer Ebene innerhalb des Helfers). Die folgenden beiden Codezeilen in unserem Beispielszenario first.cc,

Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");

Deklarieren ein Hilfsobjekt der Adresse und sagen ihm, dass es anfangen soll, IP-Adressen aus dem Netzwerk 10.1.1.0 zuzuweisen, wobei die Bitmaske 255.255.255.0 verwendet wird. StandardmĂ€ĂŸig beginnen die zugewiesenen Adressen mit eins und erhöhen sich monoton, daher wird die erste aus dieser Basis zugewiesene Adresse 10.1.1.1 sein, dann 10.1.1.2 usw. In der RealitĂ€t speichert das System ns-3 auf niedriger Ebene alle zugewiesenen IP-Adressen und erzeugt einen fatalen Fehler, wenn Sie versehentlich eine Situation schaffen, in der dieselbe Adresse zweimal generiert wird (ĂŒbrigens ist es schwierig, diesen Fehler zu debuggen).

Die nÀchste Codezeile,

Ipv4InterfaceContainer interfaces = address.Assign (devices);

fĂŒhrt die tatsĂ€chliche Zuweisung der Adresse durch. In ns-3 stellen wir eine Verbindung zwischen der IP-Adresse und dem GerĂ€t her, indem wir das Objekt Ipv4Interfaceverwenden. So wie wir manchmal eine Liste von Netzwerkteilen benötigen, die der Assistent fĂŒr die spĂ€tere Verwendung erstellt hat, benötigen wir manchmal eine Liste von Objekten, die Ipv4Interface. Ipv4InterfaceContainer diese FunktionalitĂ€t bereitstellt.

Wir haben ein Punkt-zu-Punkt-Netzwerk aufgebaut, mit installierten Stacks und zugewiesenen IP-Adressen. Jetzt benötigen wir in jedem Knoten Anwendungen zur Generierung von Verkehr.

4.2.7 Verwendung der Anwendung

Eine weitere grundlegende Abstraktion des Systems ns-3 ist die Anwendung (Anwendung). In diesem Szenario verwenden wir zwei Spezialisierungen der Basisklasse Anwendung ns-3, die UdpEchoServerApplication und UdpEchoClientApplication. Wie in den vorherigen FĂ€llen verwenden wir Hilfsobjekte zur Konfiguration und Verwaltung der Basisklassenobjekte. Hier verwenden wir UdpEchoServerHelper und UdpEchoClientHelperObjekte, um unser Leben einfacher zu machen.

UdpEchoServerHelper

Die folgenden Codezeilen in unserem Beispielskript first.cc werden zur Konfiguration der UDP-Echo-Serveranwendung auf einem der zuvor erstellten Knoten verwendet.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

Die erste Zeile des obigen Codeabschnitts erstellt UdpEchoServerHelper. Wie gewohnt handelt es sich hierbei nicht um eine Anwendung an sich, sondern um ein Objekt, das uns hilft, echte Anwendungen zu erstellen. Eine unserer Vereinbarungen ist es, die erforderlichen Attribute an den Konstruktor des Hilfsobjekts weiterzugeben. In diesem Fall kann der Assistent nichts NĂŒtzliches tun, wenn ihm die Portnummer, an der der Server auf Pakete wartet, nicht zur VerfĂŒgung gestellt wird; diese Nummer muss auch dem Client bekannt sein. In diesem Fall ĂŒbergeben wir die Portnummer an den Konstruktor des Assistenten. Der Konstruktor fĂŒhrt seinerseits einfach aus SetAttribute mit dem ĂŒbergebenen Wert. SpĂ€ter können Sie bei Bedarf mit SetAttribute einen anderen Wert fĂŒr das Attribut „Port“ festlegen.

Ähnlich wie viele andere Hilfsobjekte hat das Objekt UdpEchoServerHelper eine Methode Installieren. Die AusfĂŒhrung dieser Methode fĂŒhrt tatsĂ€chlich dazu, dass eine grundlegende Echo-Server-Anwendung erstellt und an einen Knoten gebunden wird. Interessanterweise verwendet die Methode Installieren das gleiche NodeContainter einen Parameter, genau wie andere Installieren Methoden, die wir gesehen haben.

Die implizite C++-Umwandlung, die hier arbeitet, nimmt das Ergebnis der Methode node.Get (1) (die einen Smart Pointer auf das Knotenobjekt – Ptr) zurĂŒckgibt und verwendet ihn im Konstruktor fĂŒr das anonyme Objekt NodeContainer, das dann an die Methode InstallierenĂŒbergeben wird. Wenn Sie im C++-Code nicht bestimmen können, mit welcher Signatur die Methode kompiliert und ausgefĂŒhrt wird, suchen Sie nach den impliziten Umwandlungen.

Nun sehen wir, dass echoServer.Install vorbereitet ist, die Anwendung UdpEchoServerApplication auf dem in NodeContainergefundenen Knoten zu installieren, den wir zur Verwaltung unserer Knoten verwenden, Knoten mit Index 1. Die Methode Installieren gibt den Container zurĂŒck, der Zeiger auf alle Anwendungen enthĂ€lt (in diesem Fall eine, da wir ein anonymes NodeContainer, das einen Knoten enthĂ€lt, ĂŒbergeben haben), erstellt vom Assistenten.

Die Anwendungen mĂŒssen den Zeitpunkt fĂŒr den Start der Verkehrsgenerierung angeben „start“ und ggf. auch die Zeit angeben, wann sie gestoppt werden soll „stop“. Wir geben beide Parameter an. Diese Zeiten werden mit den Methoden ApplicationContainer Start und Stopfestgelegt. Diese Methoden nehmen Parameter vom Typ Zeit. In diesem Fall verwenden wir eine explizite C++-Umwandlungssequenz, um C++ double 1.0 und es in ein Objekt tns‑3 Time umwandeln, das das Objekt Seconds verwendet, um in Sekunden zu konvertieren. Denken Sie daran, dass die Umwandlungsregeln vom Autor des Modells kontrolliert werden können und C++ eigene Regeln hat, sodass Sie nicht immer darauf vertrauen können, dass die Parameter so umgewandelt werden, wie Sie es erwarten. Zwei Zeilen,

serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));

fĂŒhrt dazu, dass die Echo-Serveranwendung (automatisch) nach einer Sekunde nach Beginn der Simulation gestartet wird und nach zehn Sekunden Simulation stoppt (deaktiviert wird). Da wir ein Simulationsereignis (Ereignis zum Stoppen der Anwendung) deklariert haben, das in zehn Sekunden ausgefĂŒhrt wird, wird mindestens zehn Sekunden Netzwerkbetrieb simuliert.

UdpEchoClientHelper

Die Clientanwendung echo wird in einer Weise konfiguriert, die praktisch identisch mit der des Servers ist. Es gibt ein grundlegendes Objekt UdpEchoClientApplication, das von
UdpEchoClientHelper.

UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));;

FĂŒr den Echo-Client mĂŒssen jedoch fĂŒnf verschiedene Attribute gesetzt werden. Die ersten beiden Attribute werden beim Erstellen gesetzt. UdpEchoClientHelperWir ĂŒbergeben die Parameter, die verwendet werden (innerhalb des Helfers), um die Attribute festzulegen. "RemoteAddress" und "RemotePort" in Übereinstimmung mit unserem Abkommen zur Übertragung der erforderlichen Parameter an den Konstruktor des Helfers.

Erinnern wir uns, dass wir verwendet haben Ipv4InterfaceContainer , um die IP-Adressen zu verfolgen, die wir unseren GerÀten zugewiesen haben. Das Null-Interface im Schnittstellencontainer entspricht der IP-Adresse des Nullknotens im Knotencontainer. Das erste Interface im Schnittstellencontainer entspricht der IP-Adresse des ersten Knotens im Knotencontainer. Daher erstellen wir in der ersten Codezeile (oben) den Helfer und teilen ihm mit, dass die Remote-Adresse des Clients die IP-Adresse ist, die dem Knoten zugewiesen ist, auf dem sich der Server befindet. Wir geben auch an, dass die Pakete an den neunten Port gesendet werden sollen.

Das Attribut „MaxPackets“ informiert den Client ĂŒber die maximale Anzahl von Paketen, die wir wĂ€hrend der Simulation senden können. Das Attribut „Interval“ gibt dem Client an, wie lange er zwischen den Paketen warten soll, und das Attribut „PacketSize“ informiert den Client darĂŒber, wie groß die Nutzlast des Pakets sein soll. Mit dieser Kombination von Attributen sagen wir dem Client, dass er ein 1024-Byte-Paket senden soll.

Wie im Fall des Echo-Servers setzen wir beim Echo-Client die Attribute Start und Stop, aber hier starten wir den Client eine Sekunde nach dem Einschalten des Servers (zwei Sekunden nach Beginn der Simulation).

4.2.8 Simulator

In diesem Schritt mĂŒssen wir die Simulation starten. Dies geschieht mit der globalen Funktion Simulator::Run.

Simulator::Run ();

Als wir zuvor die Methoden aufgerufen haben,

serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
... 
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));

haben wir tatsĂ€chlich Ereignisse im Simulator fĂŒr 1,0 Sekunden, 2,0 Sekunden und zwei Ereignisse fĂŒr 10,0 Sekunden geplant. Nach dem Aufruf Simulator::Run, wird das System beginnen, die Liste der geplanten Ereignisse zu durchlaufen und sie auszufĂŒhren. Zuerst wird es das Ereignis nach 1,0 Sekunden auslösen, was die Anwendung des Echo-Servers aktiviert (dieses Ereignis kann wiederum viele andere Ereignisse planen). Dann wird es das Ereignis auslösen, das fĂŒr t = 2,0 Sekunden geplant ist, was die Anwendung des Echo-Clients startet. Auch dieses Ereignis kann viele weitere Ereignisse planen. Die Umsetzung des Startereignisses im Echo-Client wird die Phase der DatenĂŒbertragung in der Simulation einleiten, indem sie ein Paket an den Server sendet.

Der Akt des Sendens eines Pakets an den Server wird eine Kette von Ereignissen auslösen, die im Hintergrund automatisch geplant werden und die Mechanik des Sendens von Echo-Signalen gemĂ€ĂŸ den Synchronisationsparametern umsetzen, die wir im Skript festgelegt haben.

Insgesamt, da wir nur ein Paket senden (denken wir daran, dass das Attribut MaxPackets auf eins gesetzt wurde), wird die Kette von Ereignissen, die durch diese einzige Client-Echo-Anfrage initiiert wurde, enden, und die Simulation wird in den Wartemodus gehen. Sobald dies geschieht, werden die verbleibenden geplanten Ereignisse die Ereignisse Stop fĂŒr den Server und den Client sein. Wenn diese Ereignisse ausgefĂŒhrt werden, wird es keine weiteren Ereignisse zur Verarbeitung geben und Simulator::Run die Kontrolle zurĂŒckgeben. Die Simulation ist abgeschlossen.

Nun bleibt nur noch das AufrĂ€umen. Dies geschieht durch den Aufruf der globalen Funktion Simulator::Destroy. Da Funktionen von Helfern (oder Low-Level-Code von ns-3) aufgerufen wurden, die so organisiert sind, dass im Simulator Hooks eingefĂŒgt werden, um alle erstellten Objekte zu löschen. Sie mĂŒssen keine dieser Objekte selbst verfolgen – alles, was Sie tun mĂŒssen, ist, zu deaktivieren. Simulator::Destroy Die ns-3-System erledigt diese schwierige Arbeit fĂŒr Sie. Die verbleibenden Zeilen unseres ersten ns-3-Skripts, first.cc, tun genau das:

Simulator::Destroy ();
return 0;
}

Wann stoppt der Simulator?

ns-3 ist ein diskreter Ereignissimulator (DE). In einem solchen Simulator ist jedes Ereignis mit der Zeit seiner AusfĂŒhrung verbunden, und die Simulation lĂ€uft weiter, indem sie Ereignisse in der Reihenfolge ihrer Entstehung wĂ€hrend der Simulation verarbeitet. Ereignisse können die Planung zukĂŒnftiger Ereignisse auslösen (zum Beispiel kann ein Timer sich selbst neu planen, um in der nĂ€chsten Zeiteinheit abzuschließen).

Anfangsereignisse werden normalerweise von einem Objekt ausgelöst, z. B. wird IPv6 die Dienste im Netzwerk, Nachbardanfragen usw. planen. Die Anwendung plant das erste Paketversandereignis usw. Wenn ein Ereignis verarbeitet wird, kann es null, ein oder mehrere Ereignisse generieren. WÀhrend der Simulation treten Ereignisse auf, indem sie einfach enden oder neue erzeugen. Die Simulation stoppt automatisch, wenn die Ereigniswarteschlange leer ist oder ein spezielles Ereignis entdeckt wird. Stop. Das Ereignis Stop wird durch die Funktion Simulator::Stop (Stoppe die Zeit).

Es gibt einen typischen Fall, in dem Simulator::Stop absolut notwendig ist, um die Simulation zu beenden: wenn es selbsttragende Ereignisse gibt. Selbsttragende (oder wiederkehrende) Ereignisse sind Ereignisse, die sich immer selbst neu planen. Folglich halten sie die Ereigniswarteschlange immer nicht leer. Es gibt viele Protokolle und Module, die wiederkehrende Ereignisse enthalten, wie z. B.:

‱ FlowMonitor – periodische ÜberprĂŒfung auf verlorene Pakete;

‱ RIPng – periodische Übertragung von Routertabelle-Updates;

‱ usw.

In solchen FĂ€llen Simulator::Stop ist notwendig, um die Simulation korrekt zu stoppen. Außerdem, wenn ns-3 im Emulationsmodus ist, wird RealtimeSimulator verwendet, um die Simulation mit den Uhren des Computers zu synchronisieren, und Simulator::Stop ist notwendig, um den Prozess zu stoppen.

Viele der im Lehrbuch enthaltenen Simulationsprogramme machen keinen Aufruf. Simulator::Stop Offensichtlich, da sie automatisch mit dem Erschöpfen der Ereignisse in der Warteschlange beendet werden. Diese Programme werden jedoch auch den Aufruf Simulator::Stop annehmen. Zum Beispiel plant der folgende zusÀtzliche Befehl im ersten Programmbildschirm eine explizite Beendigung in Sekunde 11:

+ Simulator::Stop (Seconds (11.0));
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}

Das obige wird das Verhalten dieses Programms tatsĂ€chlich nicht Ă€ndern, da diese spezifische Simulation natĂŒrlich nach 10 Sekunden endet. Aber wenn Sie die Stopptime im obigen Befehl von 11 Sekunden auf 1 Sekunde Ă€ndern wĂŒrden, wĂŒrden Sie feststellen, dass die Simulation stoppt, bevor eine Ausgabe auf dem Bildschirm erscheint (da die Ausgabe etwa 2 Sekunden Simulationszeit benötigt).

Es ist wichtig, Simulator::Stop vor dem Aufruf von Simulator::Run aufzurufen; andernfalls kann Simulator::Run niemals die Kontrolle an das Hauptprogramm zurĂŒckgeben, um die Beendigung durchzufĂŒhren!

4.2.9 Bereitstellung Ihres Szenarios

Wir haben das Erstellen Ihrer einfachen Skripte trivial gemacht. Alles, was Sie tun mĂŒssen, ist, Ihr Skript in das Verzeichnis scratch zu legen, und es wird automatisch zusammengebaut, wenn Sie starten Waf. Lass es uns versuchen. Gehen Sie zurĂŒck in das Hauptverzeichnis und kopieren Sie examples/tutorial/first.cc in das Verzeichnis scratch

$ cd ../..
$ cp examples/tutorial/first.cc scratch/myfirst.cc

Jetzt bauen Sie Ihr erstes Beispielskript mit waf:

$ ./waf

Sie sollten Meldungen sehen, dass Ihr erstes Beispiel erfolgreich erstellt wurde.

Waf: Betrete Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
[614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o
[706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst
Waf: Verlasse Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (2.357s)

Jetzt können Sie das Beispiel ausfĂŒhren (beachten Sie, dass, wenn Sie Ihr Programm im Verzeichnis scratch bauen, Sie es auch ausfĂŒhren mĂŒssen aus scratch):

$ ./waf --run scratch/myfirst

Sie sollten eine Àhnliche 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' erfolgreich abgeschlossen (0.418s) 1024 Bytes an 10.1.1.2 gesendet
1024 Bytes von 10.1.1.1 empfangen
1024 Bytes von 10.1.1.2 empfangen

Hier sehen Sie, dass das Build-System prĂŒft, ob die Datei erstellt wurde, und sie dann ausfĂŒhrt. Sie sehen den Komponenten-Log auf dem Echo-Client, der anzeigt, dass er ein 1024-Byte-Paket an den Echo-Server 10.1.1.2 gesendet hat. Sie sehen auch den Logging-Komponenten auf dem Echo-Server, der sagt, dass er 1024 Byte von 10.1.1.1 erhalten hat. Der Echo-Server gibt das Paket stillschweigend zurĂŒck, und im Log des Echo-Clients sehen Sie, dass er sein Paket vom Server zurĂŒckerhalten hat.

4.3 ns-3 Quellcode

Jetzt, wo Sie einige der ns-3-Hilfsprogramme verwendet haben, können Sie sich den Quellcode ansehen, der diese FunktionalitĂ€t implementiert. Den aktuellsten Code finden Sie auf unserem Webserver unter folgendem Link: https://gitlab.com/nsnam/ns-3-dev.git. Dort sehen Sie eine Zusammenfassungsseite von Mercurial fĂŒr unseren ns-3-Entwicklungsbaum. Oben auf der Seite finden Sie einige Links,

summary | shortlog | changelog | graph | tags | files

Gehen Sie weiter und wÀhlen Sie den Link zu den Dateien. So wird die oberste Ebene der meisten unserer Repositories aussehen:

drwxr-xr-x                               [up]
drwxr-xr-x                               bindings python  files
drwxr-xr-x                               doc              files
drwxr-xr-x                               examples         files
drwxr-xr-x                               ns3              files
drwxr-xr-x                               scratch          files
drwxr-xr-x                               src              files
drwxr-xr-x                               utils            files
-rw-r--r-- 2009-07-01 12:47 +0200 560    .hgignore        file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1886   .hgtags          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1276   AUTHORS          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 30961  CHANGES.html     file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 17987  LICENSE          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 3742   README           file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 16171  RELEASE_NOTES    file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 6      VERSION          file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 88110  waf              file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 28     waf.bat          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 35395  wscript          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 7673   wutils.py        file | revisions | annotate

Unsere Beispielskripte befinden sich im Verzeichnis examples. Wenn Sie auf die Beispiele klicken, sehen Sie eine Liste von Unterverzeichnissen. Eine der Dateien im Unterverzeichnis tutorial — first.cc. Wenn Sie auf klicken, first.cc sehen Sie den Code, den Sie gerade studiert haben.

Der Quellcode befindet sich hauptsĂ€chlich im Verzeichnis src. Sie können den Quellcode einsehen, indem Sie auf den Verzeichnisnamen klicken oder auf den Link Dateien rechts neben dem Verzeichnisnamen. Wenn Sie auf das Verzeichnis src klicken, erhalten Sie eine Liste der Unterverzeichnisse von src. Wenn Sie dann auf das Unterverzeichnis core klicken, finden Sie eine Liste von Dateien. Die erste Datei, die Sie sehen werden (zum Zeitpunkt des Verfassens dieses Leitfadens) — abort.h. Wenn Sie auf den Link abort.h, werden Sie zur Quelldatei fĂŒr abort.h, die nĂŒtzliche Makros zum Verlassen von Skripten enthĂ€lt, wenn abnormale Bedingungen festgestellt werden. Der Quellcode fĂŒr die Hilfsprogramme, die wir in diesem Kapitel verwendet haben, finden Sie im Verzeichnis src/Applications/helper. Zögern Sie nicht, im Verzeichnisbaum zu stöbern, um zu verstehen, was wo ist und den Stil von ns-3 zu durchdringen.

Quelle: habr.com

60GB SSD 8Gb DDR4