
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.pycWechseln 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: .
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 configureausgefĂŒhrt, um das Projekt fĂŒr Debug-Bauten mit aktivierten Beispielen und Tests zu konfigurieren. Sie haben auch
$ ./wafausgefĂŒ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.ccJetzt bauen Sie Ihr erstes Beispielskript mit waf:
$ ./wafSie 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/myfirstSie 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 empfangenHier 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: . 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 | filesGehen 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 | annotateUnsere 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
