
4 Ăberblick ĂŒber das Konzept
4.1 SchlĂŒsselabstraktionen
4.1.1 Knoten
4.1.2 Anwendung
4.1.3 Kanal
4.1.4 NetzgerÀt
4.1.5 Topologische Hilfsmittel
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 topologischer Hilfsmittel
4.2.7 Verwendung der Anwendung
4.2.8 Simulator
4.2.9 Aufbau Ihres Szenarios
4.3 ns-3 Quellcode
Kapitel 4
Ăberblick ĂŒber das Konzept
Bevor wir mit dem Lernen oder Schreiben von ns-3 Code beginnen, mĂŒssen wir einige grundlegende Konzepte und Abstraktionen im System erklĂ€ren. Vieles davon mag fĂŒr einige offensichtlich erscheinen, aber wir empfehlen, sich Zeit zu nehmen, um diesen Abschnitt zu lesen und sicherzustellen, dass Sie auf einem soliden Fundament starten.
4.1 SchlĂŒsselabstraktionen
In diesem Abschnitt werden einige Begriffe behandelt, die allgemein im Netzwerk verwendet werden, aber eine spezifische Bedeutung in ns-3 haben.
4.1.1 Knoten
Im Internet-Jargon wird ein ComputergerĂ€t, das mit einem Netzwerk verbunden ist, als Host oder manchmal als Endsystem bezeichnet. Da ns-3 jedoch ein Netzwerksimulator und kein Internetsimulator ist, verwenden wir absichtlich nicht den Begriff Host, da dieser eng mit dem Internet und dessen Protokollen verbunden ist. Stattdessen verwenden wir einen allgemeineren Begriff, der auch von anderen Simulatoren verwendet wird und seinen Ursprung in der Graphentheorie hat â Knoten.node).
In ns-3 wird die grundlegende Abstraktion eines RechenressourcengerÀtes als Knoten bezeichnet. Diese Abstraktion wird in C++ durch die Klasse Node dargestellt. Die Klasse NodeNode (Knoten) bietet Methoden zur Verwaltung der ReprÀsentationen von RechenressourcengerÀten in Simulationen.
Sie sollten verstehen, Knoten wie ein Computer, dem Sie FunktionalitĂ€ten hinzufĂŒgen werden. Sie fĂŒgen Elemente wie Anwendungen, Protokollstacks und Peripheriekarten mit Treibern hinzu, die es dem Computer ermöglichen, nĂŒtzliche Aufgaben zu erfĂŒllen. Wir verwenden dasselbe Grundmodell in ns-3.
4.1.2 Anwendung
In der Regel wird Software in zwei Hauptkategorien unterteilt. Systemsoftware organisiert verschiedene Computerressourcen wie Speicher, CPU-Zyklen, Festplatte, Netzwerk usw. entsprechend einem bestimmten Rechenmodell. Systemsoftware nutzt diese Ressourcen normalerweise nicht zur AusfĂŒhrung von Aufgaben, die dem Benutzer unmittelbaren Nutzen bringen. Um ein bestimmtes Ziel zu erreichen, startet der Benutzer normalerweise eine Anwendung, die die von der Systemsoftware verwalteten Ressourcen abruft und nutzt.
Oft wird die Grenze zwischen Systemsoftware und Anwendungssoftware durch den Wechsel der Berechtigungsstufen gezogen, der bei Betriebssystemaufrufen erfolgt. In nsâ3 gibt es kein echtes Konzept eines Betriebssystems und dementsprechend keine Begriffe fĂŒr Berechtigungsstufen oder Systemaufrufe. Wir haben jedoch die Idee einer Anwendung. Ăhnlich wie in der ârealen Weltâ arbeiten Anwendungsprogramme auf Computern zur AusfĂŒhrung von Aufgaben, arbeiten nsâ3-Anwendungen auf nsâ3-Knoten zur Steuerung von Simulationen in einer simulierten Welt.
In ns-3 ist die grundlegende Abstraktion fĂŒr ein Benutzerprogramm, das aktivitĂ€t zur Simulation erzeugt, die Anwendung. Diese Abstraktion wird in C++ durch die Klasse Application (Anwendung) dargestellt. Die Klasse Application bietet Methoden zur Verwaltung der Darstellungen unserer Version von Anwendungen auf Benutzerebene in Simulationen. Von Entwicklern wird erwartet, dass sie die Klasse Application im Sinne der objektorientierten Programmierung spezialisieren, um neue Anwendungen zu erstellen. In diesem Handbuch verwenden wir die Spezialisierungen der Klasse Application, die genannt werden UdpEchoClientApplication und UdpEchoServerApplication. Wie zu erwarten war, bilden diese Anwendungen eine Reihe von Client/Server-Anwendungen, die zur Erzeugung und Echo-Simulation von Netzwerkpaketen verwendet werden.
4.1.3 Kanal
In der realen Welt können Computer mit einem Netzwerk verbunden werden. Oft werden die Umgebungen, durch die Daten in diesen Netzwerken ĂŒbertragen werden, als KanĂ€le bezeichnet. Wenn Sie ein Ethernet-Kabel an eine 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 Hauptabstraktion des Kommunikationsunternetzes als Kanal bezeichnet und in C++ durch die Klasse Channel dargestellt.
Klasse ChannelChannel bietet Methoden zur Verwaltung der Interaktion von Objekten im Unternetz und zur Verbindung von Knoten damit. KanĂ€le können auch von Entwicklern im Sinne der objektorientierten Programmierung spezialisiert werden. Die Spezialisierung eines Kanals kann etwas Einfaches wie ein Kabel 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 verwenden wir spezialisierte Versionen des Kanals, die den Namen CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel und WifiChannelWifiChannel. CsmaChannel, zum Beispiel modelliert es eine Version eines Kommunikationsnetzwerks, das eine Kommunikationsumgebung mit mehreren Zugriffsberechtigungen und TrÀgersignalsteuerung implementiert. Das bietet uns eine Ethernet-Àhnliche FunktionalitÀt.
4.1.4 NetzgerÀt
FrĂŒher war es so, dass man, um einen Computer mit einem Netzwerk zu verbinden, ein bestimmtes Netzwerkkabel und ein HardwaregerĂ€t kaufen musste, das in der PC-Terminologie als Peripheriekarte bekannt war, die im Computer installiert werden musste. Wenn auf der Peripheriekarte bestimmte Netzwerkfunktionen implementiert waren, wurden sie als Netzwerkinterfacekarten oder Netzwerkkarten bezeichnet. Heute werden die meisten Computer mit integriertem Netzwerkinterface-Equipment ausgeliefert, sodass die Benutzer diese nicht mehr als separate GerĂ€te wahrnehmen.
Eine Netzwerkkarte funktioniert nicht ohne einen Treiber, der ihre Hardware steuert. In Unix (oder Linux) wird ein Teil der PeripheriegerĂ€te als GerĂ€t klassifiziert. GerĂ€te werden ĂŒber GerĂ€tetreiber verwaltet, und NetzwerkgerĂ€te (NICs) werden unter Verwendung von Netzwerktreibern verwaltet (Netzwerktreiber) und werden insgesamt als NetzwerkgerĂ€te bezeichnet (NetzwerkgerĂ€te). In Unix und Linux greifen Sie auf NetzwerkgerĂ€te ĂŒber Namen zu, wie zum Beispiel eth0.
In ns-3 umfasst die Abstraktion des NetzwerkgerĂ€ts sowohl den Softwaretreiber als auch die simulierte Hardware. Bei der Simulation wird das NetzwerkgerĂ€t im Knoten âinstalliertâ, um ihm die Kommunikation mit anderen Knoten ĂŒber KanĂ€le zu ermöglichen. Ăhnlich wie bei einem echten Computer kann der Knoten ĂŒber mehrere GerĂ€te mit mehreren KanĂ€len verbunden sein. NetzwerkgerĂ€te.
Die Netzwerkanalyse des GerĂ€ts wird in C++ durch die Klasse NetDevice. Die Klasse NetDevice stellt Methoden zur Verwaltung von Verbindungen mit den Objekten Node und Channel bereit; und kann von Entwicklern im Sinne der objektorientierten Programmierung spezialisiert werden. In diesem Handbuch verwenden wir mehrere spezialisierte Versionen von NetDevice mit den Bezeichnungen CsmaNetDevice, PointToPointNetDevice und WifiNetDevice. Ebenso wie der Ethernet-Netzwerkadapter fĂŒr den Betrieb mit Netzwerk Ethernet, CsmaNetDevice ausgelegt ist fĂŒr den Betrieb mit CsmaChannel, PointToPointNetDevice ausgelegt ist fĂŒr den Betrieb mit PointToPointChannel, und WifiNetDevice â ausgelegt ist fĂŒr den Betrieb mit WifiChannel.
4.1.5 Topologische Hilfsmittel
In einem realen Netzwerk finden Sie Host-Computer mit hinzugefĂŒgten (oder integrierten) Netzwerkkarten. In ns-3 wĂŒrden wir sagen, dass Sie Knoten mit verbundenen NetDevices sehen werden. In einem groĂen simulierten Netzwerk mĂŒssen Sie Verbindungen zwischen zahlreichen Objekten organisieren. Knoten, NetDevice und Kanal.
Da das AnschlieĂen von NetDevices an Knoten, NetDevices an KanĂ€le, die Zuweisung von IP-Adressen usw. in ns-3 eine hĂ€ufige Aufgabe ist, stellen wir sogenannte topologische Hilfsfunktionen zur VerfĂŒgung, um dies so einfach wie möglich zu machen. Zum Beispiel erfordert die Erstellung eines NetDevice viele Kernoperationen von ns-3: Sie mĂŒssen eine MAC-Adresse hinzufĂŒgen, dieses NetzwerkgerĂ€t einem Node zuweisen, den Protokollstapel des Knotens konfigurieren und dann das NetDevice an den Kanal anschlieĂen. Noch mehr Operationen sind erforderlich, um mehrere GerĂ€te an MehrpunktkanĂ€le anzuschlieĂen und dann einzelne Netzwerke zu einem vereinten Netzwerk (Internetworks) zu verbinden. Wir bieten Hilfsobjekte fĂŒr die Topologie an, die diese zahlreichen Operationen fĂŒr Ihre Benutzerfreundlichkeit in ein einfach zu bedienendes Modell integrieren.
4.2 Erstes ns-3 Skript
Wenn Sie das System wie oben vorgeschlagen installiert haben, finden Sie die ns-3-Version im Verzeichnis namens repos in Ihrem Home-Verzeichnis. Wechseln Sie in das Verzeichnis release
Wenn Sie ein solches Verzeichnis nicht haben, haben Sie beim Erstellen der Release-Version von ns-3 das Ausgabeverzeichnis nicht 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 herstellt und ein Paket zwischen den Knoten ĂŒbertrĂ€gt. Lassen Sie uns dieses Skript Zeile fĂŒr Zeile betrachten, indem wir first.cc in Ihrem bevorzugten Editor öffnen.
4.2.1 Boilerplate-Code
Die erste Zeile in der Datei ist die Mode-Zeile emacs. Sie informiert emacs ĂŒber die Formatierungsbedingungen (Codierungsstil), die wir in unserem Quellcode verwenden werden.
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */Das ist immer eine recht umstrittene Frage, daher sollten wir klarstellen, um sie sofort aus dem Weg zu rĂ€umen. Das nsâ3-Projekt hat, wie die meisten gröĂeren Projekte, einen Kodierungsstil 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-Kodierungsstandard einhalten, wie im Dokument doc/codingstd.txt oder auf der Projektwebsite beschrieben: .
Wir empfehlen Ihnen, sich mit dem Aussehen des nsâ3-Codes vertraut zu machen und diesen Standard anzuwenden, wann immer Sie mit unserem Code arbeiten. Das gesamte Entwicklerteam und die Mitwirkenden haben nach einiger Diskussion zugestimmt. Die oben angegebene Emacs-Moduszeile vereinfacht das korrekte Formatieren, wenn Sie den Emacs-Editor verwenden.
Der nsâ3-Simulator wird unter der GNU General Public Licenselizenziert. Sie finden den entsprechenden rechtlichen GNU-Hinweis in jeder Datei des nsâ3-Distribution. Oft können Sie eine Urheberrechtsmitteilung fĂŒr eine der beteiligten Institutionen im nsâ3-Projekt ĂŒber dem GPL-Text und den unten angegebenen Autoren 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 Code beginnt mit einer Reihe von Include-Direktiven (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 Benutzern von Hochsprachen-Skripten zu helfen, die mit einer Vielzahl von Header-Dateien in der Systemumgebung umgehen mĂŒssen, gruppieren wir diese nach deren Verwendung in umfassende Module. Wir bieten eine einzige Header-Datei an, die alle innerhalb dieses Moduls verwendeten Header-Dateien rekursiv lĂ€dt. Anstatt zu suchen, welche Header-Datei Sie benötigen und möglicherweise die richtige Liste der AbhĂ€ngigkeiten zu erhalten, ermöglichen wir Ihnen das Laden einer Gruppe von Dateien mit einem hohen MaĂ an Detailliertheit. Dies ist zwar nicht der effizienteste Ansatz, macht jedoch das Schreiben von Skripten erheblich einfacher.
Jede der inkludierten nsâ3-Dateien wird in einem Verzeichnis mit dem Namen ns3 abgelegt (unterverzeichnis der Erstellung), 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 der von Ihnen installierten Version finden werden. In der Auflistung dieses Verzeichnisses finden Sie eine Vielzahl von Header-Dateien. Wenn Sie den Build ausfĂŒhren, WAF legt öffentliche Header-Dateien im Verzeichnis ns3 im Unterverzeichnis ab build/debug
Wenn Sie ein solches Verzeichnis nicht haben, haben Sie beim Erstellen der Release-Version von ns-3 das Ausgabeverzeichnis nicht 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, abhĂ€ngig von Ihrer Konfiguration. WAF wird auĂerdem automatisch eine Header-Datei fĂŒr den Zugriff auf alle öffentlichen Header-Dateien generieren. Da Sie selbstverstĂ€ndlich dieser Anleitung strikt folgen, haben Sie bereits
$ ./waf -d debug --enable-examples --enable-tests configureum das Projekt fĂŒr Debug-Bauten mit Beispielen und Tests einzurichten. AuĂerdem haben Sie
$ ./wafum das Projekt zu compilieren. Wenn Sie jetzt das Verzeichnis ../..//build/debug/ns3, durchsuchen, werden Sie unter anderem die Header-Dateien der vier oben genannten Module finden. Sie können den Inhalt dieser Dateien prĂŒ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 Namensraumdeklaration.
using namespace ns3;Das ns-3-Projekt ist im C++-Namensraum ns3 implementiert. Dies gruppiert alle ns-3-bezogenen Deklarationen in einem Sichtbereich auĂerhalb des globalen Namensraums, was hoffentlich die Integration mit anderem Code erleichtert. Die Verwendung des C++-Operators bringt den ns-3-Namensraum in den aktuellen (globalen) Deklarationsbereich. Dies ist eine etwas umstĂ€ndliche Art zu sagen, dass Sie nach dieser Deklaration den ns3::Operator nicht mehr fĂŒr den gesamten ns-3-Code verwenden mĂŒssen. Wenn Sie mit NamensrĂ€umen nicht vertraut sind, werfen Sie einen Blick in fast jedes C++-Lehrbuch und vergleichen Sie den ns3-Namensraum mit der Verwendung des std-Namensraums und Deklarationen. using namespace std; in den Beispielen fĂŒr die Verwendung des Ausgaboperators 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 nutzen, um unser Dokumentationssystem zu besprechen. Doxygen. Wenn Sie die Website des nsâ3-Projekts besuchen, finden Sie einen Link zur "Dokumentation" in der Navigationsleiste. Wenn Sie auf diesen Link klicken, gelangen Sie zu unserer Dokumentationsseite. Dort gibt es einen Link zur "Letzten Version", der Sie zur Dokumentation der neuesten stabilen nsâ3-Version fĂŒhrt. Wenn Sie den Link zur "API Dokumentation" auswĂ€hlen, gelangen Sie zur nsâ3 API-Dokumentationsseite.
Auf der linken Seite der Seite finden Sie eine grafische Darstellung der Dokumentationsstruktur. Ein guter Ausgangspunkt ist das "Buch" Module nsâ3 im nsâ3 Navigationsbaum. Wenn Sie diesen Abschnitt aufklappen, Module, sehen Sie eine Liste der nsâ3 Modul-Dokumentationen. Wie bereits erwĂ€hnt, steht das Konzept des Moduls hier in direktem Zusammenhang mit den im Modul enthaltenen Dateien. Das nsâ3 Logging-System wird im Abschnitt "Verwendung des Logging-Moduls"diskutiert, daher werden wir spĂ€ter in diesem Handbuch darauf zurĂŒckkommen. Sie können jedoch durch den oben genannten Abschnitt lernen, indem Sie das Modul KernwĂ€hlen und dann das Buch Debugging-Toolsöffnen und die Seite auswĂ€hlen, Logging. Klicken Sie auf Logging.
Nun sollten Sie die Dokumentation Doxygen fĂŒr das Modul Logging. In der Makrosliste oben auf der Seite finden Sie den Eintrag fĂŒr NS_LOG_COMPONENT_DEFINE. Bevor Sie dem Link folgen, sollten Sie auf jeden Fall die âDetaillierte Beschreibungâ des Protokollmoduls ansehen, um seine Funktionsweise im Allgemeinen 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 vor sich geht, fahren Sie fort und schauen Sie sich die Dokumentation zu den spezifischen NS_LOG_COMPONENT_DEFINE an. Ich werde die Dokumentation hier nicht wiederholen, aber zusammenfassend gesagt, erklĂ€rt diese Zeile einen Protokollkomponenten mit dem Namen FirstScriptExample, der es erlaubt, die Konsolenprotokollierung von Nachrichten ĂŒber den Namen zu aktivieren und zu deaktivieren.
4.2.5 Hauptfunktion
In den folgenden Zeilen des Skripts sehen Sie,
int
main (int argc, char *argv[])
{ Das ist einfach die Deklaration der Hauptfunktion Ihres Programms (Skripts). Wie in jedem C++-Programm mĂŒssen Sie die Hauptfunktion definieren, die zuerst ausgefĂŒhrt wird. Hier gibt es nichts Besonderes. Ihr ns-3-Skript ist einfach ein C++-Programm. Die nĂ€chste 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 genutzt werden kann (die kleinste darstellbare Differenz zwischen zwei Zeitwerten). Sie können die Auflösung genau einmal Àndern. Der Mechanismus, der diese FlexibilitÀt gewÀhrleistet, benötigt Speicher, daher geben wir den Speicher frei, sobald die Auflösung explizit festgelegt wird, um weitere Aktualisierungen zu verhindern. (Wenn Sie die Auflösung nicht explizit festlegen, betrÀgt der Standardwert eine Nanosekunde, und der Speicher wird zu Beginn der Simulation freigegeben.)
Die folgenden zwei Zeilen des Skripts werden verwendet, um zwei Komponenten der Protokollierung zu aktivieren, die in die Anwendungen integriert sind. EchoClient und EchoServer:
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);Wenn Sie die Dokumentation zum Logging-Komponenten gelesen haben, werden Sie feststellen, dass es mehrere Detailstufen gibt, die Sie fĂŒr jede Komponente aktivieren können. Diese beiden Codezeilen aktivieren das Debug-Logging auf der INFO-Ebene fĂŒr Echo-Clients und Server. Auf dieser Ebene druckt die Anwendung wĂ€hrend der Simulation Nachrichten beim Senden und Empfangen von Paketen aus.
Jetzt kommen wir direkt zur Erstellung der Topologie und zur AusfĂŒhrung der Simulation. Wir werden topologische Hilfsobjekte verwenden, um diese Aufgabe so einfach wie möglich zu gestalten.
4.2.6 Verwendung topologischer Hilfsmittel
Die nÀchsten beiden Zeilen in unserem Skript erstellen tatsÀchlich ns-3 Node-Objekte, die Computer in der Simulation darstellen.
NodeContainer nodes;
nodes.Create(2);Bevor wir fortfahren, lassen Sie uns die Dokumentation fĂŒr die Klasse NodeContainerfinden. Eine andere Möglichkeit, zur Dokumentation dieser Klasse zu gelangen, ist ĂŒber den Reiter Classes auf den Seiten. Doxygen. Wenn Sie Doxygen bereits geöffnet haben, scrollen Sie einfach nach oben zur oberen Seite und wĂ€hlen Sie die Registerkarte Klassen. Sie sollten eine neue Reihe von Registerkarten sehen, wovon eine die Klassenliste ist. Unter dieser Registerkarte sehen Sie eine Liste aller nsâ3-Klassen. Scrollen Sie nach unten, bis ns3 :: NodeContainer. Wenn Sie die Klasse gefunden haben, wĂ€hlen Sie sie aus, um zur Dokumentation fĂŒr diese Klasse zu gelangen.
Wie wir uns erinnern, ist eine unserer wichtigsten Abstraktionen der Knoten. Er stellt den Computer dar, zu dem wir Dinge wie Protokollstacks, Anwendungen und Peripheriekarten hinzufĂŒgen möchten. Der topologische Assistent NodeContainer bietet eine benutzerfreundliche Möglichkeit, alle Objekte zu erstellen, zu verwalten und darauf zuzugreifen, Knoten, die wir zur AusfĂŒhrung der Simulation erstellen. Die erste Zeile oben deklariert NodeContainer, die wir nodes nennen. Die zweite Zeile ruft die Methode Create fĂŒr das Objekt nodes auf und bittet den Container, zwei Knoten zu erstellen. Wie beschrieben in Doxygen, fordert der Container das System nsâ3 auf, zwei Objekte zu erstellen, Knoten und speichert die Zeiger auf diese Objekte intern.
Die im Skript erstellten Knoten tun zunĂ€chst nichts. Der nĂ€chste Schritt beim Aufbau der Topologie besteht darin, unsere Knoten mit dem Netzwerk zu verbinden. Die einfachste Form des Netzwerks, die wir unterstĂŒtzen, ist eine Punkt-zu-Punkt-Verbindung zwischen zwei Knoten. Wir werden jetzt eine solche Verbindung erstellen.
PointToPointHelper
Wir erstellen die Punkt-zu-Punkt-Verbindung, indem wir einem uns vertrauten Muster folgen und ein topologisches Hilfsobjekt verwenden, um die erforderliche Low-Level-Arbeit fĂŒr die Verbindung zu erledigen. Denken wir daran, dass unsere beiden SchlĂŒsselabstraktionen NetDevice und Kanal. In der realen Welt entsprechen diese Begriffe in etwa Peripheriekarten und Netzwerkkabeln. Diese beiden Dinge sind in der Regel eng miteinander verbunden, und niemand kann erwarten, dass beispielsweise GerĂ€te Ethernet ĂŒber eine drahtlose Verbindung kommunizieren. Unsere topologischen Hilfsobjekte folgen dieser engen Verbindung, und deshalb werden Sie in diesem Szenario ein Objekt verwenden PointToPointHelper zum Konfigurieren und Verbinden von ns-3 Objekten PointToPointNetDevice und PointToPointChannel. Die nĂ€chsten drei Zeilen im Skript:
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));Die erste Zeile,
PointToPointHelper pointToPoint;erstellt im Stack eine Instanz des Objekts PointToPointHelper. Auf der obersten Ebene sieht die folgende Zeile aus,
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));sagt dem Objekt PointToPointHelper den Wert â5 Mbit/sâ (fĂŒnf Megabit pro Sekunde) als âDataRate».
Aus spezifischerer Sicht entspricht die Zeile âDataRateâ dem, was wir als Attribut bezeichnen PointToPointNetDevice. Wenn Sie sich Doxygen fĂŒr die Klasse ns3::PointToPointNetDevice und in der Dokumentation zur Methode GetTypeId werden Sie eine Liste der Attribute finden, die fĂŒr das GerĂ€t definiert sind. Unter diesen wird ein Attribut âDataRateâ sein. Die meisten fĂŒr den Benutzer sichtbaren ns-3 Objekte haben Ă€hnliche Attributlisten. Wir verwenden diesen Mechanismus fĂŒr eine einfache Anpassung der Simulation ohne erneute Kompilierung, wie Sie im folgenden Abschnitt sehen werden.
Ăhnlich wie âDataRateâ im PointToPointNetDevice finden Sie das Attribut âDelayâ, das mit dem 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 Verbreitungsverzögerung ĂŒber den Punkt-zu-Punkt-Kanal, den er anschlieĂend erstellt.
NetDeviceContainer
Bis jetzt haben wir in unserem Szenario NodeContainer, das zwei Knoten enthĂ€lt. Wir haben PointToPointHelper, das bereit ist, Objekte zu erstellen PointToPointNetDevices und deren Verbindung ĂŒber das Objekt PointToPointChannel. So wie wir den Hilfsobjekt NodeContainer zur Erstellung der Knoten verwendet haben, werden wir PointToPointHelper fĂŒr uns die Arbeiten zur Erstellung, Konfiguration und Installation unserer GerĂ€te durchfĂŒhren lassen. Wir benötigen eine Ăbersicht aller erstellten Objekte, NetDevice, weshalb wir NetDeviceContainer zum Speichern nutzen, ebenso wie wir NodeContainer zum Speichern unserer erstellten Knoten verwendet haben. Die folgenden zwei Codezeilen,
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);vollenden die Einrichtung der GerĂ€te und des Kanals. Die erste Zeile deklariert den bereits erwĂ€hnten GerĂ€tekontainer, wĂ€hrend die zweite die Hauptarbeit verrichtet. Die Methode Installation des Objekts PointToPointHelper nimmt NodeContainer als Parameter. Innerhalb von NetDeviceContainer wird fĂŒr jeden Knoten, der sich in NodeContainer befindet (fĂŒr die Punkt-zu-Punkt-Verbindung mĂŒssen es genau zwei sein), PointToPointNetDevice erstellt und im GerĂ€tekontainer gespeichert. PointToPointChannel wird erstellt, und es werden zwei PointToPointNetDevices. Nach der Erstellung der Objekte werden die in PointToPointHelpergespeicherten Attribute verwendet, um die entsprechenden Attribute in den erstellten Objekten zu initialisieren.
Nach dem Aufruf von pointToPoint.Install (nodes) Wir werden zwei Knoten haben, 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 und einer Ăbertragungsverzögerung von zwei Millisekunden ĂŒ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 Internet-Stacks dar, Ă€hnlich wie PointToPointHelper fĂŒr Punkt-zu-Punkt-NetzwerkgerĂ€te. Die Methode Installation nimmt NodeContainer als Parameter. Bei der AusfĂŒhrung wird der Internet-Stack (TCP, UDP, IP usw.) auf jedem Knoten im Container installiert.
Ipv4AddressHelper
Dann mĂŒssen wir unsere GerĂ€te mit IP-Adressen verknĂŒpfen. Wir bieten einen Topologie-Helfer zur Verwaltung der Verteilung von IP-Adressen an. Die einzige fĂŒr den Benutzer sichtbare API ist die Festlegung der Basis-IP-Adresse und der Subnetzmaske, die bei der tatsĂ€chlichen Verteilung der Adressen verwendet wird (dies geschieht auf einer niedrigeren Ebene innerhalb des Helfers). Die folgenden zwei Codezeilen in unserem Skriptbeispiel: first.cc,
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");deklarieren ein Hilfsobjekt fĂŒr Adressen und geben an, dass es mit der Zuweisung von IP-Adressen aus dem Netzwerk 10.1.1.0 beginnen soll, wobei die Bitmaske 255.255.255.0 verwendet wird. StandardmĂ€Ăig beginnen die zugewiesenen Adressen bei eins und erhöhen sich monoton, sodass die erste von dieser Basis zugewiesene Adresse 10.1.1.1 sein wird, gefolgt von 10.1.1.2 usw. In der RealitĂ€t speichert das System ns-3 auf niedriger Ebene alle zugewiesenen IP-Adressen und generiert einen schwerwiegenden Fehler, wenn Sie versehentlich eine Situation geschaffen haben, in der dieselbe Adresse zweimal generiert wird (ĂŒbrigens ist dieser Fehler schwer zu debuggen).
Die nÀchste Codezeile:
Ipv4InterfaceContainer interfaces = address.Assign (devices);fĂŒhrt die tatsĂ€chliche Adresszuweisung aus. In nsâ3 stellen wir die Verbindung zwischen der IP-Adresse und dem GerĂ€t ĂŒber das Objekt Ipv4Interfaceher. Genau wie wir manchmal eine Liste der NetzgerĂ€te benötigen, die vom Assistenten fĂŒr die spĂ€tere Verwendung erstellt wurden, benötigen wir manchmal eine Liste der Objekte Ipv4Interface. Ipv4InterfaceContainer die diese FunktionalitĂ€t bereitstellt.
Wir haben ein Punkt-zu-Punkt-Netzwerk mit installierten Stacks und zugewiesenen IP-Adressen aufgebaut. Jetzt benötigen wir in jedem Knoten Anwendungen, um Traffic zu generieren.
4.2.7 Verwendung der Anwendung
Eine weitere der grundlegenden Abstraktionen im System nsâ3 ist Application (Anwendung). In diesem Szenario verwenden wir zwei Spezialisierungen der Basisklasse Application nsâ3, die genannt werden UdpEchoServerApplication und UdpEchoClientApplication. Wie in den vorherigen FĂ€llen verwenden wir Hilfsobjekte zur Konfiguration und Verwaltung der Basiskomponenten. Hier verwenden wir UdpEchoServerHelper und UdpEchoClientHelperObjekte, um unser Leben zu erleichtern.
UdpEchoServerHelper
Die folgenden Codezeilen in unserem Beispielskript first.cc werden verwendet, um die UDP-Echo-Serveranwendung auf einem der Knoten, die wir zuvor erstellt haben, einzurichten.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));Die erste Codezeile im obigen Fragment erstellt UdpEchoServerHelper. Wie ĂŒblich handelt es sich nicht um eine eigenstĂ€ndige Anwendung, sondern um ein Objekt, das uns hilft, reale Anwendungen zu entwickeln. Eine unserer Vereinbarungen besteht darin, die erforderlichen Attribute an den Konstruktor des Hilfsobjekts zu ĂŒbermitteln. In diesem Fall kann der Hilfsobjekt nichts NĂŒtzliches tun, wenn ihm keine Portnummer zur VerfĂŒgung gestellt wird, an dem der Server auf Pakete warten wird; diese Nummer muss auch dem Client bekannt sein. Daher ĂŒbergeben wir die Portnummer an den Konstruktor des Hilfsobjekts. Der Konstruktor selbst fĂŒhrt einfach SetAttribute mit dem ĂŒbergebenen Wert aus. SpĂ€ter können Sie, falls gewĂŒnscht, mit SetAttribute einen anderen Wert fĂŒr das Attribut "Port" festlegen.
Wie viele andere Hilfsobjekte hat auch das Objekt UdpEchoServerHelper eine Methode Installation. Die AusfĂŒhrung dieser Methode fĂŒhrt tatsĂ€chlich dazu, dass eine grundlegende Echo-Server-Anwendung erstellt und an einen Knoten gebunden wird. Interessanterweise hat die Methode Installation nimmt NodeContainer als Parameter genauso wie andere Installation Methoden, die wir gesehen haben.
Die implizite Umwandlung in C++, die hier funktioniert, nimmt das Ergebnis der Methode node.Get (1) (der einen smarten Zeiger auf das Knotenobjekt zurĂŒckgibt â Ptr) und verwendet ihn im Konstruktor fĂŒr das anonyme Objekt NodeContainer, das dann an die Methode ĂŒbergeben wird Installation. Wenn Sie im C++-Code nicht feststellen können, welche Signatur eine Methode kompiliert und ausgefĂŒhrt wird, suchen Sie nach impliziten Umwandlungen.
Jetzt sehen wir, dass echoServer.Install die Anwendung installieren wird UdpEchoServerApplication auf dem gefundenen in NodeContainer, den wir verwenden, um unsere Knoten zu steuern, Knoten mit dem Index 1. Die Methode Installation 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) erstellt von dem Helfer.
Die Anwendungen mĂŒssen den Zeitpunkt des Startens der Traffic-Generierung angeben "start" und möglicherweise zusĂ€tzlich die Zeit angeben, wann diese gestoppt werden soll "stop". Wir stellen beide Parameter zur VerfĂŒgung. Diese Zeiten werden mit den Methoden ApplicationContainer Start und Stop. Diese Methoden akzeptieren Parameter vom Typ Zeit. In diesem Fall verwenden wir eine explizite Sequenz von C++-Umwandlungen, um C++ double 1,0 und es in ein tnsâ3-Zeitobjekt umwandeln, das das Objekt Seconds zur Umrechnung in Sekunden verwendet. Beachten Sie, dass die Umwandlungsregeln vom Modellautor steuert werden können und C++ seine eigenen Regeln hat, daher können Sie nicht immer darauf zĂ€hlen, dass die Parameter wie erwartet umgewandelt werden. Zwei Zeichenfolgen,
serverApps.Start (Seconds (1,0));
serverApps.Stop (Seconds (10,0));fĂŒhren dazu, dass die Echo-Serveranwendung nach einer Sekunde nach Beginn der Simulation automatisch gestartet wird und nach zehn Sekunden der Simulation gestoppt wird. Da wir ein Simulationsereignis (das Ereignis zum Stoppen der Anwendung) deklariert haben, das in zehn Sekunden ausgefĂŒhrt werden soll, wird die Netzwerkarbeit fĂŒr mindestens zehn Sekunden simuliert.
UdpEchoClientHelper
Client-Anwendung echo wird auf eine Weise konfiguriert, die praktisch der des Servers entspricht. Es gibt ein Basiselement UdpEchoClientApplication, das verwaltet wird 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 wir jedoch fĂŒnf verschiedene Attribute festlegen. Die ersten beiden Attribute werden wĂ€hrend der Erstellung gesetzt. UdpEchoClientHelperWir ĂŒbergeben die Parameter, die (innerhalb des Assistenzsystems) zur Festlegung der Attribute verwendet werden. âRemoteAddressâ und âRemotePortâ entsprechend unserer Vereinbarung zur Ăbertragung der erforderlichen Parameter an den Assistenten-Konstruktor.
Erinnern wir uns daran, dass wir Ipv4InterfaceContainer verwendet haben, um die IP-Adressen zu verfolgen, die unseren GerÀten zugewiesen wurden. Das Null-Interface im Interface-Container entspricht der IP-Adresse des Null-Knotens im Knoten-Container. Das erste Interface im Interface-Container entspricht der IP-Adresse des ersten Knotens im Knoten-Container. Also, in der ersten Zeile des Codes (oben) erstellen wir den Assistenten und teilen ihm mit, dass die Remote-Adresse des Clients die IP-Adresse ist, die dem Knoten zugewiesen wurde, auf dem der Server lÀuft. Wir geben auch an, dass die Pakete an den neunten Port gesendet werden sollen.
Das Attribut âMaxPacketsâ informiert den Kunden ĂŒber die maximale Anzahl an Paketen, die wir wĂ€hrend der Simulation senden können. Das Attribut âIntervalâ gibt an, wie lange zwischen den Paketen gewartet werden soll, und das Attribut âPacketSizeâ gibt an, wie groĂ die Nutzlast des Pakets sein muss. Mit dieser Kombination von Attributen sagen wir dem Kunden, dass er ein 1024-Byte-Paket senden soll.
Wie beim Echo-Server setzen wir die Attribute fĂŒr den Echo-Client. 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
An dieser Stelle mĂŒssen wir die Simulation starten. Dies geschieht mithilfe der globalen Funktion Simulator::Run.
Simulator::Run ();Als wir zuvor 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, das System beginnt, die Liste der geplanten Ereignisse zu durchlaufen und sie auszufĂŒhren. Zuerst wird es ein Ereignis nach 1,0 Sekunden auslösen, was die Echo-Server-Anwendung aktiviert (dieses Ereignis kann wiederum viele andere Ereignisse planen). Dann wird es das fĂŒr t = 2,0 Sekunden geplante Ereignis initiieren, das die Echo-Client-Anwendung startet. Auch dieses Ereignis kann viele weitere Ereignisse planen. Die Implementierung des Startereignisses im Echo-Client wird die Phase der Datensimulation 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 automatisch im Hintergrund geplant werden und die Mechanik des Sendens von Echo-Signalen gemÀà den Synchronisationsparametern implementieren, die wir im Skript festgelegt haben.
Letztendlich, da wir nur ein Paket senden (denken wir daran, dass das Attribut MaxPackets auf eins gesetzt war), wird die durch diese einzige Client-Echo-Anfrage eingeleitete Ereigniskette enden und die Simulation in den Wartemodus ĂŒbergehen. Sobald dies geschieht, werden die verbleibenden geplanten Ereignisse die Ereignisse sein Stop fĂŒr den Server und den Client. Sobald diese Ereignisse eintreten, werden keine weiteren Ereignisse zur Verarbeitung mehr vorhanden sein und Simulator::Run ĂŒber die Kontrolle zurĂŒckgegeben. Die Modellierung ist abgeschlossen.
Nun bleibt nur noch, aufzurĂ€umen. Dies erfolgt durch den Aufruf einer globalen Funktion Simulator::Destroy. Da Hilfsfunktionen (oder niedrigstufiger ns-3-Code) aufgerufen wurden, die so organisiert sind, dass im Simulator Hooks zum Zerstören aller erstellten Objekte eingefĂŒgt werden, mĂŒssen Sie keine dieser Objekte selbst verfolgen â alles, was Sie tun mussten, war Simulator::Destroy und das Programm zu beenden. Das ns-3-System erledigt diese mĂŒhsame Arbeit fĂŒr Sie. Die verbleibenden Zeilen unseres ersten ns-3-Skripts, first.cc, tun genau dies:
Simulator::Destroy ();
rĂŒckgabe 0;
}Wann wird der Simulator gestoppt?
ns-3 ist ein Simulationsprogramm fĂŒr diskrete Ereignisse (DE). In einem solchen Simulator ist jedes Ereignis mit der Zeit seiner AusfĂŒhrung verbunden, und die Simulation wird fortgesetzt, indem die Ereignisse in der Reihenfolge ihres Auftretens wĂ€hrend der Simulation verarbeitet werden. Ereignisse können zukĂŒnftige Ereignisse planen (z. B. kann ein Timer sich selbst umplanen, um den nĂ€chsten Intervall abzuschlieĂen).
Ereignisse werden typischerweise durch ein Objekt initiiert, wie zum Beispiel IPv6, das die Erkennung von Diensten im Netzwerk, Nachbquire-Anfragen usw. plant. Die Anwendung plant das erste Paketversandereignis usw. Wenn ein Ereignis bearbeitet wird, kann es null, ein oder mehrere Ereignisse generieren. Im Verlauf der Simulation treten Ereignisse auf, die einfach enden oder neue erzeugen. Die Simulation stoppt automatisch, wenn die Ereigniswarteschlange leer ist oder ein spezielles Ereignis erkannt wird. StopEreignis Stop wird durch die Funktion Simulator::Stop (Zeit stoppen).
Ein typischer Fall, in dem Simulator::Stop unbedingt erforderlich ist, um die Simulation zu stoppen, ist, wenn selbstunterhaltende Ereignisse vorliegen. Selbstunterhaltende (oder wiederkehrende) Ereignisse sind solche, die immer neu geplant werden. Infolgedessen halten sie die Ereigniswarteschlange immer nicht leer. Es gibt viele Protokolle und Module, die wiederkehrende Ereignisse enthalten, zum Beispiel:
âą FlowMonitor â periodische ĂberprĂŒfung auf verlorene Pakete;
âą RIPng â periodische Ăbertragung von Routing-Tabellenaktualisierungen;
âą usw.
In solchen FĂ€llen Simulator::Stop ist notwendig, um die Simulation korrekt zu stoppen. DarĂŒber hinaus wird, wenn nsâ3 im Emulationsmodus ist, der RealtimeSimulator verwendet, um die Simulationsuhren mit den Maschinenuhren zu synchronisieren, und Simulator::Stop ist erforderlich, um den Prozess zu beenden.
Viele der Simulationsprogramme im Lehrbuch rufen nicht Simulator::Stop explizit auf, da sie automatisch mit dem Erschöpfen der Ereignisse in der Warteschlange enden. Diese Programme werden jedoch auch den Aufruf von Simulator::Stop annehmen. Zum Beispiel plant der folgende zusÀtzliche Befehl im ersten Programmmuster eine explizite Beendigung nach 11 Sekunden:
+ Simulator::Stop (Seconds (11.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}Die obige Anweisung Ă€ndert das Verhalten dieses Programms nicht, da diese spezifische Simulation natĂŒrlich nach 10 Sekunden endet. Wenn Sie jedoch die Zeit fĂŒr das Stoppen in der obigen Anweisung von 11 Sekunden auf 1 Sekunde geĂ€ndert haben, wĂŒrden Sie bemerken, dass die Simulation stoppt, bevor irgendeine Ausgabe auf dem Bildschirm erscheint (da die Ausgabe etwa 2 Sekunden Simulationszeit benötigt).
Es ist wichtig, Simulator::Stop vor Simulator::Run aufzurufen; andernfalls kann Simulator::Run die Kontrolle ĂŒber das Hauptprogramm zur DurchfĂŒhrung der Stoppfunktion möglicherweise nie zurĂŒckgeben!
4.2.9 Aufbau Ihres Szenarios
Wir haben die Erstellung Ihrer einfachen Skripte ganz einfach gemacht. Alles, was Sie tun mĂŒssen, ist, Ihr Skript in das Verzeichnis scratch zu legen, und es wird automatisch erstellt, wenn Sie ausfĂŒhren WAF. Lassen Sie es uns versuchen. Kehren Sie in das ĂŒbergeordnete Verzeichnis zurĂŒck und kopieren Sie examples/tutorial/first.cc in das Verzeichnis scratch
$ cd ../..
$ cp examples/tutorial/first.cc scratch/myfirst.ccJetzt kompilieren Sie Ihr erstes Beispielszenario mit waf:
$ ./wafSie sollten Nachrichten sehen, dass Ihr erstes Beispiel erfolgreich erstellt wurde.
Waf: Betritt 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: VerlieĂt Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' wurde erfolgreich abgeschlossen (2,357s)Jetzt können Sie das Beispiel ausfĂŒhren (beachten Sie, dass Sie, wenn Sie Ihr Programm im Verzeichnis scratch kompilieren, es auch aus dem Verzeichnis starten mĂŒssen) scratch):
$ ./waf --run scratch/myfirstSie sollten eine Àhnliche Ausgabe sehen:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' betreten
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' verlassen
'build' erfolgreich beendet (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 ĂŒberprĂŒft, ob die Datei kompiliert wurde, und sie dann ausfĂŒhrt. Sie sehen den Eintrag des Clients im Echo-Center, der anzeigt, dass er ein 1024-Byte-Paket an den Echo-Server 10.1.1.2 gesendet hat. Sie sehen auch den Protokolleintrag auf dem Echo-Server, der angibt, dass er 1024 Bytes von 10.1.1.1 empfangen hat. Der Echo-Server sendet das Paket stillschweigend zurĂŒck, und Sie sehen im Protokoll des Echo-Clients, dass er sein Paket vom Server zurĂŒckerhalten hat.
4.3 ns-3 Quellcode
Jetzt, da Sie einige der Helfer von nsâ3 verwendet haben, können Sie einen Blick auf den Quellcode werfen, der diese FunktionalitĂ€t implementiert. Der aktuellste Code kann auf unserem Webserver unter folgendem Link eingesehen werden: . Dort sehen Sie eine Zusammenfassungsseite von Mercurial fĂŒr unser Entwicklungsbaum von nsâ3. Am oberen Rand der Seite finden Sie einige Links,
Zusammenfassung | Kurzprotokoll | Ănderungsprotokoll | Graph | Tags | DateienGehen Sie weiter und wĂ€hlen Sie den Link zu den Dateien. So sieht die oberste Ebene der meisten unserer Repositories aus:
drwxr-xr-x [up]
drwxr-xr-x bindings python dateien
drwxr-xr-x doc dateien
drwxr-xr-x examples dateien
drwxr-xr-x ns3 dateien
drwxr-xr-x scratch dateien
drwxr-xr-x src dateien
drwxr-xr-x utils dateien
-rw-r--r-- 2009-07-01 12:47 +0200 560 .hgignore datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 1886 .hgtags datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 1276 AUTHORS datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 17987 LICENSE datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 3742 README datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 6 VERSION datei | revisionen | annotieren
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 waf datei | revisionen | annotieren
-rwxr-xr-x 2009-07-01 12:47 +0200 28 waf.bat datei | revisionen | annotieren
-rw-r--r-- 2009-07-01 12:47 +0200 35395 wscript datei | revisionen | annotierenUnsere 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 darauf klicken, first.cc sehen Sie den Code, den Sie gerade gelernt 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 von Unterverzeichnissen des src. Wenn Sie dann auf das Unterverzeichnis core klicken, finden Sie eine Liste von Dateien. Die erste Datei, die Sie sehen werden (zum Zeitpunkt der Erstellung dieses Handbuchs) â abort.h. Wenn Sie auf den Link klicken abort.h, werden Sie zur Quelldatei fĂŒr abort.h, die nĂŒtzliche Makros enthĂ€lt, um aus Skripten auszutreten, wenn abnormalen Bedingungen erkannt werden. Der Quellcode fĂŒr die Hilfsdienste, die wir in diesem Kapitel verwendet haben, befindet sich im Verzeichnis src/Applications/helper. Zögern Sie nicht, im Verzeichnisbaum zu stöbern, um zu verstehen, wo was ist, und sich im Programmstil von ns-3 zurechtzufinden.
Quelle: habr.com
