Dies ist der Befehl ns-3-tutorial, der im kostenlosen OnWorks-Hosting-Provider mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, Windows-Online-Emulator oder MAC OS-Online-Emulator ausgeführt werden kann
PROGRAMM:
NAME/FUNKTION
ns-3-Tutorial - ns-3-Tutorial
Dies ist die NS-3 Einführung. Die Primärdokumentation für das ns-3-Projekt ist in fünf Formaten verfügbar
Formen:
· NS-3 Doxygen: Dokumentation der öffentlichen APIs des Simulators
· Lernprogramm (diese dokumentieren), Handbuch und Modellbibliothek für die neueste Release und
Entwicklung Baum
· NS-3 Wiki
Dieses Dokument ist geschrieben in reStructuredText für Sphinx und wird in der
Dokument/Tutorial Verzeichnis des Quellcodes von ns-3.
EINFÜHRUNG
Die NS-3 simulator ist ein ereignisdiskreter Netzwerksimulator, der hauptsächlich für die Forschung bestimmt ist
und pädagogische Nutzung. Die NS-3 Projekt, gestartet im Jahr 2006, ist ein Open-Source-Projekt
Entwicklung NS-3.
Der Zweck dieses Tutorials ist es, neue NS-3 Benutzer an das System in einer strukturierten
Weg. Für neue Benutzer ist es manchmal schwierig, wichtige Informationen aus detaillierten
Handbücher und diese Informationen in Arbeitssimulationen umzuwandeln. In diesem Tutorial haben wir
wird mehrere Beispielsimulationen erstellen, Schlüsselkonzepte einführen und erklären und
Funktionen wie wir gehen.
Im Laufe des Tutorials werden wir das vollständige vorstellen NS-3 dokumentieren und bereitstellen
Hinweise zum Quellcode für diejenigen, die tiefer in die Funktionsweise des
System funktionieren.
Ein paar wichtige Punkte sind zu Beginn erwähnenswert:
· NS-3 ist Open Source, und das Projekt strebt danach, eine offene Umgebung für
Forscher, ihre Software beizutragen und zu teilen.
· NS-3 ist keine abwärtskompatible Erweiterung von NS-2; Es ist ein neuer Simulator. Die Zwei
Simulatoren sind beide in C++ geschrieben, aber NS-3 ist ein neuer Simulator, der die
NS-2 APIs. Einige Modelle von NS-2 wurden bereits portiert von NS-2 zu NS-3dem „Vermischten Geschmack“. Seine
Projekt wird weitergeführt NS-2 während NS-3 wird gebaut und studiert
Übergangs- und Integrationsmechanismen.
Über uns NS-3
NS-3 wurde entwickelt, um eine offene, erweiterbare Netzwerksimulationsplattform bereitzustellen, z
Forschung und Lehre vernetzen. In Kürze, NS-3 bietet Modelle, wie Paketdaten
Netzwerke funktionieren und funktionieren und bietet eine Simulations-Engine, die Benutzer durchführen können
Simulationsexperimente. Einige der Gründe für die Verwendung NS-3 einschließen, Studien durchzuführen, die
sind mit realen Systemen schwieriger oder nicht durchführbar, um das Systemverhalten zu untersuchen
in einer stark kontrollierten, reproduzierbaren Umgebung und lernen, wie Netzwerke funktionieren.
Benutzer werden feststellen, dass das verfügbare Modell in NS-3 konzentriert sich auf die Modellierung, wie Internet
Protokolle und Netzwerke funktionieren, aber NS-3 ist nicht auf Internet-Systeme beschränkt; mehrere Benutzer
benutzen NS-3 um nicht internetbasierte Systeme zu modellieren.
Es gibt viele Simulationswerkzeuge für Netzwerksimulationsstudien. Unten sind ein paar
Unterscheidungsmerkmale von NS-3 im Gegensatz zu anderen Tools.
· NS-3 ist als eine Reihe von Bibliotheken konzipiert, die miteinander und auch mit anderen kombiniert werden können
externe Softwarebibliotheken. Während einige Simulationsplattformen Benutzern eine
eine einzige, integrierte grafische Benutzeroberflächenumgebung, in der alle Aufgaben ausgeführt werden
out, NS-3 ist in dieser Hinsicht modularer. Mehrere externe Animatoren und Datenanalyse
und Visualisierungstools können verwendet werden mit NS-3. Benutzer sollten jedoch damit rechnen, bei . zu arbeiten
über die Befehlszeile und mit C++- und/oder Python-Softwareentwicklungstools.
· NS-3 wird hauptsächlich auf Linux-Systemen verwendet, obwohl es Unterstützung für FreeBSD, Cygwin . gibt
(für Windows) und die native Windows Visual Studio-Unterstützung ist in Vorbereitung
entwickelt.
· NS-3 ist kein offiziell unterstütztes Softwareprodukt eines Unternehmens. Unterstützung für NS-3
erfolgt auf Best-Effort-Basis auf der ns-3-users-Mailingliste.
Für NS-2 Nutzer
Für diejenigen, die mit vertraut sind NS-2 (ein beliebtes Werkzeug, das vor NS-3), am sichtbarsten nach außen
ändern beim Umzug nach NS-3 ist die Wahl der Skriptsprache. Programme in NS-2 sind
in OTcl gescriptet und Simulationsergebnisse können mit dem Network Animator visualisiert werden
nam. Es ist nicht möglich, eine Simulation in NS-2 rein aus C++ (dh als main()
Programm ohne OTcl). Darüber hinaus sind einige Komponenten von NS-2 sind in C++ geschrieben und
andere in OTkl. In NS-3, der Simulator ist komplett in C++ geschrieben, mit optionalem Python
Bindungen. Simulationsskripte können daher in C++ oder in Python geschrieben werden. Neue Animatoren
und Visualizer sind verfügbar und befinden sich in der Entwicklung. Schon seit NS-3 erzeugt pcap
Paket-Trace-Dateien können auch andere Dienstprogramme zum Analysieren von Traces verwendet werden. In diesem
Tutorial konzentrieren wir uns zunächst auf die direkte Skripterstellung in C++ und die Interpretation der Ergebnisse
über Trace-Dateien.
Aber es gibt auch Ähnlichkeiten (beide basieren zum Beispiel auf C++-Objekten und einige
Code von NS-2 wurde bereits portiert auf NS-3). Wir werden versuchen, Unterschiede hervorzuheben
zwischen NS-2 und NS-3 wie wir in diesem Tutorial fortfahren.
Eine Frage, die wir oft hören, ist "Soll ich noch verwenden? NS-2 oder gehe zu NS-3?" In diesem
Meinung des Autors, es sei denn, der Benutzer ist in irgendeiner Weise daran beteiligt NS-2 (entweder basierend auf bestehenden
persönlicher Komfort mit und Wissen über NS-2, oder basierend auf einem spezifischen Simulationsmodell, das
ist nur in verfügbar NS-2), ist ein Benutzer produktiver mit NS-3 für den folgenden
Gründe dafür:
· NS-3 wird mit einer aktiven, reaktionsschnellen Benutzer-Mailingliste aktiv gepflegt, während NS-2 is
nur leicht gepflegt und hat keine wesentliche Entwicklung in seinem Hauptcodebaum erlebt
seit über einem Jahrzehnt.
· NS-3 bietet Funktionen, die in nicht verfügbar sind NS-2, wie z. B. die Ausführung eines Implementierungscodes
Umgebung (ermöglicht es Benutzern, echten Implementierungscode im Simulator auszuführen)
· NS-3 bietet eine niedrigere Basisabstraktionsebene im Vergleich zu NS-2, damit es sich ausrichten kann
besser damit, wie reale Systeme zusammengestellt werden. Einige Einschränkungen gefunden in NS-2 (Wie z. B.
mehrere Typen von Schnittstellen auf Knoten korrekt unterstützen) wurden behoben in NS-3.
NS-2 hat ein vielfältigeres Set an Modulen als dies der Fall ist NS-3, wegen seiner langen
Geschichte. Jedoch, NS-3 hat detailliertere Modelle in mehreren beliebten Forschungsbereichen
(einschließlich ausgeklügelter LTE- und WiFi-Modelle) und die Unterstützung des Implementierungscodes
lässt ein sehr breites Spektrum an High-Fidelity-Modellen zu. Benutzer werden überrascht sein, wenn sie das erfahren
Der gesamte Linux-Netzwerkstack kann in einem NS-3 Knoten, mit dem Direct
Code Execution (DCE)-Framework. NS-2 Modelle können manchmal portiert werden auf NS-3, insbesondere
wenn sie in C++ implementiert wurden.
Im Zweifelsfall ist es eine gute Richtlinie, sich beide Simulatoren (sowie andere) anzusehen
Simulatoren) und insbesondere die für Ihre Forschung verfügbaren Modelle, aber denken Sie daran
dass Ihre Erfahrung bei der Verwendung des Tools, das aktiv entwickelt wird, möglicherweise besser ist und
gepflegt (NS-3).
Beitrag
NS-3 ist ein Forschungs- und Bildungssimulator von und für die Forschungsgemeinschaft. Es wird
verlassen Sie sich auf die laufenden Beiträge der Community, um neue Modelle zu entwickeln, zu debuggen oder
bestehende pflegen und Ergebnisse teilen. Es gibt ein paar Richtlinien, von denen wir hoffen, dass sie es werden
ermutigen Sie die Menschen, einen Beitrag zu leisten NS-3 wie sie haben für NS-2:
· Open-Source-Lizenzierung basierend auf GNU GPLv2-Kompatibilität
· Wiki
· Beigesteuert Code Seite, ähnlich wie NS-2's beliebter Contributed Code Seite
· Öffnen Fehler tracker
Uns ist bewusst, dass wenn Sie dieses Dokument lesen, ein Beitrag zum Projekt ist
wahrscheinlich nicht Ihr Hauptanliegen an dieser Stelle, aber wir möchten, dass Sie sich dessen bewusst sind
Beitragen ist im Geiste des Projekts und dass sogar der Akt, uns eine Nachricht zu hinterlassen
über deine frühen Erfahrungen mit NS-3 (zB "dieser Tutorial-Abschnitt war nicht klar..."),
Berichte über veraltete Unterlagen usw. sind sehr willkommen.
Einführung Organisation
Im Tutorial wird davon ausgegangen, dass neue Benutzer anfänglich möglicherweise einem Pfad wie dem folgenden folgen:
· Versuchen Sie, eine Kopie herunterzuladen und zu erstellen;
· Versuchen Sie, einige Beispielprogramme auszuführen;
· Sehen Sie sich die Simulationsausgabe an und versuchen Sie, sie anzupassen.
Aus diesem Grund haben wir versucht, das Tutorial entlang der oben genannten groben Abfolgen von
Veranstaltungen.
HR-RESSOURCEN
Die Web
Es gibt mehrere wichtige Ressourcen, von denen jeder NS-3 Benutzer muss sich bewusst sein. Das Hauptnetz
Website befindet sich unter http://www.nsnam.org und bietet Zugang zu grundlegenden Informationen über die
NS-3 System. Ausführliche Dokumentation ist über die Hauptwebsite unter verfügbar
http://www.nsnam.org/documentation/. Dort finden Sie auch Dokumente zum System
Architektur von dieser Seite.
Es gibt ein Wiki, das das Haupt-Wiki ergänzt NS-3 Website, die Sie finden unter
http://www.nsnam.org/wiki/. Dort finden Sie Benutzer- und Entwickler-FAQs sowie
Anleitungen zur Fehlerbehebung, von Drittanbietern beigesteuerter Code, Papiere usw.
Der Quellcode kann gefunden und durchsucht werden unter http://code.nsnam.org/. Dort findest du
der aktuelle Entwicklungsbaum im Repository namens ns-3-dev. Vergangene Veröffentlichungen und
Dort sind auch experimentelle Repositories der Core-Entwickler zu finden.
Quecksilber-
Komplexe Softwaresysteme benötigen eine Möglichkeit, die Organisation und Änderungen an den
zugrunde liegenden Code und Dokumentation. Es gibt viele Möglichkeiten, dieses Kunststück zu vollbringen, und Sie können
haben von einigen der Systeme gehört, die derzeit verwendet werden, um dies zu tun. Die gleichzeitige
Version System (CVS) ist wahrscheinlich das bekannteste.
Die NS-3 Projekt verwendet Mercurial als Quellcode-Verwaltungssystem. Obwohl du es nicht tust
Sie müssen viel über Mercurial wissen, um dieses Tutorial abzuschließen, wir empfehlen
sich mit Mercurial vertraut machen und damit auf den Quellcode zugreifen. Mercurial hat eine
Web site bei http://www.selenic.com/mercurial/, von dem Sie Binär- oder Quellcode erhalten können
Versionen dieses Software Configuration Management (SCM)-Systems. Selenic (der Entwickler
von Mercurial) bietet auch ein Tutorial unter
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/, und eine QuickStart-Anleitung unter
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.
Sie finden auch wichtige Informationen zur Verwendung von Mercurial und NS-3 auf der Hauptstraße NS-3 Netz
Website.
Waf
Sobald Sie den Quellcode auf Ihr lokales System heruntergeladen haben, müssen Sie diesen kompilieren
Quelle, um brauchbare Programme zu erstellen. Genau wie bei der Quellcodeverwaltung gibt es
stehen viele Werkzeuge zur Verfügung, um diese Funktion auszuführen. Die wohl bekannteste davon
Werkzeuge ist um. Zusammen mit der bekanntesten, um ist wohl am schwierigsten
in einem sehr großen und hochgradig konfigurierbaren System zu verwenden. Aus diesem Grund viele Alternativen
sind entwickelt worden. Kürzlich wurden diese Systeme mit Python entwickelt
Sprache.
Das Build-System Waf wird auf dem NS-3 Projekt. Es ist eines der neuen Generation von
Python-basierte Build-Systeme. Sie müssen kein Python verstehen, um das zu erstellen
vorhandenen NS-3 System funktionieren.
Für diejenigen, die sich für die blutigen Details von Waf interessieren, finden Sie die Hauptwebsite unter
http://code.google.com/p/waf/.
Entwicklung Arbeitsumfeld
Wie oben erwähnt, Skripting in NS-3 erfolgt in C++ oder Python. Die meisten von den NS-3 API ist
in Python verfügbar, aber die Modelle sind in beiden Fällen in C++ geschrieben. Ein funktionierendes
Kenntnisse in C++ und objektorientierten Konzepten werden in diesem Dokument vorausgesetzt. Wir werden nehmen
etwas Zeit, um einige der fortgeschritteneren Konzepte oder möglicherweise unbekannte Sprache zu überprüfen
Funktionen, Redewendungen und Designmuster, wie sie erscheinen. Wir wollen nicht, dass dieses Tutorial
jedoch in ein C++-Tutorial übergehen, sodass wir eine grundlegende Beherrschung der Sprache erwarten.
Es gibt eine fast unvorstellbare Anzahl von Informationsquellen zu C++, die auf der
im Internet oder in gedruckter Form.
Wenn Sie C++ noch nicht kennen, möchten Sie vielleicht ein Buch oder eine Website auf der Grundlage von Tutorials oder Kochbüchern finden
und arbeiten Sie zumindest die grundlegenden Funktionen der Sprache durch, bevor Sie fortfahren. Zum
Beispiel, fehlen uns die Worte. Lernprogramm.
Die NS-3 System verwendet mehrere Komponenten der GNU-"Toolchain" für die Entwicklung. EIN
Software-Toolchain ist der Satz von Programmierwerkzeugen, die in der gegebenen Umgebung verfügbar sind. Zum
eine kurze Übersicht darüber, was in der GNU-Toolchain enthalten ist, siehe,
http://en.wikipedia.org/wiki/GNU_toolchain. NS-3 verwendet gcc, GNU-Binutils und gdb.
Wir verwenden jedoch keine GNU-Build-Systemtools, weder make noch autotools. Wir verwenden Waf
für diese Funktionen.
Typischerweise ein NS-3 author arbeitet unter Linux oder einer Linux-ähnlichen Umgebung. Für diejenigen
unter Windows laufen, gibt es Umgebungen, die die Linux-Umgebung simulieren
verschiedene Grade. Die NS-3 Projekt wurde in der Vergangenheit (aber derzeit nicht) unterstützt
Entwicklung in der Cygwin-Umgebung für diese Benutzer. Sehen http://www.cygwin.com/ für
Details zum Herunterladen und besuchen Sie die NS-3 wiki für weitere Informationen über Cygwin und
NS-3. MinGW wird derzeit nicht offiziell unterstützt. Eine andere Alternative zu Cygwin ist,
Installieren Sie eine virtuelle Maschinenumgebung wie einen VMware-Server und installieren Sie ein virtuelles Linux
Maschine.
Steckdose Programmierung
In den hier verwendeten Beispielen gehen wir von einer grundlegenden Einrichtung mit der Berkeley Sockets API aus
Lernprogramm. Wenn Sie mit Sockets noch nicht vertraut sind, empfehlen wir Ihnen, die API und einige allgemeine Anwendungen zu überprüfen
Fälle. Für einen guten Überblick über die Programmierung von TCP/IP-Sockets empfehlen wir TCP / IP Sockets in
C, Donahoo und Calvert.
Es gibt eine zugehörige Website, die Quellen für die Beispiele im Buch enthält, die
finden Sie unter: http://cs.baylor.edu/~donahoo/practical/CSockets/.
Wenn Sie die ersten vier Kapitel des Buches verstehen (oder für diejenigen, die keinen Zugang haben
zu einer Kopie des Buches, der Echo-Clients und -Server, die auf der obigen Website gezeigt werden) werden Sie
Seien Sie in einem guten Zustand, um das Tutorial zu verstehen. Es gibt ein ähnliches Buch über Multicast
Steckdosen Multicast Steckdosen Makofske und Almeroth. das deckt Material ab, das Sie möglicherweise benötigen
verstehen, wenn Sie sich die Multicast-Beispiele in der Distribution ansehen.
BEKOMMEN GESTARTET
Dieser Abschnitt zielt darauf ab, einen Benutzer in einen Arbeitszustand zu versetzen, beginnend mit einer Maschine, die
vielleicht nie gehabt NS-3 Eingerichtet. Es deckt unterstützte Plattformen, Voraussetzungen und Möglichkeiten ab, um
erhalten NS-3, Möglichkeiten zu bauen NS-3, und Möglichkeiten, Ihren Build zu überprüfen und einfache Programme auszuführen.
Übersicht
NS-3 ist als System von Softwarebibliotheken aufgebaut, die zusammenarbeiten. Anwenderprogramme können
geschrieben, die mit diesen Bibliotheken verknüpft (oder aus ihnen importiert). Anwenderprogramme sind geschrieben in
entweder die Programmiersprachen C++ oder Python.
NS-3 wird als Quellcode verteilt, d.h. das Zielsystem muss über eine
Softwareentwicklungsumgebung, um zuerst die Bibliotheken zu erstellen, dann den Benutzer zu erstellen
NS-3 könnten prinzipiell als vorgefertigte Bibliotheken für ausgewählte
Systeme, und in Zukunft kann es so verteilt werden, aber derzeit viele Benutzer
machen ihre Arbeit tatsächlich durch Bearbeiten NS-3 selbst, so dass der Quellcode neu erstellt werden muss
die Bibliotheken ist nützlich. Wenn jemand die Aufgabe übernehmen möchte, vorgefertigte
Bibliotheken und Pakete für Betriebssysteme wenden Sie sich bitte an das ns-developers mailing
Liste.
Im Folgenden sehen wir uns zwei Möglichkeiten zum Herunterladen und Erstellen an NS-3. Das erste ist
um eine offizielle Version von der Hauptwebsite herunterzuladen und zu erstellen. Die zweite ist zu holen
und erstellen Sie Entwicklungskopien von NS-3. Wir werden beide Beispiele seit den Tools durchgehen
beteiligt sind etwas anders.
Herunterladen NS-3
Die NS-3 System als Ganzes ist ein ziemlich komplexes System und hat eine Reihe von Abhängigkeiten von
andere Komponenten. Zusammen mit den Systemen, mit denen Sie wahrscheinlich jeden Tag zu tun haben (die
GNU-Toolchain, Mercurial, ein Texteditor) müssen Sie sicherstellen, dass eine Reihe von
zusätzliche Bibliotheken auf Ihrem System vorhanden sind, bevor Sie fortfahren. NS-3 bietet ein Wiki
Seite, die Seiten mit vielen nützlichen Hinweisen und Tipps enthält. Eine solche Seite ist die
Seite "Installation", http://www.nsnam.org/wiki/Installation.
Der Abschnitt "Voraussetzungen" dieser Wiki-Seite erklärt, welche Pakete benötigt werden, um
Unterstützung allgemein NS-3 Optionen und stellt auch die Befehle bereit, mit denen sie installiert werden
gängigen Linux-Varianten. Cygwin-Benutzer müssen das Cygwin-Installationsprogramm verwenden (wenn Sie ein
Cygwin-Benutzer, Sie haben damit Cygwin installiert).
Vielleicht möchten Sie diese Gelegenheit nutzen, um die NS-3 wiki ein bisschen da gibt es wirklich
dort eine Fülle von Informationen.
Ab diesem Punkt gehen wir davon aus, dass der Reader unter Linux oder einem
Linux-Emulationsumgebung (Linux, Cygwin usw.) und hat die GNU-Toolchain installiert und
zusammen mit den oben genannten Voraussetzungen überprüft. Wir gehen auch davon aus
Sie haben Mercurial und Waf installiert und laufen auf dem Zielsystem.
Die NS-3 Code ist in Mercurial-Repositorys auf dem Server verfügbar http://code.nsnam.org.
Sie können auch eine Tarball-Version herunterladen unter http://www.nsnam.org/release/, oder du kannst arbeiten
mit Repositorys, die Mercurial verwenden. Wir empfehlen die Verwendung von Mercurial, es sei denn, es gibt ein gutes
Grund nicht. Anweisungen zum Abrufen eines Tarballs finden Sie am Ende dieses Abschnitts
freizugeben.
Der einfachste Weg, um mit der Verwendung von Mercurial-Repositorys zu beginnen, ist die Verwendung der ns-3-Allinon
Umgebung. Dies ist eine Reihe von Skripten, die das Herunterladen und Erstellen von
verschiedene Subsysteme von NS-3 für dich. Wir empfehlen Ihnen, Ihre NS-3 in diesem arbeiten
Umwelt.
Eine Praxis besteht darin, ein Verzeichnis namens . zu erstellen Arbeitsplatz im eigenen Home-Verzeichnis, unter dem
man kann lokale Mercurial-Repositorys behalten. Jeder Verzeichnisname reicht aus, aber wir gehen davon aus
zur Verbesserung der Gesundheitsgerechtigkeit Arbeitsplatz wird hier verwendet (Hinweis: repos kann in einigen Dokumentationen auch als
Beispielverzeichnisname).
Herunterladen NS-3 Die richtigen a Tarball
Ein Tarball ist ein bestimmtes Format eines Softwarearchivs, in dem mehrere Dateien gebündelt sind
zusammen und das Archiv ggf. komprimiert. NS-3 Software-Releases werden über a . bereitgestellt
herunterladbarer Tarball. Der Vorgang zum Herunterladen NS-3 über Tarball ist einfach; Sie gerade
müssen eine Version auswählen, herunterladen und dekomprimieren.
Nehmen wir an, Sie als Benutzer möchten bauen NS-3 in einem lokalen Verzeichnis namens
Arbeitsplatz. Wenn Sie das annehmen Arbeitsplatz Directory-Ansatz können Sie eine Kopie einer Version erhalten
indem Sie Folgendes in Ihre Linux-Shell eingeben (ersetzen Sie die entsprechenden Versionsnummern,
selbstverständlich):
$ CD
$ mkdir-Arbeitsbereich
$ cd-Arbeitsbereich
$ wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ tar xjf ns-allinone-3.22.tar.bz2
Wenn Sie in das Verzeichnis wechseln ns-allinon-3.22 Sie sollten eine Reihe von Dateien sehen:
$ls
Bake constants.py ns-3.22 README
build.py netanim-3.105 pybindgen-0.16.0.886 util.py
Sie sind jetzt bereit, die Basis zu bauen NS-3 Verteilung.
Herunterladen NS-3 Die richtigen Backen
Bake ist ein Tool für verteilte Integration und Erstellung, entwickelt für die NS-3 Projekt.
Bake kann verwendet werden, um Entwicklungsversionen der NS-3 Software und zum Herunterladen und
baue erweiterungen an der basis NS-3 Verteilung, wie die Direct Code Execution
Umgebung, Network Simulation Cradle, Möglichkeit zum Erstellen neuer Python-Bindungen und andere.
In den letzten NS-3 Releases wurde Bake in den Release-Tarball aufgenommen. Die Konfiguration
-Datei, die in der veröffentlichten Version enthalten ist, ermöglicht es einem, jede Software herunterzuladen, die
aktuell zum Zeitpunkt der Veröffentlichung. Das ist zum Beispiel die Version von Bake, die ist
verteilt mit dem NS-3.21 release kann verwendet werden, um Komponenten dafür zu holen NS-3 Release
oder früher, kann aber nicht zum Abrufen von Komponenten für spätere Versionen verwendet werden (es sei denn, die
Bakeconf.xml Datei wird aktualisiert).
Sie können auch die neueste Kopie von backen indem Sie Folgendes in Ihr Linux eingeben
Shell (vorausgesetzt, Sie haben Mercurial installiert):
$ CD
$ mkdir-Arbeitsbereich
$ cd-Arbeitsbereich
$ hg Klon http://code.nsnam.org/bake
Wenn der Befehl hg (Mercurial) ausgeführt wird, sollten Sie Folgendes sehen:
angezeigt,
...
Zielverzeichnis: backen
alle Änderungen anfordern
Änderungssätze hinzufügen
Manifeste hinzufügen
Dateiänderungen hinzufügen
339 Änderungssätze mit 796 Änderungen an 63 Dateien hinzugefügt
Aktualisierung auf Branch-Standard
45 Dateien aktualisiert, 0 Dateien zusammengeführt, 0 Dateien entfernt, 0 Dateien nicht aufgelöst
Nachdem der Klonbefehl abgeschlossen ist, sollten Sie ein Verzeichnis namens . haben backen, die Inhalte
davon sollte in etwa wie folgt aussehen:
$ls
Bake bakeconf.xml doc generate-binary.py TODO
bake.py-Beispieltest
Beachten Sie, dass Sie wirklich gerade einige Python-Skripte und ein Python-Modul namens . heruntergeladen haben
backen. Der nächste Schritt besteht darin, diese Skripte zu verwenden, um die herunterzuladen und zu erstellen NS-3
Verteilung Ihrer Wahl.
Es stehen einige Konfigurationsziele zur Verfügung:
1. NS-3.22: das der Freigabe entsprechende Modul; es wird ähnliche Komponenten herunterladen
zum Release-Tarball.
2. ns-3-dev: ein ähnliches Modul, aber mit dem Entwicklungscodebaum
3. ns-allinon-3.22: das Modul, das weitere optionale Funktionen wie Click enthält
Routing, Openflow für NS-3, und die Netzwerksimulationsstation
4. ns-3-Allinon: ähnlich der freigegebenen Version des allinone-Moduls, aber für
Entwicklungscode.
Der aktuelle Entwicklungs-Snapshot (unveröffentlicht) von NS-3 finden Sie unter
http://code.nsnam.org/ns-3-dev/. Die Entwickler versuchen, dieses Repository in
konsistente, funktionierende Zustände, aber sie befinden sich in einem Entwicklungsbereich mit unveröffentlichtem Code
vorhanden, daher sollten Sie in Betracht ziehen, bei einer offiziellen Veröffentlichung zu bleiben, wenn Sie dies nicht benötigen
neu eingeführte Funktionen.
Die neueste Version des Codes finden Sie entweder in der Repository-Liste
oder geh zum "ns-3 Veröffentlichungen" Webseite und klicken Sie auf den Link zur neuesten Version.
Wir fahren in diesem Tutorial-Beispiel mit . fort NS-3.22.
Wir werden jetzt das Backwerkzeug verwenden, um die verschiedenen Stücke von . herunterzuziehen NS-3 Du wirst
verwenden. Zuerst werden wir ein Wort über das Ausführen von Bake sagen.
bake funktioniert, indem Quellpakete in ein Quellverzeichnis heruntergeladen und installiert werden
Bibliotheken in ein Build-Verzeichnis. bake kann durch Verweis auf die Binärdatei ausgeführt werden, aber wenn eine
wählt Bake außerhalb des Verzeichnisses, in das es heruntergeladen wurde, ist es ratsam
um Bake in Ihren Pfad einzufügen, wie folgt (Linux-Bash-Shell-Beispiel). Zuerst ändern
in das Verzeichnis 'bake' und legen Sie dann die folgenden Umgebungsvariablen fest
$ export BAKE_HOME=`pwd`
$ export PATH=$PATH:$BAKE_HOME:$BAKE_HOME/build/bin
$ export PYTHONPATH=$PYTHONPATH:$BAKE_HOME:$BAKE_HOME/build/lib
Dadurch wird das Programm bake.py in den Pfad der Shell eingefügt und es anderen Programmen ermöglicht,
Finden Sie ausführbare Dateien und Bibliotheken, die von bake erstellt wurden. Obwohl einige Back-Anwendungsfälle dies nicht tun
erfordern die Einstellung von PATH und PYTHONPATH wie oben, vollständige Builds von ns-3-Allinon (mit dem
optionale Pakete) tun dies normalerweise.
Gehen Sie in das Arbeitsbereichsverzeichnis und geben Sie Folgendes in Ihre Shell ein:
$ ./bake.py configure -e ns-3.22
Als Nächstes bitten wir bake zu überprüfen, ob wir über genügend Tools zum Herunterladen verschiedener Komponenten verfügen.
Typ:
$ ./bake.py überprüfen
Sie sollten etwa Folgendes sehen:
> Python - OK
> GNU C++-Compiler - OK
> Quecksilber - OK
> CVS - OK
> GIT - OK
> Basar - OK
> Teer-Tool - OK
> Tool zum Entpacken - OK
> Unrar-Tool - fehlt
> 7z-Dienstprogramm zur Datenkomprimierung - OK
> Dienstprogramm zur XZ-Datenkomprimierung - OK
> Machen - OK
> cMake - OK
> Patch-Tool - OK
> Autoreconf-Tool - OK
> Pfad nach Werkzeugen gesucht: /usr/lib64/qt-3.3/bin /usr/lib64/ccache
/ usr / local / bin /Behälter / usr / bin / usr / local / sbin / usr / sbin / sbin
/home/tomh/mülleimer
Insbesondere Download-Tools wie Mercurial, CVS, GIT und Bazaar sind unser Prinzip
Bedenken an dieser Stelle, da sie es uns ermöglichen, den Code abzurufen. Bitte installieren fehlende
Tools zu diesem Zeitpunkt, wie für Ihr System üblich (sofern möglich), oder wenden Sie sich an
Ihren Systemadministrator nach Bedarf, um diese Tools zu installieren.
Versuchen Sie als Nächstes, die Software herunterzuladen:
$ ./bake.py herunterladen
sollte etwas ergeben wie:
>> Suche nach Systemabhängigkeit pygoocanvas - OK
>> Suche nach Systemabhängigkeit python-dev - OK
>> Suche nach Systemabhängigkeit pygraphviz - OK
>> Herunterladen von pybindgen-0.16.0.886 - OK
>> Suche nach Systemabhängigkeit g++ - OK
>> Suche nach Systemabhängigkeit qt4 - OK
>> Netanim-3.105 herunterladen - OK
>> Herunterladen von ns-3.22 - OK
Das Obige deutet darauf hin, dass drei Quellen heruntergeladen wurden. Überprüf den Quelle Verzeichnis
jetzt und tippe ls; man sollte sehen:
$ls
netanim-3.105 ns-3.22 pybindgen-0.16.0.886
Sie sind jetzt bereit, die NS-3 Verteilung.
zum NS-3
zum mit build.py
Wenn Sie mit einem freigegebenen Tarball arbeiten, erstellen Sie das erste Mal die NS-3 Projekt du kannst
Build mit einem Komfortprogramm, das in der allinone Verzeichnis. Dieses Programm heißt
build.py. Dieses Programm wird das Projekt am häufigsten für Sie konfigurieren
nützliche Weise. Beachten Sie jedoch, dass erweiterte Konfiguration und Arbeit mit NS-3 werden wir
beinhalten in der Regel die Verwendung des nativen NS-3 Build-System, Waf, wird später in diesem vorgestellt
Tutorial.
Wenn Sie mit einem Tarball heruntergeladen haben, sollten Sie ein Verzeichnis namens etwa . haben
ns-allinon-3.22 unter Ihrem ~/Arbeitsbereich Verzeichnis. Geben Sie Folgendes ein:
$ ./build.py --enable-examples --enable-tests
Weil wir in diesem Tutorial mit Beispielen und Tests arbeiten, und weil sie es nicht sind
standardmäßig eingebaut in NS-3, weisen die Argumente für build.py an, sie für uns zu erstellen. Die
Programm erstellt auch standardmäßig alle verfügbaren Module. Später kannst du bauen NS-3
ohne Beispiele und Tests, oder eliminieren Sie die Module, die für Ihre Arbeit nicht notwendig sind,
wenn Sie wünschen.
Sie werden viele typische Compiler-Ausgabemeldungen sehen, die angezeigt werden, während das Build-Skript erstellt wird
die verschiedenen Stücke, die Sie heruntergeladen haben. Schließlich sollten Sie Folgendes sehen:
Waf: Verlassen des Verzeichnisses `/path/to/workspace/ns-allinone-3.22/ns-3.22/build'
'build' erfolgreich abgeschlossen (6m25.032s)
Module gebaut:
Antennen-ADV-Anwendungen
Brückengebäude config-store
Kern-CSMA-CSMA-Layout
dsdv dsr energie
fd-net-device flow-monitor internet
lr-wpan LTE-Mesh
Mobilität mpi netanim (kein Python)
Netzwerk Nix-Vektor-Routing olsr
Punkt-zu-Punkt-Punkt-zu-Punkt-Layout-Ausbreitung
Sixlowpan-Spektrum-Statistiken
Tap-Bridge-Test (kein Python) Topologie-Lesen
uan Virtual-Net-Device-Welle
WLAN Wimax
Nicht erstellte Module (Erklärung siehe ns-3-Tutorial):
Brite Klick Openflow
Visualizer
Verlassen des Verzeichnisses `./ns-3.22'
Zum Abschnitt über nicht gebaute Module:
Nicht erstellte Module (Erklärung siehe ns-3-Tutorial):
Brite Klick Openflow
Visualizer
Das bedeutet nur, dass einige NS-3 Module, die Abhängigkeiten von externen Bibliotheken haben, dürfen nicht
gebaut wurden oder dass die Konfiguration ausdrücklich darum gebeten hat, sie nicht zu erstellen. Es tut
bedeutet nicht, dass der Simulator nicht erfolgreich erstellt wurde oder dass er falsch liefert
Ergebnisse für die Module, die als gebaut aufgeführt sind.
zum mit backen
Wenn Sie oben Bake verwendet haben, um Quellcode aus Projekt-Repositorys abzurufen, können Sie fortfahren
benutze es zum bauen NS-3. Art
$ ./bake.py bauen
und Sie sollten etwas sehen wie:
>> Gebäude pybindgen-0.16.0.886 - OK
>> Gebäude netanim-3.105 - OK
>> Gebäude ns-3.22 - OK
Hinweis: U können. ebenfalls ausführen beide Schritte, herunterladen und bauen by Aufruf 'backen.py einsetzen'.
Wenn ein Fehler auftritt, sehen Sie sich bitte an, was der folgende Befehl sagt
Sie; es kann einen Hinweis auf eine fehlende Abhängigkeit geben:
$ ./bake.py anzeigen
Dies listet die verschiedenen Abhängigkeiten der Pakete auf, die Sie erstellen möchten.
zum mit Waf
Bisher haben wir entweder die build.py Skript oder die backen Werkzeug, um zu bekommen
begann mit dem Bauen NS-3. Diese Werkzeuge sind nützlich zum Bauen NS-3 und Unterstützung
Bibliotheken, und sie rufen in die NS-3 Verzeichnis, um das Waf-Build-Tool aufzurufen, um die
eigentliches Gebäude. Die meisten Benutzer wechseln schnell zur Verwendung von Waf direkt zum Konfigurieren und
bauen NS-3. Um fortzufahren, ändern Sie bitte Ihr Arbeitsverzeichnis in das NS-3 Verzeichnis
die Sie ursprünglich gebaut haben.
An dieser Stelle ist es nicht unbedingt erforderlich, aber es lohnt sich, einen kleinen Umweg zu machen
und sehen Sie sich an, wie Sie Änderungen an der Konfiguration des Projekts vornehmen. Wahrscheinlich die meisten
Eine nützliche Konfigurationsänderung, die Sie vornehmen können, besteht darin, die optimierte Version des
Code. Standardmäßig haben Sie Ihr Projekt so konfiguriert, dass es die Debug-Version erstellt. Lass es uns erzählen
das Projekt, um einen optimierten Build zu erstellen. Um Waf zu erklären, dass es optimiert werden sollte
Builds, die die Beispiele und Tests enthalten, müssen Sie Folgendes ausführen
Befehle:
$ ./waf sauber
$ ./waf --build-profile=optimized --enable-examples --enable-tests konfigurieren
Dies führt Waf aus dem lokalen Verzeichnis aus (das Ihnen zur Verfügung gestellt wird).
Der erste Befehl zum Bereinigen des vorherigen Builds ist normalerweise nicht unbedingt erforderlich, aber
ist eine gute Praxis (aber siehe Bauen Profil, unter); es wird das zuvor erstellte entfernen
Bibliotheken und Objektdateien im Verzeichnis gefunden bauen/. Wenn das Projekt neu konfiguriert wird
und das Build-System auf verschiedene Abhängigkeiten prüft, sollten Sie eine Ausgabe sehen, die aussieht
ähnlich wie folgt:
Einstellung oben auf : .
Aufbruch zu: bauen
Suche nach 'gcc' (c-Compiler) : /usr/bin/gcc
CC-Version prüfen: 4.2.1
Suche nach 'g++' (c++-Compiler) : /usr/bin/g++
Die Überprüfung des Boosts umfasst: 1_46_1
Überprüfung der Boost-Libs: ok
Auf Boost-Gestänge prüfen: ok
Suche nach Klickposition: nicht gefunden
Suche nach Programm pkg-config : /sw/bin/pkg-config
Suche nach 'gtk+-2.0' >= 2.12 : ja
Suche nach 'libxml-2.0' >= 2.7 : ja
Suche nach Typ uint128_t : nicht gefunden
Prüfung auf Typ __uint128_t : ja
Überprüfung der hochpräzisen Implementierung: 128-Bit-Ganzzahl (Standard)
Auf Header stdint.h prüfen: ja
Suche nach Header inttypes.h : ja
Suche nach Header sys/inttypes.h : nicht gefunden
Suche nach Header sys/types.h : ja
Überprüfung auf Header sys/stat.h : ja
Suche nach Header dirent.h : ja
Auf Header stdlib.h prüfen: ja
Auf Headersignal prüfen.h : ja
Suche nach Header pthread.h : ja
Auf Header stdint.h prüfen: ja
Suche nach Header inttypes.h : ja
Suche nach Header sys/inttypes.h : nicht gefunden
Suche nach Bibliothek rt : nicht gefunden
Suche nach Header netpacket/packet.h : nicht gefunden
Überprüfung auf Header sys/ioctl.h : ja
Überprüfung auf Header net/if.h : nicht gefunden
Überprüfung auf Header net/ethernet.h : ja
Überprüfung auf Header linux/if_tun.h : nicht gefunden
Suche nach Header netpacket/packet.h : nicht gefunden
Suche nach NSC-Standort: nicht gefunden
Suche nach 'mpic++': ja
Suche nach 'sqlite3': ja
Überprüfung auf Header linux/if_tun.h : nicht gefunden
Programm-Sudo prüfen: /usr/bin/sudo
Suche nach Programm valgrind : /sw/bin/valgrind
Suche nach 'gsl': ja
Überprüfung auf Kompilierungsflag -Wno-error=deprecated-d... support : ok
Überprüfung auf Kompilierungsflag -Wno-error=deprecated-d... support : ok
Überprüfung auf Kompilierungsflag -fstrict-aliasing... support : ok
Überprüfung auf Kompilierungsflag -fstrict-aliasing... support : ok
Überprüfung auf Kompilierungsflag -Wstrict-aliasing... support : ok
Überprüfung auf Kompilierungsflag -Wstrict-aliasing... support : ok
Suche nach Programm doxygen : /usr/local/bin/doxygen
---- Zusammenfassung der optionalen NS-3-Funktionen:
Profil erstellen: debuggen
Build-Verzeichnis: build
Python-Bindungen: aktiviert
BRITE-Integration: nicht aktiviert (BRITE nicht aktiviert (siehe Option --with-brite))
NS-3 Click Integration : nicht aktiviert (nsclick nicht aktiviert (siehe Option --with-nsclick))
GtkConfigStore : aktiviert
XmlIo: aktiviert
Threading-Primitive : aktiviert
Echtzeitsimulator: aktiviert (librt ist nicht verfügbar)
Emuliertes Netzgerät: aktiviert ( enthalten nicht erkannt)
Dateideskriptor NetDevice : aktiviert
Tippen Sie auf FdNetDevice : nicht aktiviert (benötigt linux/if_tun.h)
Emulation FdNetDevice : nicht aktiviert (benötigt netpacket/packet.h)
PlanetLab FdNetDevice : nicht aktiviert (PlanetLab-Betriebssystem nicht erkannt (siehe Option --force-planetlab))
Netzwerksimulationsstation: nicht aktiviert (NSC nicht gefunden (siehe Option --with-nsc))
MPI-Unterstützung: aktiviert
NS-3 OpenFlow Integration: nicht aktiviert (Erforderliche Boost-Bibliotheken nicht gefunden, fehlen: System, Signale, Dateisystem)
SQlite Statistikdatenausgabe: aktiviert
Tippen Sie auf Bridge : nicht aktiviert ( enthalten nicht erkannt)
PyViz-Visualisierung: aktiviert
Verwenden Sie sudo, um das suid-Bit zu setzen: nicht aktiviert (Option --enable-sudo nicht ausgewählt)
Build-Tests : aktiviert
Build-Beispiele: aktiviert
GNU Scientific Library (GSL) : aktiviert
'configure' erfolgreich beendet (1.944s)
Beachten Sie den letzten Teil der obigen Ausgabe. Etwas NS-3 Optionen sind standardmäßig nicht aktiviert oder
benötigen Unterstützung vom zugrunde liegenden System, um ordnungsgemäß zu funktionieren. Zum Beispiel, um zu aktivieren
XmlTo, die Bibliothek libxml-2.0 muss auf dem System gefunden werden. Wenn diese Bibliothek nicht wäre
gefunden, das entsprechende NS-3 Funktion wäre nicht aktiviert und eine Nachricht wäre
angezeigt. Beachten Sie außerdem, dass es eine Funktion gibt, um das Programm zu verwenden sudo die suid einstellen
ein bisschen von bestimmten Programmen. Dies ist standardmäßig nicht aktiviert und daher wird diese Funktion gemeldet
als "nicht aktiviert".
Fahren Sie nun fort und wechseln Sie zurück zum Debug-Build, der die Beispiele und Tests enthält.
$ ./waf sauber
$ ./waf --build-profile=debug --enable-examples --enable-tests konfigurieren
Das Build-System ist jetzt konfiguriert und Sie können die Debug-Versionen der NS-3
Programme durch einfaches Tippen
$ ./waf
Okay, tut mir leid, ich habe dich dazu gebracht, das zu bauen NS-3 Teil des Systems zweimal, aber jetzt wissen Sie, wie es geht
Ändern Sie die Konfiguration und erstellen Sie optimierten Code.
Das oben besprochene build.py-Skript unterstützt auch die --enable-Beispiele und Enable-Tests
-Argumente, unterstützt jedoch im Allgemeinen andere waf-Optionen nicht direkt; zum Beispiel das
wird nicht funktionieren:
$ ./build.py --disable-python
wird darin enden, dass
build.py: Fehler: keine solche Option: --disable-python
Der spezielle Operator -- kann verwendet werden, um zusätzliche Optionen an waf weiterzugeben, also
Anstelle des oben genannten funktioniert Folgendes:
$ ./build.py -- --disable-python
da es den zugrunde liegenden Befehl generiert ./waff konfigurieren --disable-python.
Hier sind ein paar weitere Einführungstipps zu Waf.
Einrichtung vs Bauen
Einige Waf-Befehle sind nur während der Konfigurationsphase sinnvoll und einige Befehle sind
gültig in der Bauphase. Wenn Sie beispielsweise die Emulationsfunktionen von
NS-3, möchten Sie möglicherweise das Setzen des suid-Bits mithilfe von sudo wie oben beschrieben aktivieren. Dies
entpuppt sich als Befehl zur Konfigurationszeit, und Sie können die Konfiguration mit dem
folgenden Befehl, der auch die Beispiele und Tests enthält.
$ ./waf configure --enable-sudo --enable-examples --enable-tests
Wenn Sie dies tun, hat Waf sudo ausgeführt, um die Socket-Creator-Programme des zu ändern
Emulationscode, der als Root ausgeführt werden soll.
Es gibt viele andere Konfigurations- und Build-Time-Optionen in Waf. Um diese zu erkunden
Optionen, Typ:
$ ./waf --Hilfe
Wir werden einige der testbezogenen Befehle im nächsten Abschnitt verwenden.
Bauen Profil
Wir haben bereits gesehen, wie Sie Waf für konfigurieren können debuggen or optimiert baut:
$ ./waf --build-profile=debug
Es gibt auch ein Zwischenbauprofil, Release. -d ist ein Synonym für
--Build-Profil.
Standardmäßig legt Waf die Build-Artefakte in den bauen Verzeichnis. Sie können a angeben
anderes Ausgabeverzeichnis mit dem --aus Option, zB
$ ./waf konfigurieren --out=foo
In Kombination mit Build-Profilen können Sie zwischen den verschiedenen Kompilierungsoptionen wechseln
auf saubere Weise:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf bauen
...
$ ./waf configure --build-profile=optimized --out=build/optimized
$ ./waf bauen
...
Auf diese Weise können Sie mit mehreren Builds arbeiten, anstatt immer den letzten zu überschreiben
bauen. Wenn Sie wechseln, kompiliert Waf nur das, was es muss, anstatt es neu zu kompilieren
alles.
Wenn Sie Build-Profile wie dieses wechseln, müssen Sie darauf achten, dasselbe zu geben
Konfigurationsparameter jedes Mal. Es kann praktisch sein, eine Umgebung zu definieren
Variablen, die Ihnen helfen, Fehler zu vermeiden:
$ export NS3CONFIG="--enable-examples --enable-tests"
$ export NS3DEBUG="--build-profile=debug --out=build/debug"
$ export NS3OPT=="--build-profile=optimized --out=build/optimized"
$ ./waf konfigurieren $NS3CONFIG $NS3DEBUG
$ ./waf bauen
...
$ ./waf konfigurieren $NS3CONFIG $NS3OPT
$ ./waf bauen
Compiler
In den obigen Beispielen verwendet Waf den GCC C++-Compiler, g ++, zum Bauen NS-3. Jedoch
Es ist möglich, den von Waf verwendeten C++-Compiler zu ändern, indem Sie CXX -Umgebung
Variable. Um beispielsweise den Clang C++-Compiler zu verwenden, klingeln ++,
$ CXX="clang++" ./waf konfigurieren
$ ./waf bauen
Man kann Waf auch so einrichten, dass es eine verteilte Kompilierung mit macht distcc in einer ähnlichen Weise:
$ CXX="distcc g++" ./waf configure
$ ./waf bauen
Weitere Informationen über distcc und verteilte Zusammenstellung finden Sie auf seiner Projekt Seite für
Abschnitt Dokumentation.
Installieren
Waf kann verwendet werden, um Bibliotheken an verschiedenen Stellen im System zu installieren. Der Standard
Der Ort, an dem Bibliotheken und ausführbare Dateien erstellt werden, befindet sich im bauen Verzeichnis, und weil
Waf kennt den Speicherort dieser Bibliotheken und ausführbaren Dateien, eine Installation ist nicht erforderlich
die Bibliotheken anderswo.
Wenn Benutzer sich dafür entscheiden, Dinge außerhalb des Build-Verzeichnisses zu installieren, können Benutzer die
./waff installieren Befehl. Standardmäßig lautet das Präfix für die Installation Verzeichnis / usr / local, damit ./waff
installieren installiert Programme in / usr / local / bin, Bibliotheken in / Usr / local / lib und
Überschriften in /usr/local/include. Superuser-Berechtigungen werden normalerweise benötigt, um zu installieren
das Standardpräfix, also wäre der typische Befehl sudo ./waff installieren. Beim Laufen
Programme mit Waf verwendet Waf zunächst lieber Shared Libraries im Build-Verzeichnis,
sucht dann nach Bibliotheken im Bibliothekspfad, der in der lokalen Umgebung konfiguriert ist. So
Wenn Sie Bibliotheken auf dem System installieren, sollten Sie überprüfen, ob die beabsichtigten
Bibliotheken verwendet werden.
Benutzer können sich für die Installation unter einem anderen Präfix entscheiden, indem sie das prefix Option bei
Zeit konfigurieren, wie zum Beispiel:
./waf konfigurieren --prefix=/opt/local
Wenn der Benutzer später nach dem Build die ./waff installieren Befehl, das Präfix /opt/lokal
werden verwendet.
Die ./waff reinigen Befehl sollte vor der Neukonfiguration des Projekts verwendet werden, wenn Waf
verwendet, um Dinge unter einem anderen Präfix zu installieren.
Zusammenfassend ist es nicht notwendig, anzurufen ./waff installieren benutzen NS-3. Die meisten Benutzer werden nicht
benötigen diesen Befehl, da Waf die aktuellen Bibliotheken aus dem bauen Verzeichnis,
Einige Benutzer finden es jedoch möglicherweise nützlich, wenn ihr Anwendungsfall die Arbeit mit Programmen außerhalb umfasst
dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog. NS-3 Verzeichnis.
Eins Waf
Es gibt nur ein Waf-Skript auf der obersten Ebene des NS-3 Quellbaum. Während Sie arbeiten,
vielleicht verbringst du viel Zeit in kratzen/, oder tief drin Quelle/..., und muss
Waf aufrufen. Sie können sich einfach daran erinnern, wo Sie sind, und Waf wie folgt aufrufen:
$ ../../../waf ...
aber das wird mühsam und fehleranfällig, und es gibt bessere Lösungen.
Wenn du das volle hast NS-3 Repository dieses kleine Juwel ist ein Anfang:
$ cd $(hg root) && ./waf ...
Noch besser ist es, dies als Shell-Funktion zu definieren:
$ Funktion waff { cd $(hg root) && ./waf $* ; }
$ waffelbau
Wenn Sie nur den Tarball haben, kann eine Umgebungsvariable helfen:
$ export NS3DIR="$PWD"
$ Funktion waff { cd $NS3DIR && ./waf $* ; }
$ CD-Kratzer
$ waffelbau
Es mag verlockend sein, in einem Modulverzeichnis ein Trivial hinzuzufügen waf Skript nach dem Vorbild von
exec ../../waf. Bitte nicht. Es ist verwirrend für Neulinge, und wenn es schlecht gemacht wird
führt zu subtilen Build-Fehlern. Die obigen Lösungen sind der richtige Weg.
Testen NS-3
Sie können die Unit-Tests des NS-3 Verteilung durch Ausführen der ./test.py -c Core
Skript:
$ ./test.py -c Kern
Diese Tests werden von Waf parallel durchgeführt. Sie sollten schließlich einen Bericht sehen, in dem das steht
92 von 92 Tests bestanden (92 bestanden, 0 fehlgeschlagen, 0 abgestürzt, 0 Valgrind-Fehler)
Dies ist die wichtige Botschaft.
Sie sehen auch die zusammenfassende Ausgabe von Waf und dem Testläufer, der jeden Test ausführt.
was tatsächlich ungefähr so aussehen wird:
Waf: Verzeichnis `/path/to/workspace/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/path/to/workspace/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (1.799s)
Module gebaut:
aodv-Anwendungsbrücke
Klicken Sie auf config-store core
csma csma-Layout dsdv
emu Energieflusswächter
Internet-LTE-Mesh
Mobilität mpi netanim
Netzwerk-Nix-Vektor-Routing ns3tcp
ns3wifi olsr openflow
Punkt-zu-Punkt-Punkt-zu-Punkt-Layout-Ausbreitung
Spektrum Stats Tap-Bridge
Vorlagentesttools
Topologie-Lesen und ein virtuelles Netzgerät
visualisierer wifi wimax
PASS: TestSuite ns3-wifi-interferenz
PASS: TestSuite-Histogramm
...
PASS: TestSuite-Objekt
PASS: TestSuite Zufallszahlengeneratoren
92 von 92 Tests bestanden (92 bestanden, 0 fehlgeschlagen, 0 abgestürzt, 0 Valgrind-Fehler)
Dieser Befehl wird normalerweise von Benutzern ausgeführt, um schnell zu überprüfen, ob ein NS-3 Vertrieb hat
richtig gebaut. (Beachten Sie die Reihenfolge der PASSIEREN: ... Linien können variieren, was in Ordnung ist. Was ist
Wichtig ist, dass die Zusammenfassungszeile am Ende anzeigt, dass alle Tests bestanden wurden; keiner ist fehlgeschlagen oder
abgestürzt.)
Laufen a Skript
Normalerweise führen wir Skripte unter der Kontrolle von Waf aus. Dadurch kann das Build-System sicherstellen, dass
dass die Pfade der gemeinsam genutzten Bibliotheken richtig eingestellt sind und dass die Bibliotheken verfügbar sind unter
Laufzeit. Um ein Programm auszuführen, verwenden Sie einfach die --Lauf Option in Waf. Lass uns laufen NS-3
Äquivalent des allgegenwärtigen Hello-World-Programms, indem Sie Folgendes eingeben:
$ ./waf --run hallo-simulator
Waf überprüft zuerst, ob das Programm korrekt erstellt wurde und führt einen Build aus, wenn
erforderlich. Waf führt dann das Programm aus, das die folgende Ausgabe erzeugt.
Hallo Simulator
Herzliche Glückwünsche! Sie sind jetzt ein ns-3-Benutzer!
Was do I do if I nicht sehen Ausgabe?
Wenn Waf-Meldungen angezeigt werden, die darauf hinweisen, dass der Build erfolgreich abgeschlossen wurde, aber nicht
Sehen Sie sich die Ausgabe von "Hello Simulator" an. Möglicherweise haben Sie Ihren Build-Modus auf umgestellt
optimiert begann zum mit Waf Abschnitt, haben aber die Änderung zurück zu verpasst debuggen Modus arbeiten können.
Alle in diesem Tutorial verwendeten Konsolenausgaben verwenden ein spezielles NS-3 Protokollierungskomponente, die
ist nützlich, um Benutzernachrichten an die Konsole zu drucken. Die Ausgabe dieser Komponente ist
automatisch deaktiviert, wenn Sie optimierten Code kompilieren - er ist "ausoptimiert". wenn du
die Ausgabe von "Hello Simulator" nicht angezeigt wird, geben Sie Folgendes ein:
$ ./waf configure --build-profile=debug --enable-examples --enable-tests
Waf anzuweisen, die Debug-Versionen der NS-3 Programme, die die Beispiele enthalten
und testet. Sie müssen immer noch die eigentliche Debug-Version des Codes erstellen, indem Sie eingeben
$ ./waf
Nun, wenn Sie die hallo-simulator Programm sollten Sie die erwartete Ausgabe sehen.
Mentessa for Good Argumente
So füttern Sie Befehlszeilenargumente an ein NS-3 Programm verwendet dieses Muster:
$ ./waf --run --command-template="%s "
Ersetzen Sie Ihren Programmnamen für , und die Argumente dafür dem „Vermischten Geschmack“. Seine
--Befehlsvorlage Argument gegen Waf ist im Grunde ein Rezept für die Konstruktion des tatsächlichen
Befehlszeile sollte Waf verwenden, um das Programm auszuführen. Waf prüft, ob der Build
complete, legt die Pfade der gemeinsam genutzten Bibliothek fest und ruft dann die ausführbare Datei mit dem bereitgestellten
Befehlszeilenvorlage, Einfügen des Programmnamens für die %s Platzhalter. (Ich gebe das zu
ist etwas umständlich, aber so ist es. Patches willkommen!)
Ein weiteres besonders nützliches Beispiel ist das Ausführen einer Testsuite allein. Nehmen wir an, a
mein Test Testsuite existiert (nicht). Oben haben wir die ./test.py Skript zum Ausführen eines Ganzen
eine Reihe von Tests parallel durch wiederholtes Aufrufen des realen Testprogramms, Testläufer.
Aufrufen Testläufer direkt für einen einzelnen Test:
$ ./waf --run test-runner --command-template="%s --suite=mytest --verbose"
Dies übergibt die Argumente an die Testläufer Programm. Schon seit mein Test existiert nicht, und
Fehlermeldung generiert wird. Zum Ausdrucken der verfügbaren Testläufer Optionen:
$ ./waf --run test-runner --command-template="%s --help"
Fehlerbeseitigung
Zu rennen NS-3 Programme, die von einem anderen Dienstprogramm gesteuert werden, z. B. einem Debugger (z.B gdb)
oder Speicherprüfer (z.B Valgrind), verwenden Sie ein ähnliches --command-template="..." Form.
Zum Beispiel, um Ihr NS-3 Programm hallo-simulator mit den Argumenten unter dem
gdb Debugger:
$ ./waf --run=hello-simulator --command-template="gdb %s --args "
Beachten Sie, dass die NS-3 Programmname passt zum --Lauf -Argument und das Kontroll-Utility
(Hier gdb) ist das erste Token im --Befehlsvorlage Streit. Das --args erzählt gdb
dass der Rest der Kommandozeile zum "minderwertigen" Programm gehört. (Etwas gdb's
verstehe das nicht --args Besonderheit. Lassen Sie in diesem Fall die Programmargumente aus der
--Befehlsvorlageund benutze die gdb Befehl kompensieren args.)
Wir können dieses Rezept und das vorherige kombinieren, um einen Test unter dem Debugger durchzuführen:
$ ./waf --run test-runner --command-template="gdb %s --args --suite=mytest --verbose"
Arbeiten Verzeichnis
Waf muss von seinem Standort an der Spitze des NS-3 Baum. Das wird die Arbeit
Verzeichnis, in das die Ausgabedateien geschrieben werden. Aber was ist, wenn Sie diese behalten wollen?
NS-3 Quellbaum? Verwenden Sie die --cwd Argument:
$ ./waf --cwd=...
Es kann bequemer sein, mit Ihrem Arbeitsverzeichnis zu beginnen, in dem Sie die Ausgabe haben möchten
Dateien, wobei ein kleiner Umweg hilfreich sein kann:
$ Funktion waff {
CWD="$PWD"
cd $NS3DIR >/dev/null
./waf --cwd="$CWD" $*
cd ->/dev/null
}
Diese Verschönerung der Vorgängerversion speichert das aktuelle Arbeitsverzeichnis, cdist zu
das Waf-Verzeichnis und weist Waf dann an, das Arbeitsverzeichnis zu ändern Zurück zu den geretteten
aktuelles Arbeitsverzeichnis, bevor Sie das Programm ausführen.
KONZEPTIV Überblick
Das erste, was wir tun müssen, bevor wir mit dem Anschauen oder Schreiben beginnen NS-3 Code ist zu
einige Kernkonzepte und Abstraktionen im System erklären. Vieles davon kann erscheinen
für einige transparent einleuchtend, aber wir empfehlen, sich die Zeit zu nehmen, dies durchzulesen
nur um sicherzustellen, dass Sie auf einem festen Fundament beginnen.
Wesentliche Abstraktionen
In diesem Abschnitt besprechen wir einige Begriffe, die häufig in Netzwerken verwendet werden, aber
spezifische Bedeutung in NS-3.
Knoten
Im Internet-Jargon wird ein Computergerät, das sich mit einem Netzwerk verbindet, als a . bezeichnet Gastgeber or
manchmal ein Ende System. weil NS-3 ist eine Netzwerk Simulator, nicht speziell ein
Internet Simulator verwenden wir den Begriff Host absichtlich nicht, da er eng ist
mit dem Internet und seinen Protokollen verbunden. Stattdessen verwenden wir auch einen allgemeineren Begriff
von anderen Simulatoren verwendet, die aus der Graphentheorie stammen --- die Knoten.
In NS-3 die grundlegende Abstraktion von Computergeräten wird als Knoten bezeichnet. Diese Abstraktion ist
in C++ repräsentiert durch die Klasse Knotendem „Vermischten Geschmack“. Seine Knoten -Klasse bietet Methoden zum Verwalten der
Darstellungen von Computergeräten in Simulationen.
Sie sollten an a . denken Knoten als Computer, dem Sie Funktionen hinzufügen. Einer fügt hinzu
Dinge wie Anwendungen, Protokollstapel und Peripheriekarten mit ihren zugehörigen
Treiber, damit der Computer nützliche Arbeiten ausführen kann. Wir verwenden das gleiche Grundmodell in NS-3.
Anwendungs-
Typischerweise wird Computersoftware in zwei große Klassen eingeteilt. System Software organisiert
verschiedene Computerressourcen wie Speicher, Prozessorzyklen, Festplatte, Netzwerk usw.,
nach einem Rechenmodell. Die Systemsoftware verwendet diese Ressourcen normalerweise nicht
um Aufgaben zu erledigen, die einem Benutzer direkt zugute kommen. Ein Benutzer würde normalerweise eine Anwendung
das die von der Systemsoftware kontrollierten Ressourcen erwirbt und verwendet, um einige zu erreichen
Tor.
Die Trennung zwischen System- und Anwendungssoftware erfolgt oft erst an der
Änderung der Berechtigungsebene, die in Betriebssystem-Traps auftritt. In NS-3 es gibt keine echte
Konzept des Betriebssystems und insbesondere kein Konzept von Berechtigungsstufen oder Systemaufrufen.
Wir haben jedoch die Idee einer Anwendung. So wie Softwareanwendungen weiterlaufen
Computer, um Aufgaben in der "realen Welt" auszuführen, NS-3 Anwendungen laufen weiter NS-3 Nodes zu
Fahrsimulationen in der simulierten Welt.
In NS-3 die grundlegende Abstraktion für ein Benutzerprogramm, das eine Aktivität erzeugt, die
simuliert ist die Anwendung. Diese Abstraktion wird in C++ durch die Klasse
Anwendungs-dem „Vermischten Geschmack“. Seine Anwendungs- -Klasse bietet Methoden zum Verwalten der Darstellungen von
unsere Version von Anwendungen auf Benutzerebene in Simulationen. Von Entwicklern wird erwartet, dass sie
spezialisieren Anwendungs- Klasse im Sinne der objektorientierten Programmierung zum Erstellen neuer
Anwendungen. In diesem Tutorial verwenden wir Spezialisierungen der Klasse Anwendungs- namens
UdpEchoClient-Anwendung und UdpEchoServer-Anwendung. Wie zu erwarten, diese
Anwendungen stellen einen Client/Server-Anwendungssatz zusammen, der verwendet wird, um simulierte
Netzwerkpakete
Kanal
In der realen Welt kann man einen Computer mit einem Netzwerk verbinden. Oft die Medien, über die
Datenflüsse in diesen Netzen heißen Kanäle. Wenn Sie Ihr Ethernet-Kabel an
den Stecker in der Wand, verbinden Sie Ihren Computer mit einer Ethernet-Kommunikation
Kanal. In der simulierten Welt von NS-3, man verbindet a Knoten zu einem Objekt, das a . darstellt
Kommunikationskanal. Hier wird die grundlegende Abstraktion des Kommunikationssubnetzes als bezeichnet
Kanal und wird in C++ durch die Klasse Kanal.
Die Kanal -Klasse bietet Methoden zum Verwalten von Kommunikationssubnetzobjekten und
Knoten mit ihnen verbinden. Kanäle kann auch von Entwicklern auf das Objekt spezialisiert werden
orientierten Programmiersinn. EIN Kanal Spezialisierung kann etwas so Einfaches wie a . modellieren
Kabel. Der Spezialist Kanal kann auch so komplizierte Dinge wie ein großes Ethernet modellieren
Schalter oder dreidimensionaler Raum voller Hindernisse im Fall von drahtlosen Netzwerken.
Wir verwenden spezialisierte Versionen der Kanal namens CsmaChannel, PunktzuPunktKanal
und WifiKanal in diesem Tutorial. Die CsmaChannelzum Beispiel modelliert eine Version von a
Kommunikations-Subnetz, das a . implementiert Träger Sinn mehrere Zugang Kommunikation
Mittel. Dies gibt uns Ethernet-ähnliche Funktionalität.
Netto- Gerät
Früher war es so, dass man, wenn man einen Computer mit einem Netzwerk verbinden wollte, dies tun musste
Kaufen Sie eine bestimmte Art von Netzwerkkabel und ein Hardwaregerät namens (in der PC-Terminologie) a
peripher Karte die auf Ihrem Computer installiert werden musste. Wenn die Peripheriekarte
eine Netzwerkfunktion implementiert haben, wurden sie Network Interface Cards genannt, oder NICs.
Heutzutage sind die meisten Computer mit integrierter Netzwerkschnittstellenhardware ausgestattet, die Benutzer nicht sehen
diese Bausteine.
Eine NIC funktioniert nicht ohne einen Softwaretreiber zur Steuerung der Hardware. Unter Unix (oder
Linux) wird eine periphere Hardware als Gerät. Geräte werden gesteuert
Verwendung von Gerät Treiber, und Netzwerkgeräte (NICs) werden mit . gesteuert Netzwerk Gerät
Treiber kollektiv bekannt als Netto- Low-Level-Lichtlaser. Unter Unix und Linux beziehen Sie sich auf diese Netze
Geräte mit Namen wie eth0.
In NS-3 Netto- Gerät Abstraktion umfasst sowohl den Softwaretreiber als auch den simulierten
Hardware. Ein Netzgerät wird in a . "installiert" Knoten um die zu aktivieren Knoten zu
mit anderen kommunizieren Nodes in der Simulation über Kanäle. Wie in einem echten Computer,
a Knoten kann mit mehr als einem verbunden sein Kanal über mehrere NetGeräte.
Die Netzgeräteabstraktion wird in C++ durch die Klasse NetDevicedem „Vermischten Geschmack“. Seine NetDevice
-Klasse bietet Methoden zum Verwalten von Verbindungen zu Knoten und Kanal Gegenstände; und vielleicht
von Entwicklern im Sinne der objektorientierten Programmierung spezialisiert. Wir werden die verwenden
mehrere spezialisierte Versionen der NetDevice namens CsmaNetDevice, PointToPointNetDevice,
und WifiNetGerät in diesem Tutorial. So wie eine Ethernet-NIC für die Arbeit mit einem
Ethernet-Netzwerk, das CsmaNetDevice wurde entwickelt, um mit a . zu arbeiten CsmaChannel; das
PointToPointNetDevice wurde entwickelt, um mit a . zu arbeiten PunktzuPunktKanal und einem WifiNetNevice
wurde entwickelt, um mit a . zu arbeiten WifiKanal.
Topologie Helpers
In einem echten Netzwerk finden Sie Hostcomputer mit hinzugefügten (oder integrierten) NICs. In NS-3 we
würde sagen, du wirst fündig Nodes mit angehängtem NetGeräte. In einem großen simulierten Netzwerk
Sie müssen viele Verbindungen zwischen Nodes, NetGeräte und Kanäle.
Seit dem Verbinden NetGeräte zu Nodes, NetGeräte zu Kanäle, Vergabe von IP-Adressen,
usw., sind solche häufigen Aufgaben in NS-3, wir bieten, was wir nennen Topologie Helfer um das zu machen
so einfach wie möglich. Zum Beispiel kann es viele verschiedene dauern NS-3 Kernoperationen zu
Erstellen Sie ein NetDevice, fügen Sie eine MAC-Adresse hinzu, installieren Sie dieses NetDevice auf einem Knoten, konfigurieren Sie die
den Protokollstapel des Knotens und verbinden Sie dann die NetDevice zum Kanal. Noch mehr Operationen
wäre erforderlich, um mehrere Geräte mit Mehrpunktkanälen zu verbinden und dann zu verbinden
einzelne Netzwerke zu Internetworks zusammen. Wir bieten Topologie-Hilfsobjekte, die
Kombinieren Sie diese vielen verschiedenen Operationen zu einem einfach zu bedienenden Modell für Ihre Bequemlichkeit.
A Vorname NS-3 Skript
Wenn Sie das System wie oben vorgeschlagen heruntergeladen haben, erhalten Sie eine Version von NS-3 in einem
Verzeichnis aufgerufen repos unter Ihrem Home-Verzeichnis. Wechseln Sie in dieses Release-Verzeichnis und
Sie sollten eine Verzeichnisstruktur wie die folgende finden:
AUTOREN Beispiele scratch utils waf.bat*
Bindungen LIZENZ src utils.py waf-tools
Erstellen Sie ns3 test.py* utils.pyc wscript
ÄNDERUNGEN.html README testpy-Ausgabe VERSION wutils.py
doc RELEASE_NOTES testpy.supp waf* wutils.pyc
Wechseln Sie in die Beispiele/Tutorial Verzeichnis. Sie sollten eine Datei namens . sehen zuerst.cc located
dort. Dies ist ein Skript, das eine einfache Punkt-zu-Punkt-Verbindung zwischen zwei Knoten erstellt
und Echo eines einzelnen Pakets zwischen den Knoten. Werfen wir einen Blick auf diese Skriptzeile von
Linie, also mach weiter und öffne zuerst.cc in Ihrem Lieblingseditor.
Kesselplatte
Die erste Zeile in der Datei ist eine Emacs-Moduszeile. Dies informiert emacs über die Formatierung
Konventionen (Codierungsstil), die wir in unserem Quellcode verwenden.
/* -*- Modus:C++; c-Dateistil:"gnu"; einrücken-tabs-modus:nil; -*- */
Das ist immer ein etwas kontroverses Thema, also können wir es auch gleich aus dem Weg räumen
sofort. Das NS-3 Projekt hat, wie die meisten großen Projekte, einen Codierungsstil angenommen, um
die der gesamte beigesteuerte Code einhalten muss. Wenn Sie Ihren Code zum . beitragen möchten
Projekts müssen Sie sich schließlich an die NS-3 Codierungsstandard wie in . beschrieben
die Datei doc/codingstd.txt oder auf der Projektwebseite gezeigt HIER.
Wir empfehlen Ihnen, sich einfach an das Aussehen und die Haptik von zu gewöhnen NS-3 codieren und annehmen
diesen Standard immer dann, wenn Sie mit unserem Code arbeiten. Das gesamte Entwicklungsteam und
Mitwirkende haben dies mit unterschiedlichem Murren getan. Die emacs-Moduszeile oben
erleichtert die korrekte Formatierung, wenn Sie den emacs-Editor verwenden.
Die NS-3 Simulator ist unter der GNU General Public License lizenziert. Sie werden sehen,
entsprechende GNU-Rechtssprache am Anfang jeder Datei im NS-3 Verteilung. Oft bist du
wird einen Copyright-Vermerk für eine der an der beteiligten Institutionen sehen NS-3 Projekt oben
den GPL-Text und einen unten aufgeführten Autor.
/*
* Dieses Programm ist freie Software; Sie können es weitergeben und/oder ändern
* es unter den Bedingungen der GNU General Public License Version 2 als
* veröffentlicht von der Free Software Foundation;
*
* Dieses Programm wird in der Hoffnung verteilt, dass es nützlich ist,
* jedoch OHNE JEGLICHE GARANTIE; auch ohne die stillschweigende garantie von
* MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die
* GNU General Public License für weitere Details.
*
* Sie sollten eine Kopie der GNU General Public License erhalten haben
* zusammen mit diesem Programm; wenn nicht, schreiben Sie an die Freie Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
Modul Enthält
Der eigentliche Code beginnt mit einer Reihe von Include-Anweisungen.
#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 High-Level-Skriptbenutzern zu helfen, mit der großen Anzahl von Include-Dateien umzugehen, die in
Das System, das wir gruppieren, umfasst entsprechend relativ große Module. Wir bieten eine Single
include-Datei, die alle in jedem Modul verwendeten Include-Dateien rekursiv lädt.
Anstatt genau nachschlagen zu müssen, welche Kopfzeile Sie benötigen, und möglicherweise eine
Anzahl der Abhängigkeiten richtig, geben wir Ihnen die Möglichkeit, eine große Gruppe von Dateien zu laden
Die Granularität. Dies ist nicht der effizienteste Ansatz, aber es macht sicherlich das Schreiben
Skripte viel einfacher.
Jeder der NS-3 include-Dateien wird in einem Verzeichnis namens . abgelegt ns3 (unter dem Build
Verzeichnis) während des Build-Prozesses, um Kollisionen mit Include-Dateinamen zu vermeiden. Die
ns3/core-module.h Datei entspricht dem ns-3 Modul, das Sie im Verzeichnis finden
Quelle/Kern in Ihrer heruntergeladenen Release-Distribution. Wenn Sie dieses Verzeichnis auflisten, werden Sie
finden Sie eine große Anzahl von Header-Dateien. Wenn Sie einen Build erstellen, platziert Waf einen öffentlichen Header
Dateien in einem ns3 Verzeichnis unter dem entsprechenden bauen/debuggen or bauen/optimiert Verzeichnis
je nach Konfiguration. Waf generiert auch automatisch ein Modul enthalten
file, um alle öffentlichen Header-Dateien zu laden.
Da Sie dieses Tutorial natürlich religiös befolgen, haben Sie es bereits getan
a
$ ./waf -d debug --enable-examples --enable-tests konfigurieren
um das Projekt so zu konfigurieren, dass Debugbuilds ausgeführt werden, die Beispiele und Tests enthalten.
Sie werden auch getan haben
$ ./waf
das Projekt aufzubauen. Also jetzt, wenn du in das Verzeichnis schaust ../../build/debug/ns3 Sie werden
finden Sie die oben gezeigten vier Modul-Include-Dateien. Sie können sich den Inhalt von
diese Dateien und stellen fest, dass sie alle öffentlichen Include-Dateien in ihren
jeweiligen Module.
Ns3 Namespace
Die nächste Zeile im zuerst.cc script ist eine Namespace-Deklaration.
Verwenden des Namensraums ns3;
Die NS-3 Projekt ist in einem C++-Namensraum namens . implementiert ns3. Dies gruppiert alle
NS-3-bezogene Deklarationen in einem Geltungsbereich außerhalb des globalen Namensraums, von denen wir hoffen, dass sie helfen werden
mit Integration mit anderem Code. Das C++ Verwendung von Aussage führt die NS-3 Namensraum
in die aktuelle (globale) deklarative Region. Dies ist eine schicke Art zu sagen, dass nach
Diese Erklärung müssen Sie nicht eingeben ns3:: Bereichsauflösungsoperator vor allen
NS-3 Code, um ihn zu verwenden. Wenn Sie mit Namensräumen nicht vertraut sind, wenden Sie sich bitte an
fast jedes C++-Tutorial und vergleichen Sie die ns3 Namespace und Verwendung hier mit Instanzen der
std Namensraum und die Verwendung von Namensraum Standard; Aussagen, die man oft in Diskussionen findet
of Cout und Ströme.
Protokollierung
Die nächste Zeile des Skripts ist die folgende,
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
Wir werden diese Erklärung als bequemen Ort nutzen, um über unsere Doxygen-Dokumentation zu sprechen
System. Wenn Sie sich die Projektwebsite ansehen, NS-3 Projekt, finden Sie einen Link zu
"Dokumentation" in der Navigationsleiste. Wenn Sie diesen Link auswählen, gelangen Sie zu unserem
Dokumentationsseite. Es gibt einen Link zu "Latest Release", der Sie zum
Dokumentation für die neueste stabile Version von NS-3. Wenn Sie die "API
Dokumentation" gelangen Sie zum NS-3 API-Dokumentationsseite.
Auf der linken Seite finden Sie eine grafische Darstellung des Aufbaus der
Dokumentation. Ein guter Ausgangspunkt ist der NS-3 Module "Buch" in der NS-3 Navigation
Baum. Wenn Sie erweitern Module Sie sehen eine Liste mit NS-3 Moduldokumentation. Die
Das Konzept des Moduls knüpft hier direkt an die oben besprochenen Modul-Include-Dateien an. Die
NS-3 Logging-Subsystem wird in der C + + Konstruiert Gebrauchte by Alle Module Abschnitt, also
Fahren Sie fort und erweitern Sie diesen Dokumentationsknoten. Erweitern Sie nun die Fehlerbeseitigung buchen und dann
wählen Sie die Protokollierung
Sie sollten sich jetzt die Doxygen-Dokumentation für das Logging-Modul ansehen. In dem
Liste der #define's oben auf der Seite sehen Sie den Eintrag für
NS_LOG_COMPONENT_DEFINE. Bevor Sie einsteigen, wäre es wahrscheinlich gut, nach dem zu suchen
"Detaillierte Beschreibung" des Logging-Moduls, um ein Gefühl für die Gesamtbedienung zu bekommen. Du
können Sie entweder nach unten scrollen oder den Link "Mehr..." unter dem Kollaborationsdiagramm auswählen
Dies.
Sobald Sie eine allgemeine Vorstellung davon haben, was vor sich geht, werfen Sie einen Blick auf das Besondere
NS_LOG_COMPONENT_DEFINE Dokumentation. Ich werde die Dokumentation hier nicht duplizieren, aber um
Zusammenfassend deklariert diese Zeile eine Protokollierungskomponente namens Erstes SkriptBeispiel das erlaubt
Sie können die Protokollierung von Konsolennachrichten anhand des Namens aktivieren und deaktivieren.
Main Funktion
Die nächsten Zeilen des Skripts, das Sie finden werden, sind:
int
main (int argc, char *argv[])
{
Dies ist nur die Deklaration der Hauptfunktion Ihres Programms (Skripts). Genau wie in
In jedem C++-Programm müssen Sie eine Hauptfunktion definieren, die als erste Funktion ausgeführt wird.
Hier gibt es gar nichts besonderes. Ihre NS-3 script ist nur ein C++-Programm.
Die nächste Zeile stellt die Zeitauflösung auf eine Nanosekunde ein, was zufällig die Standardeinstellung ist
Wert:
Time::SetResolution (Time::NS);
Die Auflösung ist der kleinste darstellbare Zeitwert (sowie der kleinste
darstellbare Differenz zwischen zwei Zeitwerten). Sie können die Auflösung genau ändern
wenn. Der Mechanismus, der diese Flexibilität ermöglicht, ist etwas speicherhungrig
Auflösung explizit gesetzt wurde geben wir den Speicher frei und verhindern so weitere Updates.
(Wenn Sie die Auflösung nicht explizit einstellen, wird sie standardmäßig auf eine Nanosekunde eingestellt, und die
Speicher wird freigegeben, wenn die Simulation startet.)
Die nächsten beiden Zeilen des Skripts werden verwendet, um zwei erstellte Protokollierungskomponenten zu aktivieren
in die Echo Client- und Echo Server-Anwendungen:
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
Wenn Sie die Dokumentation der Protokollierungskomponente gelesen haben, werden Sie feststellen, dass dort
sind eine Reihe von Ebenen der Ausführlichkeit/Details der Protokollierung, die Sie für jede Komponente aktivieren können.
Diese beiden Codezeilen ermöglichen die Debug-Protokollierung auf der INFO-Ebene für Echo-Clients und
Server. Dies führt dazu, dass die Anwendung Nachrichten ausdruckt, wenn Pakete gesendet werden
und während der Simulation empfangen.
Jetzt kommen wir direkt zum Geschäft, eine Topologie zu erstellen und eine Simulation auszuführen.
Wir verwenden die Topologie-Hilfsobjekte, um diese Aufgabe so einfach wie möglich zu gestalten.
Topologie Helpers
NodeContainer
Die nächsten beiden Codezeilen in unserem Skript erstellen tatsächlich die NS-3 Knoten Objekte, die
stellt die Computer in der Simulation dar.
NodeContainer-Knoten;
Knoten.Erstellen (2);
Suchen wir die Dokumentation für die NodeContainer Klasse, bevor es weitergeht. Ein anderer Weg
um in die Dokumentation für eine bestimmte Klasse zu gelangen, erfolgt über die Klassen Registerkarte im Doxygen
Seiten. Wenn Sie das Doxygen noch zur Hand haben, scrollen Sie einfach nach oben auf der Seite und
wählen Sie die Klassen Tab. Sie sollten sehen, dass ein neuer Satz von Registerkarten angezeigt wird, einer davon ist Klasse
Liste. Unter dieser Registerkarte sehen Sie eine Liste aller NS-3 Klassen. Runterscrollen,
Auf der Suche nach ns3::NodeContainer. Wenn Sie die Klasse gefunden haben, fahren Sie fort und wählen Sie sie aus, um zu gehen
die Unterlagen für die Klasse.
Sie erinnern sich vielleicht, dass eine unserer wichtigsten Abstraktionen die Knoten. Dies stellt einen Computer dar
zu denen wir Dinge wie Protokollstapel, Anwendungen und Peripheriegeräte hinzufügen werden
Karten. Die NodeContainer Topology Helper bietet eine bequeme Möglichkeit zum Erstellen, Verwalten und
auf alle zugreifen Knoten Objekte, die wir erstellen, um eine Simulation auszuführen. Die erste Zeile oben
deklariert einfach einen NodeContainer, den wir nennen Fiber Node. Die zweite Zeile ruft die Erstellen
Methode auf der Fiber Node -Objekt und fordert den Container auf, zwei Knoten zu erstellen. Wie beschrieben in
der Doxygen, der Behälter ruft hinunter in die NS-3 richtiges System, um zwei zu erstellen Knoten
Objekte und speichert intern Zeiger auf diese Objekte.
Die Knoten, wie sie im Skript stehen, tun nichts. Der nächste Schritt bei der Konstruktion von a
Topologie besteht darin, unsere Knoten zu einem Netzwerk zu verbinden. Die einfachste Form des Netzwerks wir
Unterstützung ist eine einzelne Punkt-zu-Punkt-Verbindung zwischen zwei Knoten. Wir bauen eine davon
hier verlinkt.
PointToPointHelper
Wir konstruieren eine Punkt-zu-Punkt-Verbindung, und zwar in einem Muster, das ziemlich
Ihnen vertraut ist, verwenden wir ein Topologie-Hilfsobjekt, um die für die Erstellung erforderliche Low-Level-Arbeit zu erledigen
die Verbindung zusammen. Denken Sie daran, dass zwei unserer wichtigsten Abstraktionen die NetDevice und der
Kanal. In der realen Welt entsprechen diese Begriffe ungefähr den peripheren Karten und
Netzwerkkabel. Normalerweise sind diese beiden Dinge eng miteinander verbunden und man kann es nicht
erwarten, zum Beispiel Ethernet-Geräte und drahtlose Kanäle auszutauschen. Unsere Topologie
Helfer folgen dieser innigen Kopplung und daher werden Sie eine einzige verwenden
PointToPointHelper konfigurieren und verbinden NS-3 PointToPointNetDevice und
PunktzuPunktKanal Objekte in diesem Skript.
Die nächsten drei Zeilen im Skript sind:
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
Die erste Zeile,
PointToPointHelper pointToPoint;
instanziiert a PointToPointHelper Objekt auf dem Stapel. Aus einer hochrangigen Perspektive ist die
nächste Zeile,
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
erzählt die PointToPointHelper den Wert "5Mbps" (fünf Megabit pro Sekunde) als
die "DataRate", wenn es erstellt a PointToPointNetDevice Objekt.
Aus einer genaueren Perspektive entspricht die Zeichenfolge "DataRate" dem, was wir an . nennen
Attribut dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog. PointToPointNetDevice. Wenn du dir den Doxygen für den Unterricht ansiehst
ns3::PointToPointNetDevice und finden Sie die Dokumentation für die GetTypeId Methode, du wirst
finden Sie eine Liste von Attribute für das Gerät definiert. Darunter ist die "DataRate"
Attribut. Für den Benutzer am besten sichtbar NS-3 Objekte haben ähnliche Listen von Attribute. Wir verwenden das
Mechanismus zum einfachen Konfigurieren von Simulationen ohne Neukompilierung, wie Sie in a . sehen werden
folgenden Abschnitt.
Ähnlich wie die "DataRate" auf der PointToPointNetDevice Sie finden eine "Verzögerung" Attribut
in Verbindung mit PunktzuPunktKanal. Die letzte Zeile,
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
erzählt die PointToPointHelper den Wert "2ms" (zwei Millisekunden) als Wert des
Übertragungsverzögerung jedes Punkt-zu-Punkt-Kanals, den es anschließend erzeugt.
NetDeviceContainer
An dieser Stelle im Skript haben wir a NodeContainer die zwei Knoten enthält. Wir haben ein
PointToPointHelper das ist grundiert und fertig PointToPointNetGeräte und Draht
PunktzuPunktKanal Gegenstände dazwischen. So wie wir es benutzt haben NodeContainer Topologie
Hilfsobjekt zum Erstellen der Nodes für unsere Simulation fragen wir die PointToPointHelper
um die Arbeiten zur Erstellung, Konfiguration und Installation unserer Geräte für uns zu erledigen. Wir
benötigen eine Liste aller erstellten NetDevice-Objekte, daher verwenden wir a
NetDeviceContainer, um sie zu halten, so wie wir einen NodeContainer verwendet haben, um die Knoten zu halten, die wir
erstellt. Die folgenden zwei Codezeilen,
NetDeviceContainer-Geräte;
Geräte = pointToPoint.Install (Knoten);
beendet die Konfiguration der Geräte und des Kanals. Die erste Zeile deklariert das Gerät
der oben erwähnte Container und der zweite übernimmt das schwere Heben. Die Installieren Methode von
PointToPointHelper nimmt ein NodeContainer als Parameter. Intern, a
NetDeviceContainer geschaffen. Für jeden Knoten im NodeContainer (es muss genau sein
zwei für eine Punkt-zu-Punkt-Verbindung) a PointToPointNetDevice wird im Gerät erstellt und gespeichert
Container. EIN PunktzuPunktKanal entsteht und die beiden PointToPointNetGeräte sind
befestigt. Wenn Objekte von der . erstellt werden PointToPointHelper, der Attribute vorher
set im Helfer werden verwendet, um die entsprechenden Attribute im erstellten
Objekte.
Nach der Ausführung des pointToPoint.Install (Knoten) call haben wir zwei Knoten mit jeweils einem
installierten Punkt-zu-Punkt-Netzgerät und einem einzelnen Punkt-zu-Punkt-Kanal zwischen ihnen.
Beide Geräte werden so konfiguriert, dass sie Daten mit fünf Megabit pro Sekunde über die
Kanal, der eine Übertragungsverzögerung von zwei Millisekunden hat.
InternetStackHelper
Wir haben jetzt Knoten und Geräte konfiguriert, aber keine Protokollstapel installiert
auf unseren Knoten. Dafür sorgen die nächsten beiden Codezeilen.
InternetStackHelper-Stack;
stack.Install (Knoten);
Die InternetStackHelper ist ein Topologie-Helfer, der für Internet-Stacks das ist, was die
PointToPointHelper ist auf Punkt-zu-Punkt-Netzgeräte. Die Installieren Methode dauert a
NodeContainer als Parameter. Wenn es ausgeführt wird, wird ein Internet Stack installiert
(TCP, UDP, IP usw.) auf jedem der Knoten im Knotencontainer.
IPv4AddressHelper
Als nächstes müssen wir die Geräte auf unseren Knoten mit IP-Adressen verknüpfen. Wir bieten eine
Topologie-Helfer, um die Zuweisung von IP-Adressen zu verwalten. Die einzige für den Benutzer sichtbare API ist zu
Stellen Sie die Basis-IP-Adresse und die Netzwerkmaske ein, die beim Ausführen der tatsächlichen Adresse verwendet werden sollen
Zuweisung (die auf einer niedrigeren Ebene innerhalb des Helfers erfolgt).
Die nächsten beiden Codezeilen in unserem Beispielskript, zuerst.cc,
IPv4AddressHelper-Adresse;
address.SetBase ("10.1.1.0", "255.255.255.0");
deklarieren Sie ein Adresshilfsobjekt und teilen Sie ihm mit, dass es mit der Zuweisung von IP-Adressen beginnen soll
aus dem Netzwerk 10.1.1.0 unter Verwendung der Maske 255.255.255.0, um die zuordenbaren Bits zu definieren. Von
Standardmäßig beginnen die zugewiesenen Adressen bei eins und steigen monoton an, also die erste
Die von dieser Basis zugewiesene Adresse ist 10.1.1.1, gefolgt von 10.1.1.2 usw. Der niedrige
Grad des NS-3 System merkt sich tatsächlich alle zugewiesenen IP-Adressen und generiert eine
schwerwiegender Fehler, wenn Sie versehentlich die gleiche Adresse zweimal generieren lassen (was a
übrigens sehr schwer zu debuggen).
Die nächste Codezeile,
Ipv4InterfaceContainer-Schnittstellen = address.Assign (Geräte);
führt die eigentliche Adressvergabe durch. In NS-3 wir machen die Assoziation zwischen einem IP
Adresse und ein Gerät mit einem IPv4-Schnittstelle Objekt. So wie wir manchmal eine Liste von
net-Geräte, die von einem Helfer für zukünftige Referenzen erstellt wurden, benötigen wir manchmal eine Liste von
IPv4-Schnittstelle Objekte. Das IPv4InterfaceContainer bietet diese Funktionalität.
Jetzt haben wir ein Punkt-zu-Punkt-Netzwerk aufgebaut, mit installierten Stacks und IP-Adressen
zugewiesen. Was wir an dieser Stelle brauchen, sind Anwendungen, um Traffic zu generieren.
Anwendungen
Eine weitere der Kernabstraktionen des ns-3-Systems ist die Anwendungs-. In diesem
Skript verwenden wir zwei Spezialisierungen des Kerns NS-3 Klasse Anwendungs- namens
UdpEchoServer-Anwendung und UdpEchoClient-Anwendung. Genauso wie in unserem vorherigen
Erläuterungen verwenden wir Hilfsobjekte, um die zugrunde liegenden Objekte zu konfigurieren und zu verwalten.
Hier verwenden wir UdpEchoServerHelper und UdpEchoClientHelper Gegenstände, die unser Leben erleichtern.
UdpEchoServerHelper
Die folgenden Codezeilen in unserem Beispielskript, zuerst.cc, werden verwendet, um ein UDP-Echo einzurichten
Serveranwendung auf einem der zuvor erstellten Knoten.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Sekunden (1.0));
serverApps.Stop (Sekunden (10.0));
Die erste Codezeile im obigen Ausschnitt deklariert die UdpEchoServerHelper. Wie gewöhnlich,
Dies ist nicht die Anwendung selbst, sondern ein Objekt, das uns bei der Erstellung des tatsächlichen hilft
Anwendungen. Eine unserer Konventionen ist es, falls angefordert Attribute im Helfer
Konstrukteur. In diesem Fall kann der Helfer nichts Nützliches tun, es sei denn, er wird mit bereitgestellt
eine Portnummer, die auch dem Client bekannt ist. Anstatt nur einen auszuwählen und zu hoffen
alles klappt, wir benötigen die Portnummer als Parameter für den Konstruktor. Die
Konstruktor wiederum macht einfach a SetAttribute mit dem übergebenen Wert. Wenn du willst
kann den "Port" einstellen Attribut auf einen anderen Wert später mit SetAttribute.
Ähnlich wie bei vielen anderen Hilfsobjekten ist das UdpEchoServerHelper Objekt hat eine Installieren
Methode. Es ist die Ausführung dieser Methode, die tatsächlich das zugrunde liegende Echo verursacht
Serveranwendung, die instanziiert und an einen Knoten angehängt werden soll. Interessanterweise ist die Installieren
Methode dauert a KnotenContainer als Parameter genauso wie der andere Installieren Methoden die wir haben
gesehen. Dies wird tatsächlich an die Methode übergeben, auch wenn es nicht so aussieht
dieser Fall. Es gibt ein C++ implizit Umwandlung bei der Arbeit hier, die das Ergebnis von
Knoten.Get (1) (was einen intelligenten Zeiger auf ein Knotenobjekt zurückgibt --- Ptr) und nutzt das
in einem Konstruktor für ein unbenanntes NodeContainer das wird dann weitergegeben an Installieren. Wenn Sie
immer in Verlegenheit, eine bestimmte Methodensignatur in C++-Code zu finden, die kompiliert und ausgeführt wird
gut, suchen Sie nach diesen Arten von impliziten Konvertierungen.
Das sehen wir jetzt echoServer.Install wird installieren a UdpEchoServer-Anwendung auf die
Knoten gefunden bei Index Nummer eins der NodeContainer Früher haben wir unsere Knoten verwaltet. Installieren
gibt einen Container zurück, der Zeiger auf alle Anwendungen enthält (in diesem Fall eine
seit wir vorbeigekommen sind NodeContainer mit einem Knoten) vom Helfer erstellt.
Anwendungen benötigen eine gewisse Zeit, um mit der Generierung von Datenverkehr zu beginnen, und es kann eine optionale Zeit dauern, bis sie
"halt". Wir bieten beides. Diese Zeiten werden mit dem Anwendungscontainer Methoden
Startseite und Stoppen. Diese Methoden nehmen Uhrzeit Parameter. In diesem Fall verwenden wir ein explizit C + +
Konvertierungssequenz, um das C++ Double 1.0 zu nehmen und in ein zu konvertieren NS-3 Uhrzeit Objekt mit
a Sekunden werfen. Beachten Sie, dass die Konvertierungsregeln möglicherweise vom Modellautor gesteuert werden.
und C++ hat seine eigenen Regeln, daher kann man nicht immer einfach davon ausgehen, dass Parameter glücklich sein werden
für Sie umgebaut. Die beiden Zeilen,
serverApps.Start (Sekunden (1.0));
serverApps.Stop (Sekunden (10.0));
bewirkt, dass die Echo-Serveranwendung Startseite (aktiviert sich) in einer Sekunde in die
Simulation und zu Stoppen (sich selbst deaktivieren) nach zehn Sekunden in der Simulation. Aufgrund
die Tatsache, dass wir ein Simulationsereignis (das Anwendungsstoppereignis) als
nach zehn Sekunden ausgeführt, dauert die Simulation at am wenigsten zehn Sekunden.
UdpEchoClientHelper
Die Echo-Client-Anwendung wird in einer Methode eingerichtet, die im Wesentlichen der für die
Server. Es gibt einen zugrunde liegenden UdpEchoClient-Anwendung das wird von einem verwaltet
UdpEchoClientHelper.
UdpEchoClientHelper echoClient (Schnittstellen.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Sekunden (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (nodes.Get (0));
clientApps.Start (Sekunden (2.0));
clientApps.Stop (Sekunden (10.0));
Für den Echo-Client müssen wir jedoch fünf verschiedene einstellen Attribute. Die ersten beiden
Attribute werden während des Baus der UdpEchoClientHelper. Wir übergeben Parameter
die (intern zum Helfer) verwendet werden, um die "RemoteAddress" und "RemotePort" zu setzen
Attribute in Übereinstimmung mit unserer Konvention erforderlich zu machen Attribute Parameter in der
Helfer Konstrukteure.
Denken Sie daran, dass wir ein verwendet haben IPv4InterfaceContainer um die IP-Adressen zu verfolgen, die wir
unseren Geräten zugeordnet. Die nullte Schnittstelle im Schnittstellen Behälter wird
entsprechen der IP-Adresse des nullten Knotens im Fiber Node Container. Der erste
Schnittstelle im Schnittstellen container entspricht der IP-Adresse des ersten Knotens in
Fiber Node Container. In der ersten Codezeile (von oben) erstellen wir also die
Helfer und teilen Sie ihm mit, dass die Remote-Adresse des Clients die IP-Adresse ist
dem Knoten zugewiesen, auf dem sich der Server befindet. Wir sagen es auch, um den Versand zu arrangieren
Pakete an Port neun.
Die "MaxPackets" Attribut teilt dem Client die maximale Anzahl von Paketen mit, die wir ihm erlauben
während der Simulation senden. Das Intervall" Attribut sagt dem Kunden, wie lange er warten soll
zwischen Paketen und die "PacketSize" Attribut teilt dem Client mit, wie groß sein Paket ist
Nutzlasten sein sollten. Mit dieser besonderen Kombination aus Attribute, wir sagen dem
Client, um ein 1024-Byte-Paket zu senden.
Genau wie beim Echo-Server weisen wir den Echo-Client an Startseite und Stoppen, Aber
hier starten wir den Client eine Sekunde nachdem der Server aktiviert wurde (nach zwei Sekunden im
Simulation).
Simulator
An dieser Stelle müssen wir die Simulation tatsächlich ausführen. Dies geschieht mit
die globale Funktion Simulator::Ausführen.
Simulator::Run ();
Als wir zuvor die Methoden aufgerufen haben,
serverApps.Start (Sekunden (1.0));
serverApps.Stop (Sekunden (10.0));
...
clientApps.Start (Sekunden (2.0));
clientApps.Stop (Sekunden (10.0));
Wir haben tatsächlich Ereignisse im Simulator mit 1.0 Sekunden, 2.0 Sekunden und zwei Ereignissen geplant
bei 10.0 Sekunden. Wann Simulator::Ausführen aufgerufen wird, beginnt das System mit der Suche durch die
Liste der geplanten Ereignisse und deren Ausführung. Zuerst wird das Ereignis mit 1.0 Sekunden ausgeführt,
wodurch die Echo-Server-Anwendung aktiviert wird (dieses Ereignis kann wiederum viele
Andere Ereignisse). Dann wird das für t = 2.0 Sekunden geplante Ereignis ausgeführt, das gestartet wird
die Echo-Client-Anwendung. Auch dieses Ereignis kann viele weitere Ereignisse planen. Der Beginn
Event-Implementierung in der Echo-Client-Anwendung beginnt die Datenübertragungsphase von
die Simulation durch Senden eines Pakets an den Server.
Das Senden des Pakets an den Server löst eine Kette von Ereignissen aus, die
automatisch hinter den Kulissen geplant und die Mechanik des
Paketecho gemäß den verschiedenen Timing-Parametern, die wir im Skript festgelegt haben.
Da wir schließlich nur ein Paket senden (erinnern Sie sich an die MaxPakete Attribut wurde auf
one), wird die Kette von Ereignissen, die durch diese einzelne Client-Echo-Anforderung ausgelöst wird, auslaufen und
die Simulation geht in den Leerlauf. Sobald dies geschieht, werden die verbleibenden Ereignisse die Stoppen
Ereignisse für den Server und den Client. Wenn diese Ereignisse ausgeführt werden, gibt es keine
weitere Ereignisse zu bearbeiten und Simulator::Ausführen kehrt zurück. Die Simulation ist dann abgeschlossen.
Bleibt nur noch aufzuräumen. Dies geschieht durch den Aufruf der globalen Funktion
Simulator::Zerstören. Da die Helferfunktionen (oder niedrige Ebene NS-3 Code) ausgeführt, sie
ordnete es so an, dass Haken in den Simulator eingefügt wurden, um alle Objekte zu zerstören
die erstellt wurden. Sie mussten keines dieser Objekte selbst verfolgen ---
alles was du tun musstest war anzurufen Simulator::Zerstören und Ausfahrt. Die NS-3 System hat sich darum gekümmert
der schwierige Teil für dich. Die restlichen Zeilen unseres ersten NS-3 Skript, zuerst.cc, mach einfach
dass:
Simulator::Zerstören ();
Rückkehr 0;
}
Wann Simulator werden wir halt?
NS-3 ist ein Discrete Event (DE) Simulator. In einem solchen Simulator ist jedes Ereignis zugeordnet
mit seiner Ausführungszeit, und die Simulation fährt mit der Ausführung von Ereignissen im zeitlichen
Reihenfolge der Simulationszeit. Ereignisse können dazu führen, dass zukünftige Ereignisse geplant werden (z. B. a
Timer kann sich selbst neu planen, um im nächsten Intervall abzulaufen).
Die ersten Ereignisse werden normalerweise von jedem Objekt ausgelöst, z. B. plant IPv6 Router
Ankündigungen, Anfragen von Nachbarn usw., eine Anwendung planen das erste Paket
Sendeereignis usw.
Wenn ein Ereignis verarbeitet wird, kann es null, ein oder mehrere Ereignisse generieren. Als Simulation
ausgeführt wird, werden Ereignisse konsumiert, aber es können (oder auch nicht) mehr Ereignisse generiert werden. Die
Die Simulation stoppt automatisch, wenn sich keine weiteren Ereignisse in der Ereigniswarteschlange befinden oder wenn
ein spezielles Stop-Ereignis wird gefunden. Das Stop-Ereignis wird durch die Simulator::Stopp
(StoppZeit); Funktion.
Es gibt einen typischen Fall, in dem Simulator::Stopp ist unbedingt notwendig, um die
Simulation: wenn ein sich selbst tragendes Ereignis vorliegt. Selbsttragende (oder wiederkehrende) Ereignisse
sind Veranstaltungen, die sich immer wieder neu planen. Als Konsequenz behalten sie immer die Veranstaltung
Warteschlange nicht leer.
Es gibt viele Protokolle und Module mit wiederkehrenden Ereignissen, zB:
· FlowMonitor - regelmäßige Überprüfung auf verlorene Pakete
· RIPng - periodische Übertragung von Routing-Tabellen-Updates
· usw.
In diesen Fällen, Simulator::Stopp ist notwendig, um die Simulation ordnungsgemäß zu stoppen. In
zusätzlich, wenn NS-3 befindet sich im Emulationsmodus, der Echtzeit-Simulator wird verwendet, um die
Simulationsuhr auf Maschinenuhr ausgerichtet und Simulator::Stopp ist notwendig zu stoppen
der Prozess.
Viele der Simulationsprogramme im Tutorial rufen nicht explizit auf Simulator::Stopp,
da der Ereigniswarteschlange automatisch die Ereignisse ausgehen. Diese Programme werden jedoch
auch einen Anruf annehmen an Simulator::Stopp. Zum Beispiel die folgende zusätzliche Anweisung in
das erste Beispielprogramm plant einen expliziten Stopp nach 11 Sekunden:
+ Simulator::Stop (Sekunden (11.0));
Simulator::Run ();
Simulator::Zerstören ();
Rückkehr 0;
}
Das Obige wird das Verhalten dieses Programms nicht wirklich ändern, da dies insbesondere
Simulation endet natürlich nach 10 Sekunden. Aber wenn Sie die Stoppzeit ändern würden in
die obige Aussage von 11 Sekunden auf 1 Sekunde, würden Sie feststellen, dass die Simulation
stoppt, bevor eine Ausgabe auf dem Bildschirm gedruckt wird (da die Ausgabe um die Zeit 2 . erfolgt
Sekunden Simulationszeit).
Es ist wichtig anzurufen Simulator::Stopp bevor Aufruf Simulator::Ausführen;; Andernfalls,
Simulator::Ausführen darf niemals die Kontrolle an das Hauptprogramm zurückgeben, um den Stopp auszuführen!
zum Sie Skript
Wir haben es einfach gemacht, Ihre einfachen Skripte zu erstellen. Alles, was Sie tun müssen, ist, Ihre fallen zu lassen
script in das Scratch-Verzeichnis und es wird automatisch erstellt, wenn Sie Waf ausführen.
Lass es uns versuchen. Kopieren Beispiele/Tutorial/first.cc in die kratzen Verzeichnis nach Änderung
zurück in das Verzeichnis der obersten Ebene.
$CD ../ ..
$ cp Beispiele/Tutorial/first.cc scratch/myfirst.cc
Erstellen Sie nun Ihr erstes Beispielskript mit waf:
$ ./waf
Sie sollten Meldungen sehen, dass Ihr mein erstes Beispiel wurde erfolgreich gebaut.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
[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: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (2.357s)
Sie können nun das Beispiel ausführen (beachten Sie, dass wenn Sie Ihr Programm im Scratch-Verzeichnis erstellen
Sie müssen es aus dem Scratch-Verzeichnis heraus ausführen):
$ ./waf --run scratch/myfirst
Sie sollten eine Ausgabe sehen:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.418s)
Gesendet 1024 Byte an 10.1.1.2
1024 Bytes von 10.1.1.1 erhalten
1024 Bytes von 10.1.1.2 erhalten
Hier sehen Sie, dass das Build-System überprüft, ob die Datei erstellt wurde und
dann läuft es. Sie sehen, dass die Protokollierungskomponente auf dem Echo-Client anzeigt, dass sie gesendet hat
ein 1024-Byte-Paket an den Echo-Server am 10.1.1.2. Sie sehen auch die Protokollierungskomponente
auf dem Echoserver sagen, dass er die 1024 Bytes von 10.1.1.1 erhalten hat. Der Echo-Server
gibt das Paket lautlos zurück und Sie sehen im Echo-Client-Protokoll, dass es sein Paket empfangen hat
vom Server zurück.
NS-3 Quelle Code
Nachdem Sie nun einige der NS-3 Helfer, die Sie sich vielleicht mal ansehen möchten
Quellcode, der diese Funktionalität implementiert. Der neueste Code kann auf durchgeblättert werden
unseren Webserver unter folgendem Link: http://code.nsnam.org/ns-3-dev. Dort siehst du
die Mercurial-Übersichtsseite für unsere NS-3 Entwicklungsbaum.
Oben auf der Seite sehen Sie eine Reihe von Links,
Zusammenfassung | Shortlog | Änderungsprotokoll | Grafik | Tags | Dateien
Fahren Sie fort und wählen Sie die Dateien Verknüpfung. Das ist die oberste Ebene der meisten unserer
Repositories aussehen wird:
drwxr-xr-x [nach oben]
drwxr-xr-x Bindungen Python-Dateien
drwxr-xr-x doc-Dateien
drwxr-xr-x Beispieldateien
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 | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 1886 .hgtags-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 1276 AUTOREN Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 17987 LIZENZdatei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 3742 README-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 6 VERSION Datei | Überarbeitungen | kommentieren
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 waf-Datei | Überarbeitungen | kommentieren
-rwxr-xr-x 2009-07-01 12:47 +0200 28 waf.bat-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 35395 wscript-Datei | Überarbeitungen | kommentieren
-rw-r--r-- 2009-07-01 12:47 +0200 7673 wutils.py-Datei | Überarbeitungen | kommentieren
Unsere Beispielskripte befinden sich im Beispiele Verzeichnis. Wenn Sie auf klicken Beispiele Sie werden sehen,
eine Liste von Unterverzeichnissen. Eine der Dateien in Lernprogramm Unterverzeichnis ist zuerst.cczu buchen. Wenn Sie
Klicken Sie auf zuerst.cc Sie finden den Code, den Sie gerade durchlaufen haben.
Der Quellcode befindet sich hauptsächlich im src Verzeichnis. Sie können den Quellcode entweder anzeigen, indem Sie
Klicken Sie auf den Verzeichnisnamen oder klicken Sie auf das Dateien Link rechts vom
Verzeichnisname. Wenn Sie auf klicken src Verzeichnis, Sie werden zur Liste der
src Unterverzeichnisse. Wenn Sie dann auf klicken Core Unterverzeichnis finden Sie eine Liste mit
Dateien. Die erste Datei, die Sie (zum jetzigen Zeitpunkt) finden, ist abbrechen.h. Wenn Sie auf die Schaltfläche klicken
abbrechen.h Link, Sie werden zur Quelldatei für weitergeleitet abbrechen.h die nützliche Makros enthält
zum Beenden von Skripten, wenn anormale Bedingungen erkannt werden.
Den Quellcode für die Helfer, die wir in diesem Kapitel verwendet haben, finden Sie im
src/Anwendungen/Helfer Verzeichnis. Fühlen Sie sich frei, im Verzeichnisbaum herumzustöbern, um
ein Gespür für das, was da ist und den Stil von NS-3 Programme.
ZWISCHEN
Die richtigen Protokollierung Modul
Wir haben bereits einen kurzen Blick auf die NS-3 Logging-Modul beim Überfahren der
zuerst.cc Skript. Wir werden nun genauer hinschauen und sehen, welche Art von Anwendungsfällen die
Logging-Subsystem wurde entwickelt, um abzudecken.
Protokollierung Übersicht
Viele große Systeme unterstützen eine Art von Nachrichtenprotokollierungsfunktion, und NS-3 ist kein
Ausnahme. In einigen Fällen werden nur Fehlermeldungen an der "Bedienkonsole" protokolliert (die
ist typisch stderr in Unix-basierten Systemen). In anderen Systemen können Warnmeldungen
Ausgabe sowie ausführlichere Informationsmeldungen. In einigen Fällen sind Protokollierungseinrichtungen
werden verwendet, um Debug-Meldungen auszugeben, die die Ausgabe schnell in eine Unschärfe verwandeln können.
NS-3 ist der Ansicht, dass alle diese Ausführlichkeitsstufen nützlich sind, und wir bieten eine
wählbarer, mehrstufiger Ansatz zur Nachrichtenprotokollierung. Die Protokollierung kann komplett deaktiviert werden,
Komponente für Komponente aktiviert oder global aktiviert; und es bietet wählbare
Ausführlichkeitsstufen. Die NS-3 log-Modul bietet eine unkomplizierte, relativ einfach zu bedienende
Möglichkeit, nützliche Informationen aus Ihrer Simulation zu gewinnen.
Sie sollten verstehen, dass wir einen Allzweckmechanismus bereitstellen --- Tracing --- to
Holen Sie Daten aus Ihren Modellen, die für die Simulationsausgabe bevorzugt werden sollen (siehe die
Tutorial-Abschnitt Verwenden des Tracing-Systems für weitere Details zu unserem Tracing-System).
Die Protokollierung sollte zum Debuggen von Informationen, Warnungen, Fehlermeldungen usw. bevorzugt werden
wenn Sie schnell eine Nachricht aus Ihren Skripten oder Modellen erhalten möchten.
Es gibt derzeit sieben Ebenen von Protokollnachrichten mit zunehmender Ausführlichkeit, die in der definiert sind
System funktionieren.
· LOG_ERROR --- Fehlermeldungen protokollieren (zugehöriges Makro: NS_LOG_ERROR);
· LOG_WARN --- Warnmeldungen protokollieren (zugehöriges Makro: NS_LOG_WARN);
· LOG_DEBUG --- Protokolliert relativ seltene Ad-hoc-Debugging-Meldungen (zugehöriges Makro:
NS_LOG_DEBUG);
· LOG_INFO --- Informationsmeldungen über den Programmfortschritt protokollieren (zugehöriges Makro:
NS_LOG_INFO);
· LOG_FUNCTION --- Protokolliert eine Nachricht, die jede aufgerufene Funktion beschreibt (zwei zugehörige Makros:
NS_LOG_FUNCTION, verwendet für Memberfunktionen und NS_LOG_FUNCTION_NOARGS, verwendet für statische
Funktionen);
· LOG_LOGIC -- Protokollnachrichten, die den logischen Fluss innerhalb einer Funktion beschreiben (zugehöriges Makro:
NS_LOG_LOGIC);
· LOG_ALL --- Alles oben Erwähnte protokollieren (kein zugehöriges Makro).
Für jeden LOG_TYPE gibt es auch LOG_LEVEL_TYPE, der bei Verwendung die Protokollierung aller
Ebenen darüber zusätzlich zu seiner Ebene. (Als Folge davon werden LOG_ERROR und
LOG_LEVEL_ERROR und auch LOG_ALL und LOG_LEVEL_ALL sind funktional äquivalent.) Für
Wenn Sie beispielsweise LOG_INFO aktivieren, werden nur Nachrichten aktiviert, die vom NS_LOG_INFO-Makro bereitgestellt werden, während
Durch Aktivieren von LOG_LEVEL_INFO werden auch Nachrichten aktiviert, die von NS_LOG_DEBUG, NS_LOG_WARN bereitgestellt werden
und NS_LOG_ERROR-Makros.
Wir bieten auch ein bedingungsloses Logging-Makro, das immer angezeigt wird, unabhängig von
Protokollierungsebenen oder Komponentenauswahl.
· NS_LOG_UNCOND -- Die zugehörige Nachricht bedingungslos protokollieren (keine zugehörige Protokollebene).
Jede Stufe kann einzeln oder kumulativ angefordert werden; und Protokollierung können mit a . eingerichtet werden
Shell-Umgebungsvariable (NS_LOG) oder durch Protokollieren des Systemfunktionsaufrufs. Wie gesehen wurde
weiter oben im Tutorial hat das Logging-System eine Doxygen-Dokumentation und wäre jetzt a
Es ist an der Zeit, die Dokumentation des Protokollierungsmoduls zu lesen, falls Sie dies noch nicht getan haben.
Nachdem Sie die Dokumentation nun ausführlich gelesen haben, lassen Sie uns etwas von diesem Wissen nutzen
um einige interessante Informationen aus der scratch/myfirst.cc Beispielskript hast du
schon gebaut.
Der Weg zu Protokollierung
Lassen Sie uns die Umgebungsvariable NS_LOG verwenden, um mehr Protokollierung zu aktivieren, aber zuerst nur um
Orientieren Sie sich, fahren Sie fort und führen Sie das letzte Skript wie zuvor aus,
$ ./waf --run scratch/myfirst
Sie sollten die jetzt bekannte Ausgabe des ersten sehen NS-3 Beispielprogramm
$ Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.413s)
Gesendet 1024 Byte an 10.1.1.2
1024 Bytes von 10.1.1.1 erhalten
1024 Bytes von 10.1.1.2 erhalten
Es stellt sich heraus, dass die oben angezeigten Nachrichten "Gesendet" und "Empfangen" tatsächlich protokolliert werden
Nachrichten von der UdpEchoClient-Anwendung und UdpEchoServer-Anwendung. Wir können das fragen
Client-Anwendung, um beispielsweise mehr Informationen zu drucken, indem Sie ihre Protokollierungsstufe festlegen
über die Umgebungsvariable NS_LOG.
Ich gehe von nun an davon aus, dass Sie eine sh-ähnliche Shell verwenden, die verwendet
die Syntax "VARIABLE=Wert". Wenn Sie eine csh-ähnliche Shell verwenden, müssen Sie
Konvertieren Sie meine Beispiele in die Syntax "setenv VARIABLE value", die von diesen Shells benötigt wird.
Im Moment antwortet die UDP-Echo-Client-Anwendung auf die folgende Codezeile in
scratch/myfirst.cc,
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
Diese Codezeile ermöglicht die LOG_LEVEL_INFO Protokollierungsebene. Wenn wir eine Protokollierung bestehen
Level-Flag, aktivieren wir tatsächlich das angegebene Level und alle niedrigeren Level. In diesem Fall,
wir haben aktiviert NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN und NS_LOG_ERROR. Wir können steigern
die Protokollierungsebene und erhalten Sie weitere Informationen, ohne das Skript zu ändern und neu zu kompilieren, indem Sie
Setzen Sie die Umgebungsvariable NS_LOG wie folgt:
$ export NS_LOG=UdpEchoClientApplication=level_all
Dies setzt die Shell-Umgebungsvariable NS_LOG zur Saite,
UdpEchoClientApplication=level_all
Die linke Seite der Zuweisung ist der Name der Protokollierungskomponente, die wir setzen möchten.
und die rechte Seite ist die Flagge, die wir verwenden möchten. In diesem Fall schalten wir ein
alle Debugging-Ebenen für die Anwendung. Wenn Sie das Skript mit NS_LOG-Set ausführen
auf diese Weise, die NS-3 Das Protokollierungssystem nimmt die Änderung auf und Sie sollten Folgendes sehen:
Ausgabe:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.404s)
UdpEchoClientAnwendung:UdpEchoClient()
UdpEchoClient-Anwendung:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
Gesendet 1024 Byte an 10.1.1.2
1024 Bytes von 10.1.1.1 erhalten
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
1024 Bytes von 10.1.1.2 erhalten
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientAnwendung:~UdpEchoClient()
Die von der Anwendung bereitgestellten zusätzlichen Debug-Informationen stammen aus der NS_LOG_FUNCTION
Niveau. Dies wird jedes Mal angezeigt, wenn eine Funktion in der Anwendung während des Skripts aufgerufen wird
Hinrichtung. Im Allgemeinen ist die Verwendung von (mindestens) NS_LOG_FUNCTION(this) in Memberfunktionen
bevorzugt. Verwenden Sie NS_LOG_FUNCTION_NOARGS() nur in statischen Funktionen. Beachten Sie jedoch, dass
es gibt keine anforderungen in der NS-3 System, bei dem die Modelle bestimmte Anforderungen unterstützen müssen
Protokollierungsfunktionalität. Die Entscheidung, wie viele Informationen protokolliert werden, liegt bei
der einzelne Modellentwickler. Bei den Echo-Anwendungen ist viel Log
Ausgabe vorhanden ist.
Sie können jetzt ein Protokoll der Funktionsaufrufe anzeigen, die an die Anwendung gesendet wurden. wenn du
Schauen Sie genau hin, Sie werden einen einzelnen Doppelpunkt zwischen der Zeichenfolge bemerken UdpEchoClient-Anwendung
und den Methodennamen, wo Sie möglicherweise einen C++-Bereichsoperator erwartet haben (::). Das ist
absichtlich.
Der Name ist kein Klassenname, sondern ein Name der Protokollierungskomponente. Wenn es ein gibt
Eins-zu-eins-Entsprechung zwischen einer Quelldatei und einer Klasse, dies ist im Allgemeinen die
Klassenname, aber Sie sollten verstehen, dass es sich nicht wirklich um einen Klassennamen handelt, und es gibt ein
einfacher Doppelpunkt anstelle eines Doppelpunkts, um Sie auf relativ subtile Weise daran zu erinnern
Trennen Sie den Namen der Protokollierungskomponente konzeptionell vom Klassennamen.
Es stellt sich heraus, dass es in einigen Fällen schwierig sein kann zu bestimmen, welche Methode tatsächlich verwendet wird
erzeugt eine Log-Meldung. Wenn Sie in den obigen Text schauen, fragen Sie sich vielleicht, wo die Zeichenfolge
"Empfangene 1024 Bytes für 10.1.1.2" kommt von. Sie können dies lösen, indem Sie die ODER-Verknüpfung
prefix_func Ebene in die NS_LOG Umgebungsvariable. Versuchen Sie Folgendes:
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'
Beachten Sie, dass die Anführungszeichen erforderlich sind, da der vertikale Balken, den wir verwenden, um ein ODER anzuzeigen
Betrieb ist auch ein Unix-Rohrverbinder.
Wenn Sie nun das Skript ausführen, werden Sie sehen, dass das Logging-System sicherstellt, dass alle
Nachricht von der angegebenen Protokollkomponente wird der Komponentenname vorangestellt.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.417s)
UdpEchoClientAnwendung:UdpEchoClient()
UdpEchoClient-Anwendung:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Gesendet 1024 Byte an 10.1.1.2
1024 Bytes von 10.1.1.1 erhalten
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 erhalten
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientAnwendung:~UdpEchoClient()
Sie können jetzt alle Nachrichten sehen, die von der UDP-Echo-Client-Anwendung kommen
als solche gekennzeichnet. Die Meldung "1024 Bytes von 10.1.1.2 erhalten" ist jetzt eindeutig
als von der Echo-Client-Anwendung stammend identifiziert. Die verbleibende Nachricht muss sein
von der UDP-Echo-Server-Anwendung stammen. Wir können diese Komponente aktivieren, indem wir a . eingeben
durch Doppelpunkte getrennte Liste von Komponenten in der Umgebungsvariablen NS_LOG.
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
UdpEchoServerApplication=level_all|prefix_func'
Warnung: Sie müssen den Zeilenumbruch nach dem entfernen : im obigen Beispieltext
ist nur für Dokumentformatierungszwecke da.
Wenn Sie nun das Skript ausführen, sehen Sie alle Protokollmeldungen sowohl des Echo-Clients
und Serveranwendungen. Sie werden sehen, dass dies beim Debuggen von Problemen sehr nützlich sein kann.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientAnwendung:UdpEchoClient()
UdpEchoClient-Anwendung:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Gesendet 1024 Byte an 10.1.1.2
UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
UdpEchoServerApplication:HandleRead(): Echo-Paket
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 erhalten
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientAnwendung:~UdpEchoClient()
UdpEchoServerAnwendung:~UdpEchoServer()
Manchmal ist es auch nützlich, den Simulationszeitpunkt sehen zu können, zu dem eine Log-Meldung
erzeugt wird. Dies können Sie durch ODER-Verknüpfung des prefix_time-Bits tun.
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time:
UdpEchoServerApplication=level_all|prefix_func|prefix_time'
Auch hier müssen Sie den obigen Zeilenumbruch entfernen. Wenn Sie das Skript jetzt ausführen, sollten Sie
siehe folgende Ausgabe:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0S udpechoclientApplication: udpechoclient ()
0s UdpEchoClientAnwendung:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Gesendet 1024 Byte an 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
2.00369s UdpEchoServerApplication:HandleRead(): Echo-Paket
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): 1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientAnwendung:~UdpEchoClient()
UdpEchoServerAnwendung:~UdpEchoServer()
Sie sehen, dass der Konstruktor für den UdpEchoServer zu einer Simulationszeit von aufgerufen wurde
0 Sekunden. Dies geschieht tatsächlich, bevor die Simulation beginnt, aber die Zeit ist
als null Sekunden angezeigt. Das gleiche gilt für die UdpEchoClient-Konstruktornachricht.
Daran erinnern, dass die Scratch/first.cc Skript startete die Echo-Server-Anwendung in einer Sekunde
in die Simulation ein. Sie können jetzt sehen, dass die Bewerbung starten Methode des Servers ist,
tatsächlich in einer Sekunde aufgerufen. Sie können auch sehen, dass die Echo-Client-Anwendung
mit einer Simulationszeit von zwei Sekunden gestartet, wie wir es im Skript gefordert haben.
Sie können nun den Fortschritt der Simulation von der Seite aus verfolgen ZeitplanTransmit Rufen Sie in der
Kunde, der anruft Absenden zu den HandleRead Rückruf in der Echo-Server-Anwendung. Notiz
dass die verstrichene Zeit für das Senden des Pakets über die Punkt-zu-Punkt-Verbindung 3.69 beträgt
Millisekunden. Sie sehen, wie der Echo-Server eine Nachricht protokolliert, die Ihnen mitteilt, dass es ein Echo gegeben hat
das Paket und dann, nach einer weiteren Kanalverzögerung, sehen Sie, dass der Echo-Client die
Echo-Paket in seinem HandleRead Methode.
In dieser Simulation passiert eine Menge unter der Decke, die Sie nicht sind
auch sehen. Sie können den gesamten Vorgang ganz einfach verfolgen, indem Sie alle
Protokollierungskomponenten im System. Versuchen Sie die Einstellung NS_LOG variabel wie folgt,
$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'
Das Sternchen oben ist der Platzhalter für die Protokollierungskomponente. Dadurch werden alle
alle in der Simulation verwendeten Komponenten einloggen. Ich werde die Ausgabe nicht reproduzieren
hier (zum jetzigen Zeitpunkt erzeugt es 1265 Ausgabezeilen für das Einzelpaketecho), aber
Sie können diese Informationen in eine Datei umleiten und mit Ihrem Favoriten durchsehen
Redakteur, wenn Sie möchten,
$ ./waf --run scratch/myfirst > log.out 2>&1
Ich persönlich benutze diese extrem ausführliche Version der Protokollierung, wenn mir ein angezeigt wird
Problem und ich habe keine Ahnung, wo die Dinge schief laufen. Ich kann den Fortschritt der
Code ganz einfach, ohne Breakpoints setzen und Code in einem Debugger schrittweise durchlaufen zu müssen.
Ich kann die Ausgabe einfach in meinem Lieblingseditor bearbeiten und nach Dingen suchen, die ich erwarte,
und sehe Dinge passieren, die ich nicht erwarte. Wenn ich eine allgemeine Vorstellung davon habe, was ist
Wenn es schief geht, gehe ich in einen Debugger über, um das Problem genauer zu untersuchen.
Diese Art der Ausgabe kann besonders nützlich sein, wenn Ihr Skript etwas vollständig macht
unerwartet. Wenn Sie einen Debugger verwenden, verpassen Sie möglicherweise einen unerwarteten Ausflug
ganz und gar. Die Protokollierung der Exkursion macht sie schnell sichtbar.
Hinzufügen Protokollierung zu deine Code
Sie können Ihren Simulationen eine neue Protokollierung hinzufügen, indem Sie die Protokollkomponente über . aufrufen
mehrere Makros. Machen wir das im myfirst.cc Skript haben wir in der kratzen Verzeichnis.
Denken Sie daran, dass wir in diesem Skript eine Protokollierungskomponente definiert haben:
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
Sie wissen jetzt, dass Sie die gesamte Protokollierung für diese Komponente aktivieren können, indem Sie die
NS_LOG Umgebungsvariable auf die verschiedenen Ebenen. Machen wir weiter und fügen Sie etwas Protokollierung hinzu
das Skript. Das Makro, das zum Hinzufügen einer Protokollnachricht auf Informationsebene verwendet wird, ist NS_LOG_INFO. Gehen
voraus und fügen Sie einen hinzu (kurz bevor wir mit dem Erstellen der Knoten beginnen), der Ihnen sagt, dass das Skript
ist "Topologie erstellen". Dies geschieht wie in diesem Code-Snippet,
Öffnen scratch/myfirst.cc in Ihrem Lieblingseditor und fügen Sie die Zeile hinzu,
NS_LOG_INFO ("Erstellen einer Topologie");
direkt vor den Zeilen,
NodeContainer-Knoten;
Knoten.Erstellen (2);
Erstellen Sie nun das Skript mit waf und löschen Sie das NS_LOG Variable zum Abschalten des Torrents von
Protokollierung, die wir zuvor aktiviert haben:
$ ./waf
$ exportieren NS_LOG=
Wenn Sie nun das Skript ausführen,
$ ./waf --run scratch/myfirst
Sie werden nicht sehen Sie Ihre neue Nachricht seit der zugehörigen Protokollierungskomponente
(Erstes SkriptBeispiel) wurde nicht aktiviert. Um Ihre Nachricht zu sehen, müssen Sie
Aktivieren Sie die Erstes SkriptBeispiel Protokollierungskomponente mit einem Level größer oder gleich
NS_LOG_INFO. Wenn Sie nur diese bestimmte Protokollierungsebene sehen möchten, können Sie sie aktivieren
durch,
$ export NS_LOG=FirstScriptExample=info
Wenn Sie jetzt das Skript ausführen, sehen Sie Ihre neue Protokollmeldung "Creating Topology",
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.404s)
Topologie erstellen
Gesendet 1024 Byte an 10.1.1.2
1024 Bytes von 10.1.1.1 erhalten
1024 Bytes von 10.1.1.2 erhalten
Die richtigen Befehl Line Argumente
Überschreiben Standard Attribute
Eine andere Möglichkeit, wie Sie ändern können NS-3 Skripte verhalten sich ohne Bearbeitung und das Erstellen erfolgt über
Befehl Linie Argumente. Wir bieten einen Mechanismus zum Parsen von Befehlszeilenargumenten und
Legen Sie basierend auf diesen Argumenten automatisch lokale und globale Variablen fest.
Der erste Schritt bei der Verwendung des Befehlszeilen-Argumentsystems besteht darin, die Befehlszeile zu deklarieren
Parser. Dies geschieht ganz einfach (in Ihrem Hauptprogramm) wie im folgenden Code,
int
main (int argc, char *argv[])
{
...
Befehlszeile cmd;
cmd.Parse (argc, argv);
...
}
Dieses einfache zweizeilige Snippet ist an sich schon sehr nützlich. Es öffnet die Tür zum
NS-3 globale Variable und Attribut Systeme. Fahren Sie fort und fügen Sie diese zwei Codezeilen zu hinzu
scratch/myfirst.cc Skript zu Beginn von Haupt-. Fahren Sie fort und erstellen Sie das Skript und führen Sie es aus
es, aber bitten Sie das Skript wie folgt um Hilfe:
$ ./waf --run "scratch/myfirst --PrintHelp"
Dadurch wird Waf aufgefordert, die kratzen/myfirst script und übergeben Sie das Kommandozeilenargument
--DruckenHilfe zum Skript. Die Anführungszeichen werden benötigt, um herauszufinden, welches Programm welches bekommt
Streit. Der Befehlszeilen-Parser sieht nun das --DruckenHilfe argumentieren und antworten mit,
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Name des Handle-Arguments=PrintHelp-Wert=
--PrintHelp: Drucken Sie diese Hilfenachricht.
--PrintGroups: Drucken Sie die Liste der Gruppen.
--PrintTypeIds: Alle TypeIds drucken.
--PrintGroup=[group]: Druckt alle TypeIds der Gruppe.
--PrintAttributes=[typeid]: Gibt alle Attribute von typeid aus.
--PrintGlobals: Druckt die Liste der Globals.
Konzentrieren wir uns auf die --Druckattribute Möglichkeit. Die haben wir schon angedeutet NS-3 Attribut
System beim Gehen durch die zuerst.cc Skript. Wir haben uns die folgenden Zeilen von . angesehen
Code,
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
und erwähnte das Datenrate war eigentlich ein Attribut dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog. PointToPointNetDevice. Lasst uns
Verwenden Sie den Befehlszeilenargument-Parser, um einen Blick auf die Attribute dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog.
PointToPointNetDevice. In der Hilfeliste steht, dass wir eine Typ-ID. Dies
entspricht dem Klassennamen der Klasse, zu der die Attribute gehören. In diesem Fall
es wird sein ns3::PointToPointNetDevice. Lass uns weitermachen und eintippen,
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"
Das System druckt alle Attribute dieser Art von Netzgerät. Unter den
Attribute Sie sehen aufgelistet ist,
--ns3::PointToPointNetDevice::DataRate=[32768bps]:
Die Standarddatenrate für Punkt-zu-Punkt-Verbindungen
Dies ist der Standardwert, der verwendet wird, wenn a PointToPointNetDevice wird in der erstellt
System. Wir überschreiben diese Vorgabe mit dem Attribut Einstellung in der PointToPointHelper
Oben. Verwenden wir die Standardwerte für die Punkt-zu-Punkt-Geräte und -Kanäle von
Löschen der SetDeviceAttribute anrufen und die SetChannelAttribute Anruf von der myfirst.cc
Wir haben im Scratch-Verzeichnis.
Ihr Skript sollte jetzt nur die deklarieren PointToPointHelper und mach keine kompensieren Geschäftstätigkeit
wie im folgenden Beispiel,
...
NodeContainer-Knoten;
Knoten.Erstellen (2);
PointToPointHelper pointToPoint;
NetDeviceContainer-Geräte;
Geräte = pointToPoint.Install (Knoten);
...
Fahren Sie fort und erstellen Sie das neue Skript mit Waf (./waff) und lass uns zurückgehen und einige aktivieren
Protokollierung von der UDP-Echo-Serveranwendung und aktivieren Sie das Zeitpräfix.
$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'
Wenn Sie das Skript ausführen, sollten Sie jetzt die folgende Ausgabe sehen:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Gesendet 1024 Byte an 10.1.1.2
2.25732s Erhaltene 1024 Bytes von 10.1.1.1
2.25732s Echopaket
1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerAnwendung:~UdpEchoServer()
Denken Sie daran, dass wir uns das letzte Mal die Simulationszeit angesehen haben, zu der das Paket war
vom Echo-Server empfangen wurde, war es bei 2.00369 Sekunden.
2.00369s UdpEchoServerApplication:HandleRead(): 1024 Bytes von 10.1.1.1 empfangen
Jetzt empfängt es das Paket bei 2.25732 Sekunden. Das liegt daran, dass wir gerade das fallen gelassen haben
Datenrate des PointToPointNetDevice bis auf den Standardwert von 32768 Bit pro Sekunde von
fünf Megabit pro Sekunde.
Wenn wir eine neue zur Verfügung stellen würden Datenrate Mit der Kommandozeile konnten wir unsere Simulation beschleunigen
wieder auf. Wir tun dies auf folgende Weise, gemäß der von der Hilfe implizierten Formel:
Artikel:
$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"
Dadurch wird der Standardwert des Datenrate Attribut zurück zu fünf Megabit pro
Sekunde. Sind Sie vom Ergebnis überrascht? Es stellt sich heraus, dass um das Original zu bekommen
Verhalten des Skripts zurück, müssen wir die Lichtgeschwindigkeitsverzögerung des Kanals einstellen
sowie. Wir können das Kommandozeilensystem bitten, die auszudrucken Attribute des Kanals
genau wie wir es für das net-Gerät getan haben:
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"
Wir entdecken die Verzögerung Attribut des Kanals wird wie folgt eingestellt:
--ns3::PointToPointChannel::Delay=[0ns]:
Übertragungsverzögerung durch den Kanal
Wir können dann diese beiden Standardwerte über das Befehlszeilensystem festlegen,
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"
In diesem Fall stellen wir das Timing wieder her, das wir hatten, als wir explizit die Datenrate und Verzögerung
im Skript:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Gesendet 1024 Byte an 10.1.1.2
2.00369s Erhaltene 1024 Bytes von 10.1.1.1
2.00369s Echopaket
1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerAnwendung:~UdpEchoServer()
Beachten Sie, dass das Paket nach 2.00369 Sekunden erneut vom Server empfangen wird. Wir könnten
tatsächlich einen der Attribute auf diese Weise im Skript verwendet. Insbesondere könnten wir
Stellen Sie den UdpEchoClient Attribut MaxPakete auf einen anderen Wert als eins.
Wie würden Sie das angehen? Versuche es. Denken Sie daran, dass Sie den Ort auskommentieren müssen
Wir überschreiben die Standardeinstellung Attribut und explizit gesetzt MaxPakete im Skript. Dann Sie
muss das Skript neu erstellen. Sie müssen auch die Syntax für die tatsächliche Einstellung finden
den neuen Standardattributwert mithilfe der Befehlszeilen-Hilfefunktion. Sobald du das hast
Ich habe herausgefunden, dass Sie in der Lage sein sollten, die Anzahl der Pakete zu kontrollieren, die vom Befehl zurückgesendet werden
Leitung. Da wir nette Leute sind, sagen wir Ihnen, dass Ihre Befehlszeile am Ende aussehen sollte
etwas wie,
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms
--ns3::UdpEchoClient::MaxPackets=2"
Einhaken Sie Eigene Werte
Sie können dem Befehlszeilensystem auch eigene Hooks hinzufügen. Das geht ganz einfach von
Verwendung der AddValue -Methode zum Befehlszeilen-Parser.
Lassen Sie uns diese Funktion verwenden, um die Anzahl der Pakete anzugeben, die in einem völlig anderen Echo wiedergegeben werden sollen
Weg. Fügen wir eine lokale Variable namens . hinzu nPakete zu den Haupt- Funktion. Wir initialisieren
es zu eins, um unserem vorherigen Standardverhalten zu entsprechen. Um dem Befehlszeilenparser zu erlauben,
Wenn Sie diesen Wert ändern, müssen wir den Wert in den Parser einbinden. Wir tun dies, indem wir einen Anruf hinzufügen
zu AddValue. Mach weiter und ändere die scratch/myfirst.cc Skript, um mit dem zu beginnen
folgenden Code,
int
main (int argc, char *argv[])
{
uint32_t nPakete = 1;
Befehlszeile cmd;
cmd.AddValue("nPackets", "Anzahl der Pakete zum Echo", nPackets);
cmd.Parse (argc, argv);
...
Scrollen Sie nach unten zu der Stelle im Skript, an der wir die MaxPakete Attribut und ändere es
so dass es auf die Variable gesetzt wird nPakete statt der Konstante 1 wie unten gezeigt.
echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));
Wenn Sie nun das Skript ausführen und die --DruckenHilfe Argument, du solltest dein neues sehen
Mitglied Argument in der Hilfeanzeige aufgelistet.
Versuchen,
$ ./waf --run "scratch/myfirst --PrintHelp"
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.403s)
--PrintHelp: Drucken Sie diese Hilfenachricht.
--PrintGroups: Drucken Sie die Liste der Gruppen.
--PrintTypeIds: Alle TypeIds drucken.
--PrintGroup=[group]: Druckt alle TypeIds der Gruppe.
--PrintAttributes=[typeid]: Gibt alle Attribute von typeid aus.
--PrintGlobals: Druckt die Liste der Globals.
Benutzerargumente:
--nPackets: Anzahl der Pakete zum Echo
Wenn Sie die Anzahl der zu echoenden Pakete angeben möchten, können Sie dies jetzt tun, indem Sie die
--nPakete Argument in der Befehlszeile,
$ ./waf --run "scratch/myfirst --nPackets=2"
Sie sollten jetzt sehen
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Gesendet 1024 Byte an 10.1.1.2
2.25732s Erhaltene 1024 Bytes von 10.1.1.1
2.25732s Echopaket
1024 Bytes von 10.1.1.2 erhalten
Gesendet 1024 Byte an 10.1.1.2
3.25732s Erhaltene 1024 Bytes von 10.1.1.1
3.25732s Echopaket
1024 Bytes von 10.1.1.2 erhalten
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerAnwendung:~UdpEchoServer()
Sie haben jetzt zwei Pakete zurückgesendet. Ziemlich einfach, nicht wahr?
Sie können das sehen, wenn Sie ein . sind NS-3 Benutzer können Sie das Befehlszeilen-Argumentsystem verwenden, um
globale Werte steuern und Attribute. Wenn Sie ein Modellautor sind, können Sie neue hinzufügen
Attribute auf Ihre Objekte und sie stehen automatisch zur Einstellung durch Ihre zur Verfügung
Benutzer über das Befehlszeilensystem. Wenn Sie ein Drehbuchautor sind, können Sie neue hinzufügen
Variablen in Ihre Skripte und binden Sie sie ganz schmerzlos in das Befehlszeilensystem ein.
Die richtigen Tracing System
Der Sinn der Simulation besteht darin, Ergebnisse für weitere Studien zu generieren, und die NS-3
Tracing-System ist ein primärer Mechanismus dafür. Schon seit NS-3 ist ein C++ Programm, Standard
Einrichtungen zum Generieren von Ausgaben aus C++-Programmen könnten verwendet werden:
#einschließen
...
int Haupt ()
{
...
std::cout << "Der Wert von x ist " << x << std::endl;
...
}
Sie könnten sogar das Protokollierungsmodul verwenden, um Ihrer Lösung ein wenig Struktur zu verleihen. Dort
sind viele bekannte Probleme, die durch solche Ansätze erzeugt werden, und so haben wir a
generisches Subsystem zur Ereignisverfolgung, um die Probleme zu lösen, die wir für wichtig hielten.
Die grundlegenden Ziele der NS-3 Rückverfolgungssystem sind:
· Für grundlegende Aufgaben sollte das Rückverfolgungssystem dem Benutzer ermöglichen, eine Standardverfolgung zu erstellen
für gängige Tracing-Quellen und um anzupassen, welche Objekte die Tracing generieren;
· Fortgeschrittene Benutzer müssen in der Lage sein, das Tracing-System zu erweitern, um das Ausgabeformat zu ändern
generiert oder neue Tracing-Quellen einzufügen, ohne den Kern der
Simulator;
· Fortgeschrittene Benutzer können den Simulatorkern modifizieren, um neue Verfolgungsquellen und -senken hinzuzufügen.
Die NS-3 Rückverfolgungssystem basiert auf den Konzepten unabhängiger Rückverfolgungsquellen und
Verfolgung von Senken und einen einheitlichen Mechanismus zum Verbinden von Quellen mit Senken. Spurenquellen sind
Entitäten, die Ereignisse signalisieren können, die in einer Simulation passieren, und den Zugriff auf
interessante Basisdaten. Eine Trace-Quelle könnte beispielsweise anzeigen, wenn ein Paket
von einem Netzgerät empfangen und bieten Zugriff auf den Paketinhalt für interessierte Traces
sinkt.
Trace-Quellen sind an sich nicht nützlich, sie müssen mit anderen Teilen von "verbunden" werden
Code, der mit den von der Senke bereitgestellten Informationen tatsächlich etwas Nützliches anstellt. Verfolgen
Senken sind Verbraucher der Ereignisse und Daten, die von den Ablaufverfolgungsquellen bereitgestellt werden. Zum Beispiel,
man könnte eine Trace-Senke erstellen, die (wenn sie mit der Trace-Quelle des
vorheriges Beispiel) interessante Teile des empfangenen Pakets ausdrucken.
Der Grund für diese explizite Aufteilung ist, dass Benutzer neue Arten von Spülen an
vorhandenen Tracing-Quellen, ohne dass der Kern der
Simulator. Im obigen Beispiel könnte ein Benutzer also eine neue Ablaufverfolgungssenke in ihr definieren
Skript und hängen Sie es an eine vorhandene Ablaufverfolgungsquelle an, die im Simulationskern definiert ist, indem Sie
nur das Benutzerskript bearbeiten.
In diesem Tutorial werden wir einige vordefinierte Quellen und Senken durchgehen und zeigen, wie
sie können mit geringem Benutzeraufwand angepasst werden. Siehe ns-3 Handbuch oder Anleitungen
für Informationen zur erweiterten Tracing-Konfiguration einschließlich der Erweiterung des Tracing
Namespace und Erstellen neuer Tracing-Quellen.
ASCII Tracing
NS-3 bietet Hilfsfunktionen, die das Ablaufverfolgungssystem auf niedriger Ebene umschließen, um Ihnen zu helfen
mit den Details, die bei der Konfiguration einiger leicht verständlicher Paketverfolgungen erforderlich sind. wenn du
Wenn Sie diese Funktionalität aktivieren, sehen Sie die Ausgabe in ASCII-Dateien --- daher der Name. Zum
diejenigen, die sich auskennen NS-2 ausgegeben, ist dieser Trace-Typ analog zum aus.tr erzeugt
durch viele Skripte.
Lassen Sie uns einfach direkt einsteigen und unserem ASCII-Tracing-Output hinzufügen scratch/myfirst.cc
Skript. Kurz vor dem Anruf bei Simulator::Ausführen (), fügen Sie die folgenden Codezeilen hinzu:
AsciiTraceHelper ascii;
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
Wie in vielen anderen NS-3 Idiome verwendet dieser Code ein Hilfsobjekt, um ASCII zu erstellen
Spuren. Die zweite Zeile enthält zwei verschachtelte Methodenaufrufe. Die "innen"-Methode,
CreateFileStream() verwendet ein unbenanntes Objekt-Idiom, um ein Dateistream-Objekt auf dem . zu erstellen
stack (ohne Objektnamen) und übergeben Sie es an die aufgerufene Methode. Wir gehen darauf ein
mehr in der Zukunft, aber alles, was Sie an dieser Stelle wissen müssen, ist, dass Sie eine
Objekt, das eine Datei namens "myfirst.tr" darstellt und an NS-3. Du erzählst
NS-3 mit den Lebensdauerproblemen des erstellten Objekts umzugehen und auch mit Problemen umzugehen
verursacht durch eine wenig bekannte (absichtliche) Einschränkung von C++ ofstream-Objekten in Bezug auf das Kopieren
Konstrukteure.
Der externe Anruf, um EnableAsciiAll(), teilt dem Helfer mit, dass Sie ASCII aktivieren möchten
Verfolgung auf allen Punkt-zu-Punkt-Geräten in Ihrer Simulation; und du willst die (vorausgesetzt)
Trace-Senken, um Informationen über die Paketbewegung im ASCII-Format auszugeben.
Für diejenigen, die mit vertraut sind NS-2, entsprechen die verfolgten Ereignisse den gängigen Tracepunkten
die "+", "-", "d" und "r"-Ereignisse protokollieren.
Sie können nun das Skript erstellen und über die Befehlszeile ausführen:
$ ./waf --run scratch/myfirst
So wie Sie es schon oft gesehen haben, sehen Sie einige Nachrichten von Waf und dann
"'build' erfolgreich beendet" mit einer Reihe von Meldungen des laufenden Programms.
Wenn es ausgeführt wurde, hat das Programm eine Datei namens . erstellt meineerste.tr. Wegen dem Weg
dass Waf funktioniert, die Datei wird nicht im lokalen Verzeichnis erstellt, sie wird am
Verzeichnis der obersten Ebene des Repositorys standardmäßig. Wenn Sie kontrollieren möchten, wo die Spuren
gespeichert sind, können Sie die --cwd Option von Waf, um dies anzugeben. Wir haben es nicht getan, also
wir müssen in das Top-Level-Verzeichnis unseres Repos wechseln und einen Blick auf das ASCII werfen
Trace-Datei meineerste.tr in Ihrem Lieblingseditor.
Parsing ASCII Traces (Spuren)
Es gibt viele Informationen in einer ziemlich dichten Form, aber das erste, was auffällt
ist, dass diese Datei mehrere verschiedene Zeilen enthält. Es kann schwer zu sehen sein
dies deutlich, es sei denn, Sie erweitern Ihr Fenster erheblich.
Jede Zeile in der Datei entspricht a Spur Event. In diesem Fall verfolgen wir Ereignisse auf
übertragen Warteschlange in jedem Punkt-zu-Punkt-Netzgerät in der Simulation vorhanden. Die
Sendewarteschlange ist eine Warteschlange, durch die jedes Paket, das für einen Punkt-zu-Punkt-Kanal bestimmt ist
muss bestehen. Beachten Sie, dass jede Zeile in der Trace-Datei mit einem einzelnen Zeichen beginnt (hat ein
Leerzeichen danach). Dieses Zeichen hat folgende Bedeutung:
· +: In der Gerätewarteschlange ist ein Vorgang zum Einreihen in die Warteschlange aufgetreten.
· -: In der Gerätewarteschlange ist ein Vorgang zum Entfernen aus der Warteschlange aufgetreten;
· d: Ein Paket wurde verworfen, normalerweise weil die Warteschlange voll war;
· r: Ein Paket wurde vom Netzgerät empfangen.
Sehen wir uns die erste Zeile in der Trace-Datei genauer an. Ich werde es zerlegen
in Abschnitte (der Übersichtlichkeit halber eingerückt) mit einer Referenznummer auf der linken Seite:
+
2
/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
ns3::PppHeader (
Punkt-zu-Punkt-Protokoll: IP (0x0021))
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 Protokoll 17 Offset 0 Flags [keine]
Länge: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
Länge: 1032 49153 > 9)
Nutzlast (Größe = 1024)
Der erste Abschnitt dieses erweiterten Ablaufverfolgungsereignisses (Referenznummer 0) ist die Operation. Wir
haben ein + Zeichen, das entspricht also einem enqueue Operation in der Sendewarteschlange.
Der zweite Abschnitt (Referenz 1) ist die Simulationszeit, ausgedrückt in Sekunden. Du darfst
Denken Sie daran, dass wir gefragt haben UdpEchoClient-Anwendung um nach zwei Sekunden mit dem Senden von Paketen zu beginnen.
Hier sehen wir die Bestätigung, dass dies tatsächlich geschieht.
Der nächste Abschnitt des Beispiel-Trace (Referenz 2) sagt uns, welche Trace-Quelle stammt
dieses Ereignis (ausgedrückt im Ablaufverfolgungs-Namespace). Sie können sich den Namensraum für die Ablaufverfolgung vorstellen
ähnlich wie bei einem Dateisystem-Namespace. Die Wurzel des Namensraums ist der
Knotenliste. Dies entspricht einem Container, der im . verwaltet wird NS-3 Kerncode, der alles enthält
der Knoten, die in einem Skript erstellt werden. So wie ein Dateisystem Verzeichnisse haben kann
unter der Wurzel haben wir möglicherweise Knotennummern in der Knotenliste. Die Saite /Knotenliste/0
bezieht sich daher auf den nullten Knoten im Knotenliste die wir normalerweise als "Knoten" betrachten
0". In jedem Knoten gibt es eine Liste der installierten Geräte. Diese Liste erscheint
weiter im Namensraum. Sie können sehen, dass dieses Ablaufverfolgungsereignis von . stammt Geräteliste/0 welches ist
das nullte Gerät, das im Knoten installiert ist.
Die nächste Saite, $ns3::PointToPointNetDevice sagt Ihnen, was für ein Gerät sich in der
nullte Position der Geräteliste für Knoten null. Denken Sie daran, dass die Operation + gefunden am
Referenz 00 bedeutete, dass eine Enqueue-Operation in der Sendewarteschlange des Geräts stattgefunden hat.
Dies spiegelt sich in den letzten Abschnitten des "Spurpfads" wider, die TxQueue/Enqueue.
Die verbleibenden Abschnitte in der Ablaufverfolgung sollten ziemlich intuitiv sein. Referenzen 3-4 geben an
dass das Paket in das Punkt-zu-Punkt-Protokoll eingekapselt ist. Die Referenzen 5-7 zeigen, dass
das Paket hat einen IP-Version-10.1.1.1-Header und stammt von der IP-Adresse XNUMX und
ist für 10.1.1.2 bestimmt. Die Referenzen 8-9 zeigen, dass dieses Paket einen UDP-Header hat und
schließlich zeigt Referenz 10, dass die Nutzlast die erwarteten 1024 Bytes beträgt.
Die nächste Zeile in der Trace-Datei zeigt, dass das gleiche Paket aus der Warteschlange entfernt wird
Warteschlange auf demselben Knoten.
Die dritte Zeile in der Trace-Datei zeigt das Paket an, das vom Netzgerät auf dem
Knoten mit dem Echo-Server. Ich habe dieses Ereignis unten wiedergegeben.
r
2.25732
/NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 Protokoll 17 Offset 0 Flags [keine]
Länge: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
Länge: 1032 49153 > 9)
Nutzlast (Größe = 1024)
Beachten Sie, dass die Trace-Operation jetzt ist r und die Simulationszeit hat sich auf 2.25732 . erhöht
Sekunden. Wenn Sie die Schritte des Tutorials genau befolgt haben, bedeutet dies, dass Sie
verließ die Datenrate der Netzgeräte und des Kanals Verzögerung auf ihre Standardwerte setzen.
Diese Zeit sollte Ihnen bekannt vorkommen, wie Sie sie zuvor in einem vorherigen Abschnitt gesehen haben.
Der Eintrag für den Namensraum der Ablaufverfolgungsquelle (Referenz 02) wurde geändert, um widerzuspiegeln, dass dieses Ereignis
von Knoten 1 kommend (/Knotenliste/1) und die Paketempfangs-Trace-Quelle (/MacRx). Es
sollte für Sie recht einfach sein, den Fortschritt des Pakets durch die Topologie zu verfolgen, indem Sie
Betrachten Sie den Rest der Spuren in der Datei.
PCAP Tracing
Die NS-3 Gerätehelfer können auch verwendet werden, um Trace-Dateien im .pcap Format. Das
Akronym pcap (normalerweise in Kleinbuchstaben geschrieben) steht für Packet Capture und ist eigentlich ein
API, die die Definition von a . enthält .pcap Datei Format. Das beliebteste Programm, das
lesen und anzeigen kann, ist dieses Format Wireshark (ehemals Ethereal). Allerdings gibt es
gibt es viele Traffic-Trace-Analysatoren, die dieses Paketformat verwenden. Wir empfehlen den Benutzern,
Nutzen Sie die vielen verfügbaren Tools zum Analysieren von Pcap-Traces. In diesem Tutorial haben wir
Konzentrieren Sie sich auf die Anzeige von Pcap-Spuren mit tcpdump.
Der zum Aktivieren der pcap-Ablaufverfolgung verwendete Code ist einzeilig.
pointToPoint.EnablePcapAll ("myfirst");
Fahren Sie fort und fügen Sie diese Codezeile nach dem ASCII-Tracing-Code ein, den wir gerade hinzugefügt haben
scratch/myfirst.cc. Beachten Sie, dass wir nur die Zeichenfolge "myfirst" übergeben haben und nicht
"myfirst.pcap" oder ähnliches. Dies liegt daran, dass der Parameter ein Präfix ist, kein a
vollständiger Dateiname. Der Helfer erstellt tatsächlich eine Trace-Datei für jeden Punkt-zu-Punkt
Gerät in der Simulation. Die Dateinamen werden mit dem Präfix, der Knotennummer,
die Gerätenummer und ein ".pcap"-Suffix.
In unserem Beispielskript sehen wir schließlich Dateien namens "myfirst-0-0.pcap" und
"myfirst-1-0.pcap", das sind die pcap-Traces für Knoten 0-Gerät 0 und Knoten 1-Gerät 0,
beziehungsweise.
Nachdem Sie die Codezeile hinzugefügt haben, um die Pcap-Ablaufverfolgung zu aktivieren, können Sie das Skript im
normaler Weg:
$ ./waf --run scratch/myfirst
Wenn Sie sich das Verzeichnis der obersten Ebene Ihrer Distribution ansehen, sollten Sie jetzt drei Protokolle sehen
Dateien: meineerste.tr ist die ASCII-Trace-Datei, die wir zuvor untersucht haben. myfirst-0-0.pcap
und myfirst-1-0.pcap sind die neuen pcap-Dateien, die wir gerade generiert haben.
Lesebrillen Möglichkeiten für das Ausgangssignal: mit tcpdump
Am einfachsten ist es an dieser Stelle zu verwenden tcpdump um zu sehen ppc Dateien.
$ tcpdump -nn -tt -r meineerste-0-0.pcap
Lesen aus Datei myfirst-0-0.pcap, Link-Typ PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, Länge 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, Länge 1024
tcpdump -nn -tt -r myfirst-1-0.pcap
Lesen aus Datei myfirst-1-0.pcap, Link-Typ PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, Länge 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, Länge 1024
Sie können in der Müllkippe von sehen myfirst-0-0.pcap (das Client-Gerät), dass das Echopaket ist
2 Sekunden in die Simulation gesendet. Wenn Sie sich den zweiten Dump ansehen (myfirst-1-0.pcap)
Sie können sehen, dass das Paket nach 2.257324 Sekunden empfangen wird. Sie sehen, wie das Paket ist
im zweiten Dump bei 2.257324 Sekunden zurückgespiegelt, und schließlich sehen Sie, dass das Paket ist
beim Client im ersten Dump bei 2.514648 Sekunden zurückerhalten.
Lesebrillen Möglichkeiten für das Ausgangssignal: mit Wireshark
Wenn Sie mit Wireshark nicht vertraut sind, gibt es eine Website, auf der Sie
Programme und Dokumentation herunterladen: http://www.wireshark.org/.
Wireshark ist eine grafische Benutzeroberfläche, mit der diese Traces angezeigt werden können
Dateien. Wenn Sie Wireshark zur Verfügung haben, können Sie jede der Trace-Dateien öffnen und anzeigen
den Inhalt so, als hätten Sie die Pakete mit a captured eingefangen Paket Schnüffler.
GEBÄUDE- TOPOLOGIEN
zum a Bus Network Topologie
In diesem Abschnitt werden wir unsere Beherrschung der NS-3 Netzwerkgeräte und -kanäle an
ein Beispiel für ein Busnetz abdecken. NS-3 bietet ein Netzgerät und einen Kanal, den wir CSMA nennen
(Carrier Sense-Mehrfachzugriff).
Die NS-3 Das CSMA-Gerät modelliert ein einfaches Netzwerk im Geiste von Ethernet. Ein echtes Ethernet
verwendet das CSMA/CD-Schema (Carrier Sense Multiple Access with Collision Detection) mit
exponentiell zunehmender Backoff, um um das gemeinsam genutzte Übertragungsmedium zu kämpfen. Der NS-3
CSMA-Geräte- und Kanalmodelle sind nur eine Teilmenge davon.
So wie wir beim Konstruieren Punkt-zu-Punkt-Topologie-Hilfsobjekte gesehen haben
Punkt-zu-Punkt-Topologien werden wir in diesem Abschnitt äquivalente CSMA-Topologie-Helfer sehen.
Das Aussehen und die Bedienung dieser Helfer sollte Ihnen bekannt vorkommen.
Wir stellen ein Beispielskript in unserem Verzeichnis instances/tutorial} zur Verfügung. Dieses Skript baut auf
zuerst.cc Skript und fügt der Punkt-zu-Punkt-Simulation, die wir bereits haben, ein CSMA-Netzwerk hinzu
berücksichtigt. Mach weiter und öffne Beispiele/Tutorial/Second.cc in Ihrem Lieblingseditor. Sie
werde schon genug gesehen haben NS-3 Code, um das meiste von dem zu verstehen, was darin vor sich geht
Beispiel, aber wir werden das gesamte Skript durchgehen und einen Teil der Ausgabe untersuchen.
Genau wie im zuerst.cc Beispiel (und in allen ns-3-Beispielen) beginnt die Datei mit einem emacs
mode-Zeile und einige GPL-Boilerplate.
Der eigentliche Code beginnt mit dem Laden der Include-Dateien des Moduls, genau wie in der zuerst.cc
Beispiel.
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"
Eine Sache, die überraschend nützlich sein kann, ist eine kleine ASCII-Grafik, die einen Cartoon zeigt
der im Beispiel aufgebauten Netztopologie. Eine ähnliche "Zeichnung" finden Sie in
die meisten unserer Beispiele.
In diesem Fall sehen Sie, dass wir unser Punkt-zu-Punkt-Beispiel (den Link
zwischen den Knoten n0 und n1 unten) durch Abhängen eines Busnetzes an der rechten Seite. Notiz
dass dies die Standard-Netzwerktopologie ist, da Sie die Anzahl der Knoten tatsächlich variieren können
im LAN erstellt. Wenn Sie nCsma auf eins setzen, gibt es insgesamt zwei Knoten auf dem
LAN (CSMA-Kanal) --- ein erforderlicher Knoten und ein "zusätzlicher" Knoten. Standardmäßig sind es drei
"zusätzliche" Knoten wie unten zu sehen:
// Standard-Netzwerktopologie
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// Punkt-zu-Punkt | | | |
// ================
//LAN 10.1.2.0
Dann ist der ns-3-Namensraum benutzt und eine Protokollierungskomponente wird definiert. Das ist alles so
es war in zuerst.cc, es gibt also noch nichts Neues.
Verwenden des Namensraums ns3;
NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");
Das Hauptprogramm beginnt mit einer etwas anderen Wendung. Wir verwenden ein ausführliches Flag, um
bestimmen, ob die UdpEchoClient-Anwendung und UdpEchoServer-Anwendung Protokollierung
Komponenten aktiviert sind. Dieses Flag ist standardmäßig auf "true" eingestellt (die Protokollierungskomponenten sind aktiviert)
ermöglicht es uns jedoch, die Protokollierung während des Regressionstests dieses Beispiels zu deaktivieren.
Sie sehen einen vertrauten Code, mit dem Sie die Anzahl der Geräte auf dem ändern können
CSMA-Netzwerk über Befehlszeilenargument. Wir haben etwas Ähnliches gemacht, als wir das erlaubten
Anzahl der gesendeten Pakete, die im Abschnitt über Befehlszeilenargumente geändert werden sollen. Das Letzte
line stellt sicher, dass Sie mindestens einen "zusätzlichen" Knoten haben.
Der Code besteht aus Variationen der zuvor behandelten API, also sollten Sie vollständig sein
an dieser Stelle des Tutorials mit dem folgenden Code vertraut.
bool verbose = wahr;
uint32_tnCsma = 3;
Befehlszeile cmd;
cmd.AddValue ("nCsma", "Anzahl \"zusätzlicher\" CSMA-Knoten/Geräte", nCsma);
cmd.AddValue ("ausführlich", "Echo-Anwendungen anweisen, zu protokollieren, wenn wahr", ausführlich);
cmd.Parse (argc, argv);
wenn (ausführlich)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
nCsma = nCsma == 0 ? 1: nCsma;
Der nächste Schritt besteht darin, zwei Knoten zu erstellen, die wir über die Punkt-zu-Punkt-Verbindung verbinden.
Die NodeContainer wird verwendet, um dies zu tun, genau wie in zuerst.cc.
NodeContainer p2pNodes;
p2pNodes.Create (2);
Als nächstes erklären wir ein anderes NodeContainer um die Knoten zu halten, die Teil des Busses sein werden
(CSMA) Netzwerk. Zuerst instanziieren wir nur das Containerobjekt selbst.
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
Die nächste Codezeile Ruft der erste Knoten (als ob er einen Index von eins hätte) aus dem
Punkt-zu-Punkt-Knotencontainer und fügt ihn dem Container der Knoten hinzu, die CSMA erhalten
Geräte. Der fragliche Knoten wird am Ende ein Punkt-zu-Punkt-Gerät haben und ein CSMA
Gerät. Wir erstellen dann eine Reihe von "zusätzlichen" Knoten, die den Rest des CSMA bilden
Netzwerk. Da wir bereits einen Knoten im CSMA-Netzwerk haben – den, der noch haben wird
sowohl ein Punkt-zu-Punkt- als auch ein CSMA-Netzgerät, die Anzahl der "zusätzlichen" Knoten bedeutet die Anzahl
gewünschten Knoten im CSMA-Abschnitt minus eins.
Das nächste Bit Code sollte jetzt ziemlich bekannt sein. Wir instanziieren a PointToPointHelper
und stellen Sie die zugehörige Voreinstellung ein Attribute damit wir fünf Megabit pro Sekunde erzeugen
Sender auf Geräten, die mit dem Helfer erstellt wurden, und eine Verzögerung von zwei Millisekunden auf den Kanälen
vom Helfer erstellt.
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
Wir instanziieren dann a NetDeviceContainer um den Überblick über die Punkt-zu-Punkt-Netzgeräte zu behalten
Installieren Geräte auf den Punkt-zu-Punkt-Knoten.
Wir haben oben erwähnt, dass Sie einen Helfer für CSMA-Geräte und -Kanäle sehen werden, und
die nächsten Zeilen stellen sie vor. Der CsmaHelper funktioniert genauso wie ein PointToPointHelper, Aber
es erstellt und verbindet CSMA-Geräte und -Kanäle. Bei einem CSMA-Gerät und
Kanalpaar, beachten Sie, dass die Datenrate durch a . angegeben wird Kanal Attribut statt a
Gerät Attribut. Dies liegt daran, dass ein echtes CSMA-Netzwerk kein Mischen zulässt, z
B. 10Base-T- und 100Base-T-Geräte auf einem bestimmten Kanal. Wir setzen zuerst die Datenrate auf
100 Megabit pro Sekunde und stellen Sie dann die Lichtgeschwindigkeitsverzögerung des Kanals auf 6560 . ein
Nanosekunden (willkürlich gewählt als 1 Nanosekunde pro Fuß über ein 100-Meter-Segment).
Beachten Sie, dass Sie eine Attribut unter Verwendung seines nativen Datentyps.
CsmaHelper-csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
So wie wir a . erstellt haben NetDeviceContainer um die Geräte zu halten, die von der . erstellt wurden
PointToPointHelper wir schaffen eine NetDeviceContainer um die von uns erstellten Geräte zu halten
CsmaHelper. Wir nennen die Installieren Methode der CsmaHelper um die Geräte in die
Knoten der csmaNodes NodeContainer.
Wir haben jetzt unsere Knoten, Geräte und Kanäle erstellt, aber wir haben keine Protokollstapel
Geschenk. Genau wie im zuerst.cc Skript verwenden wir das InternetStackHelper zu installieren
diese Stapel.
InternetStackHelper-Stack;
Stack.Install (p2pNodes.Get (0));
stack.Installieren (csmaNodes);
Denken Sie daran, dass wir einen der Knoten aus dem genommen haben p2pNodes Behälter und fügte ihn dem . hinzu
csmaNodes Container. Somit müssen wir nur die Stacks auf den restlichen installieren p2pNodes
Knoten und alle Knoten im csmaNodes Container, um alle Knoten im abzudecken
Simulation.
Genau wie im zuerst.cc Beispielskript verwenden wir das IPv4AddressHelper zu
unseren Geräteschnittstellen IP-Adressen zuweisen. Zuerst verwenden wir das Netzwerk 10.1.1.0 um
die beiden Adressen, die für unsere beiden Punkt-zu-Punkt-Geräte benötigt werden.
IPv4AddressHelper-Adresse;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
Denken Sie daran, dass wir die erstellten Schnittstellen in einem Container speichern, damit sie leicht herausgezogen werden können
Adressinformationen später zur Verwendung beim Einrichten der Anwendungen.
Wir müssen nun unseren CSMA-Geräteschnittstellen IP-Adressen zuweisen. Die Operation funktioniert
genau wie für den Punkt-zu-Punkt-Fall, außer dass wir jetzt die Operation auf ausführen
ein Container mit einer variablen Anzahl von CSMA-Geräten --- denken Sie daran, dass wir die Anzahl der gemacht haben
CSMA-Geräte können durch Befehlszeilenargument geändert werden. Die CSMA-Geräte werden verknüpft
mit IP-Adressen ab Netzwerknummer 10.1.2.0 in diesem Fall, wie unten zu sehen.
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
Jetzt haben wir eine Topologie aufgebaut, aber wir brauchen Anwendungen. Dieser Abschnitt wird
im Wesentlichen ähnlich wie der Anwendungsbereich von zuerst.cc aber wir werden
Instanziieren Sie den Server auf einem der Knoten mit einem CSMA-Gerät und den Client auf dem
Knoten mit nur einem Punkt-zu-Punkt-Gerät.
Zuerst richten wir den Echo-Server ein. Wir erstellen ein UdpEchoServerHelper und geben Sie eine erforderliche
Attribut Wert an den Konstruktor, der die Serverportnummer ist. Denken Sie daran, dass dieser Port
kann später mit der geändert werden SetAttribute Methode, falls gewünscht, aber wir benötigen sie
dem Konstrukteur zur Verfügung gestellt.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Sekunden (1.0));
serverApps.Stop (Sekunden (10.0));
Daran erinnern, dass die csmaNodes NodeContainer enthält einen der Knoten, die für die erstellt wurden
Punkt-zu-Punkt-Netzwerk und nCsma "zusätzliche" Knoten. Was wir erreichen wollen, ist der letzte der
"zusätzliche" Knoten. Der nullte Eintrag des csmaNodes Container wird der Punkt-zu-Punkt sein
Knoten. Der einfache Weg, sich das vorzustellen, ist, wenn wir einen "zusätzlichen" CSMA-Knoten erstellen, dann ist es
wird bei Index eins der . sein csmaNodes Container. Durch Induktion, wenn wir erzeugen nCsma "extra"
Knoten der letzte befindet sich am Index nCsma. Sie sehen dies ausgestellt in der Erhalten Sie vom ersten
Codezeile.
Die Client-Anwendung ist genau so eingerichtet, wie wir es in der zuerst.cc Beispielskript. Wieder,
wir stellen erforderlich Attribute zu den UdpEchoClientHelper im Konstruktor (in diesem Fall
die Remote-Adresse und den Port). Wir sagen dem Client, dass er Pakete an den Server senden soll, den wir nur
auf dem letzten der "zusätzlichen" CSMA-Knoten installiert. Wir installieren den Client ganz links
Punkt-zu-Punkt-Knoten in der Topologieabbildung.
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Sekunden (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Sekunden (2.0));
clientApps.Stop (Sekunden (10.0));
Da wir hier tatsächlich ein Internetwork aufgebaut haben, brauchen wir irgendeine Form von Internetwork
Routing. NS-3 bietet das, was wir globales Routing nennen, um Ihnen zu helfen. Globales Routing dauert
Vorteil, dass das gesamte Internetwork in der Simulation zugänglich ist und
durchläuft alle für die Simulation erstellten Knoten --- es erledigt die harte Arbeit von
Routing für Sie einrichten, ohne Router konfigurieren zu müssen.
Grundsätzlich verhält sich jeder Knoten so, als wäre er ein OSPF-Router, der
kommuniziert sofort und magisch mit allen anderen Routern hinter den Kulissen. Jeder Knoten
generiert Link-Werbung und übermittelt diese direkt an einen globalen Routenmanager
die diese globalen Informationen verwendet, um die Routing-Tabellen für jeden Knoten zu erstellen. Einstellung
up diese Form des Routings ist ein Einzeiler:
Ipv4GlobalRoutingHelper::RoutingTables bevölkern ();
Als nächstes aktivieren wir das pcap-Tracing. Die erste Codezeile zum Aktivieren der pcap-Ablaufverfolgung im
Point-to-Point-Helfer sollten Ihnen inzwischen bekannt sein. Die zweite Zeile aktiviert pcap
Tracing im CSMA-Helper und es gibt einen zusätzlichen Parameter, den Sie noch nicht kennen.
pointToPoint.EnablePcapAll ("zweite");
csma.EnablePcap ("zweite", csmaDevices.Get (1), wahr);
Das CSMA-Netzwerk ist ein Multi-Point-to-Point-Netzwerk. Dies bedeutet, dass (und sind in)
in diesem Fall) mehrere Endpunkte auf einem gemeinsam genutzten Medium. Jeder dieser Endpunkte hat ein Netz
damit verbundenes Gerät. Es gibt zwei grundlegende Alternativen zum Sammeln von Spuren
Informationen aus einem solchen Netzwerk. Eine Möglichkeit besteht darin, für jedes Netzgerät eine Trace-Datei zu erstellen
und nur die Pakete speichern, die von diesem Netzgerät ausgegeben oder verbraucht werden. Ein anderer Weg
besteht darin, eines der Geräte auszuwählen und es in den Promiscuous-Modus zu versetzen. Dieses einzelne Gerät dann
"schnüffelt" das Netzwerk nach allen Paketen und speichert sie in einer einzigen pcap-Datei. Das ist wie
tcpdump, zum Beispiel, funktioniert. Dieser letzte Parameter sagt dem CSMA-Helfer, ob er
veranlassen, Pakete im promiskuitiven Modus zu erfassen.
In diesem Beispiel wählen wir eines der Geräte im CSMA-Netzwerk aus und fragen es
ein promiskuitives Schnüffeln des Netzwerks durchzuführen und dabei zu emulieren, was tcpdump würdest du.
Wenn Sie auf einem Linux-Rechner waren, könnten Sie etwas tun wie tcpdump -i eth0 um das zu bekommen
verfolgen. In diesem Fall spezifizieren wir das Gerät mit csmaDevices.Get(1), die die . auswählt
erstes Gerät im Container. Das Setzen des finalen Parameters auf true aktiviert promiscuous
fängt.
Der letzte Codeabschnitt wird einfach ausgeführt und bereinigt die Simulation genau wie die zuerst.cc
Beispiel.
Simulator::Run ();
Simulator::Zerstören ();
Rückkehr 0;
}
Um dieses Beispiel auszuführen, kopieren Sie die zweite.cc Beispielskript in das Scratch-Verzeichnis
und baue mit waf so wie du es mit dem gemacht hast zuerst.cc Beispiel. Wenn Sie in der
Verzeichnis der obersten Ebene des Repositorys, das Sie gerade eingeben,
$ cp Beispiele/tutorial/second.cc scratch/mysecond.cc
$ ./waf
Achtung: Wir verwenden die Datei zweite.cc als einer unserer Regressionstests, um zu überprüfen, ob es funktioniert
genau so, wie es unserer Meinung nach erforderlich ist, um Ihre Tutorial-Erfahrung positiv zu gestalten.
Dies bedeutet, dass eine ausführbare Datei namens zweite ist bereits im Projekt vorhanden. Um irgendwelche zu vermeiden
Verwirrung darüber, was Sie ausführen, bitte umbenennen in mysecond.cc vorgeschlagen
zu teilen.
Wenn Sie dem Tutorial religiös folgen (Sie sind es, nicht wahr) haben Sie immer noch
den NS_LOG-Variablensatz, also fahren Sie fort, löschen Sie diese Variable und führen Sie das Programm aus.
$ exportieren NS_LOG=
$ ./waf --run scratch/mysecond
Da wir die UDP-Echo-Anwendungen so eingerichtet haben, dass sie sich genauso wie bei uns anmelden zuerst.cc, Werden Sie
sehen Sie eine ähnliche Ausgabe, wenn Sie das Skript ausführen.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.415s)
Gesendet 1024 Byte an 10.1.2.4
1024 Bytes von 10.1.1.1 erhalten
1024 Bytes von 10.1.2.4 erhalten
Denken Sie daran, dass die erste Nachricht "Sent 1024 Bytes zu 10.1.2.4," ist der UDP-Echo-Client
ein Paket an den Server senden. In diesem Fall befindet sich der Server in einem anderen Netzwerk
(10.1.2.0). Die zweite Nachricht "Empfangene 1024 Bytes für 10.1.1.1," stammt aus dem UDP-Echo
Server, der generiert wird, wenn er das Echopaket empfängt. Die letzte Nachricht "Empfangene 1024
Bytes für 10.1.2.4," kommt vom Echo-Client und zeigt an, dass er sein Echo empfangen hat
vom Server zurück.
Wenn Sie nun im Top-Level-Verzeichnis nachsehen, finden Sie drei Trace-Dateien:
second-0-0.pcap second-1-0.pcap second-2-0.pcap
Nehmen wir uns einen Moment Zeit, um uns die Benennung dieser Dateien anzusehen. Sie haben alle die gleiche Form,
- - .pcap. Die erste Datei in der Auflistung ist beispielsweise
zweite-0-0.pcap Dies ist der pcap-Trace von Knoten Null, Gerät Null. Dies ist das
Punkt-zu-Punkt-Netzgerät auf Knoten Null. Die Datei zweite-1-0.pcap ist der pcap-Trace für
Gerät null auf Knoten XNUMX, auch ein Punkt-zu-Punkt-Netzgerät; und die Datei zweite-2-0.pcap is
den pcap-Trace für Gerät null auf Knoten zwei.
Wenn Sie auf die Topologie-Abbildung am Anfang des Abschnitts zurückgreifen, sehen Sie
dass Knoten null der ganz linke Knoten der Punkt-zu-Punkt-Verbindung ist und Knoten eins der Knoten
das sowohl ein Punkt-zu-Punkt-Gerät als auch ein CSMA-Gerät hat. Sie werden sehen, dass Knoten zwei ist
der erste "extra" Knoten im CSMA-Netzwerk und dessen Gerät Null wurde als Gerät ausgewählt
um den Promiscuous-Mode-Trace zu erfassen.
Folgen wir nun dem Echopaket durch das Netzwerk. Führen Sie zuerst einen tcpdump des
Trace-Datei für den Punkt-zu-Punkt-Knoten ganz links --- Knoten Null.
$ tcpdump -nn -tt -r second-0-0.pcap
Der Inhalt der pcap-Datei sollte angezeigt werden:
Lesen aus Datei second-0-0.pcap, Link-Type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Die erste Zeile des Dumps zeigt an, dass der Linktyp PPP (Point-to-Point) ist, den wir
erwarten von. Sie sehen dann das Echopaket, das Knoten Null über das mit IP verknüpfte Gerät verlässt
Adresse 10.1.1.1 leitet zur IP-Adresse 10.1.2.4 (der CSMA-Knoten ganz rechts). Dieses Paket
bewegt sich über die Punkt-zu-Punkt-Verbindung und wird vom Punkt-zu-Punkt-Netzgerät empfangen
Knoten eins. Lass uns mal sehen:
$ tcpdump -nn -tt -r second-1-0.pcap
Sie sollten jetzt die pcap-Trace-Ausgabe der anderen Seite des Punkt-zu-Punkt-Links sehen:
Lesen aus Datei second-1-0.pcap, Link-Type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Hier sehen wir, dass der Linktyp auch PPP ist, wie wir es erwarten würden. Sie sehen das Paket von IP
Adresse 10.1.1.1 (die nach 2.000000 Sekunden gesendet wurde) in Richtung IP-Adresse 10.1.2.4
erscheinen auf dieser Schnittstelle. Nun wird das Paket intern an diesen Knoten weitergeleitet an
die CSMA-Schnittstelle und wir sollten sehen, wie sie auf diesem Gerät auftaucht, das auf sein ultimatives Ziel zusteuert
Ziel.
Denken Sie daran, dass wir Knoten 2 als promiskuitiven Sniffer-Knoten für das CSMA-Netzwerk ausgewählt haben
Schauen wir uns dann second-2-0.pcap an und sehen, ob es dort ist.
$ tcpdump -nn -tt -r second-2-0.pcap
Sie sollten jetzt den promiskuitiven Dump von Knoten zwei, Gerät null, sehen:
Lesen aus Datei second-2-0.pcap, Link-Typ EN10MB (Ethernet)
2.007698 ARP, Abfrage wer-hat 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, Länge 50
2.007710 ARP, Antwort 10.1.2.4 is-at 00:00:00:00:00:06, Länge 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
2.013815 ARP, Abfrage wer-hat 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, Länge 50
2.013828 ARP, Antwort 10.1.2.1 is-at 00:00:00:00:00:03, Länge 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Wie Sie sehen, lautet der Linktyp jetzt "Ethernet". Es ist jedoch etwas Neues aufgetaucht. Der
Busnetzbedarf ARP, das Adressauflösungsprotokoll. Knoten eins weiß, dass er senden muss
das Paket an die IP-Adresse 10.1.2.4, aber es kennt die MAC-Adresse des
entsprechenden Knoten. Es sendet im CSMA-Netzwerk (ff:ff:ff:ff:ff:ff) und fragt nach dem
Gerät mit IP-Adresse 10.1.2.4. In diesem Fall antwortet der Knoten ganz rechts und sagt es
hat die MAC-Adresse 00:00:00:00:00:06. Beachten Sie, dass Knoten zwei nicht direkt daran beteiligt ist
Exchange, sondern schnüffelt das Netzwerk ab und meldet den gesamten Verkehr, den es sieht.
Dieser Austausch ist in den folgenden Zeilen zu sehen,
2.007698 ARP, Abfrage wer-hat 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, Länge 50
2.007710 ARP, Antwort 10.1.2.4 is-at 00:00:00:00:00:06, Länge 50
Dann geht Knoten eins, Gerät eins voran und sendet das Echopaket an den UDP-Echoserver an
IP-Adresse 10.1.2.4.
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
Der Server empfängt die Echo-Anfrage und dreht das Paket um, um es zurückzusenden an
die Quelle. Der Server weiß, dass sich diese Adresse in einem anderen Netzwerk befindet, über das er erreicht wird
IP-Adresse 10.1.2.1. Dies liegt daran, dass wir das globale Routing initialisiert haben und es alles herausgefunden hat
davon für uns aus. Aber der Echo-Server-Knoten kennt die MAC-Adresse des ersten nicht
CSMA-Knoten, also muss er dafür ARP verwenden, genau wie der erste CSMA-Knoten es tun musste.
2.013815 ARP, Abfrage wer-hat 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, Länge 50
2.013828 ARP, Antwort 10.1.2.1 is-at 00:00:00:00:00:03, Länge 50
Der Server sendet dann das Echo zurück an den Weiterleitungsknoten.
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Rückblickend auf den äußerst rechten Knoten der Punkt-zu-Punkt-Verbindung,
$ tcpdump -nn -tt -r second-1-0.pcap
Sie können jetzt sehen, dass das zurückgesendete Paket als letztes auf die Punkt-zu-Punkt-Verbindung zurückkehrt
Zeile des Trace-Dumps.
Lesen aus Datei second-1-0.pcap, Link-Type PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Schließlich können Sie auf den Knoten zurückblicken, der das Echo verursacht hat
$ tcpdump -nn -tt -r second-0-0.pcap
und sehen Sie, dass das zurückgesendete Paket um 2.007602 Sekunden an der Quelle ankommt,
Lesen aus Datei second-0-0.pcap, Link-Type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, Länge 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, Länge 1024
Denken Sie abschließend daran, dass wir die Möglichkeit hinzugefügt haben, die Anzahl der CSMA-Geräte im
Simulation durch Befehlszeilenargument. Sie können dieses Argument genauso ändern wie wenn
Wir haben uns angesehen, die Anzahl der Pakete zu ändern, die in der zuerst.cc Beispiel. Versuchen Sie zu laufen
das Programm mit der Anzahl der "zusätzlichen" Geräte auf vier:
$ ./waf --run "scratch/mysecond --nCsma=4"
Sie sollten jetzt sehen,
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.405s)
Zum Zeitpunkt 2s sendete der Client 1024 Bytes an 10.1.2.5 Port 9
Zum Zeitpunkt 2.0118s erhielt der Server 1024 Bytes von 10.1.1.1 Port 49153
Zum Zeitpunkt 2.0118s sendete der Server 1024 Bytes an 10.1.1.1 Port 49153
Zum Zeitpunkt 2.02461s Client erhielt 1024 Bytes von 10.1.2.5 Port 9
Beachten Sie, dass der Echo-Server jetzt zum letzten der CSMA-Knoten verschoben wurde, d. h
10.1.2.5 statt Standardfall, 10.1.2.4.
Es ist möglich, dass Sie mit einer Trace-Datei, die von einem Umstehenden in erstellt wurde, nicht zufrieden sind
das CSMA-Netzwerk. Vielleicht möchten Sie wirklich eine Spur von einem einzelnen Gerät erhalten und möglicherweise nicht
an anderen Datenverkehr im Netzwerk interessiert sein. Sie können dies ziemlich einfach tun.
Lassen Sie uns einen Blick darauf werfen scratch/mysecond.cc und füge diesen Code hinzu, damit wir mehr sein können
her. NS-3 Helfer bieten Methoden, die eine Knotennummer und eine Gerätenummer als
Parameter. Mach weiter und ersetze die Aktivieren Sie Pcap ruft mit den unten stehenden Anrufen an.
pointToPoint.EnablePcap ("zweite", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("zweite", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("zweite", csmaNodes.Get (nCsma-1)->GetId (), 0, false);
Wir wissen, dass wir eine pcap-Datei mit dem Basisnamen "Second" erstellen möchten und wir wissen es auch
dass das interessierende Gerät in beiden Fällen Null sein wird, also sind diese Parameter nicht
wirklich interessant.
Um die Knotennummer zu erhalten, haben Sie zwei Möglichkeiten: Erstens werden die Knoten in a . nummeriert
monoton ansteigende Mode, beginnend bei Null in der Reihenfolge, in der Sie erstellt haben
Ihnen. Eine Möglichkeit, eine Knotennummer zu erhalten, besteht darin, diese Nummer "manuell" herauszufinden, indem Sie
Betrachtung der Reihenfolge der Knotenerstellung. Wenn Sie sich die Netzwerktopologie ansehen
Abbildung am Anfang der Datei, das haben wir für Sie gemacht und Sie können sehen, dass die
Der letzte CSMA-Knoten wird die Knotennummer sein nCsma + 1. Dieser Ansatz kann nervig werden
in größeren Simulationen schwierig.
Ein alternativer Weg, den wir hier verwenden, besteht darin, zu erkennen, dass die NodeContainer enthalten
Zeiger auf NS-3 Knoten Objekte. Das Knoten Objekt hat eine Methode namens GetId welches wird
Geben Sie die ID dieses Knotens zurück, die die gesuchte Knotennummer ist. Werfen wir einen Blick auf die
Doxygen für die Knoten und suchen Sie diese Methode, die weiter unten im NS-3 Kerncode
als wir bisher gesehen haben; aber manchmal muss man fleißig nach nützlichen Dingen suchen.
Rufen Sie die Doxygen-Dokumentation für Ihre Veröffentlichung auf (denken Sie daran, dass Sie sie auf der
Projektwebsite). Sie können zum Knoten Dokumentation durch Durchsehen der
Registerkarte "Klassen" und scrollen Sie in der "Klassenliste" nach unten, bis Sie finden ns3::Knoten. Wählen
ns3::Knoten und Sie gelangen zur Dokumentation für die Knoten Klasse. Wenn du jetzt
scrollen Sie nach unten zu GetId Methode und wählen Sie diese aus, Sie werden zum ausführlichen
Dokumentation zur Methode. Verwendung der GetId Methode kann die Bestimmung von Knotennummern ermöglichen
viel einfacher in komplexen Topologien.
Lassen Sie uns die alten Trace-Dateien aus dem Verzeichnis der obersten Ebene löschen, um Verwirrung zu vermeiden
Was ist los,
$rm *.pcap
$rm *.tr
Wenn Sie das neue Skript erstellen und die Simulationseinstellung ausführen nCsma zu 100,
$ ./waf --run "scratch/mysecond --nCsma=100"
Sie sehen die folgende Ausgabe:
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.407s)
Zum Zeitpunkt 2s sendete der Client 1024 Bytes an 10.1.2.101 Port 9
Zum Zeitpunkt 2.0068s erhielt der Server 1024 Bytes von 10.1.1.1 Port 49153
Zum Zeitpunkt 2.0068s sendete der Server 1024 Bytes an 10.1.1.1 Port 49153
Zum Zeitpunkt 2.01761s Client erhielt 1024 Bytes von 10.1.2.101 Port 9
Beachten Sie, dass sich der Echo-Server jetzt am 10.1.2.101 befindet, was 100 entspricht
"extra" CSMA-Knoten mit dem Echo-Server auf dem letzten. Wenn Sie die pcap-Dateien in auflisten
das Verzeichnis der obersten Ebene, das Sie sehen werden,
second-0-0.pcap second-100-0.pcap second-101-0.pcap
Die Trace-Datei zweite-0-0.pcap ist das "ganz links" Punkt-zu-Punkt-Gerät, das das Echo ist
Paketquelle. Die Datei zweite-101-0.pcap entspricht dem CSMA-Gerät ganz rechts, das
Hier befindet sich der Echo-Server. Sie haben vielleicht bemerkt, dass der letzte Parameter auf dem
Aufruf zum Aktivieren der pcap-Ablaufverfolgung auf dem Echo-Serverknoten war falsch. Dies bedeutet, dass die Spur
gesammelt auf diesem Knoten befand sich im nicht-promiskuitiven Modus.
Um den Unterschied zwischen promiskuitiven und nicht promiskuitiven Spuren zu veranschaulichen, haben wir auch
forderte einen nicht-promiskuitiven Trace für den vorletzten Knoten an. Mach weiter und sieh es dir an
tcpdump für zweite-100-0.pcap.
$ tcpdump -nn -tt -r second-100-0.pcap
Sie können jetzt sehen, dass der Knoten 100 wirklich ein Zuschauer im Echoaustausch ist. Das einzige
Pakete, die es empfängt, sind die ARP-Anfragen, die an die gesamte CSMA gesendet werden
Netzwerk.
Lesen aus Datei second-100-0.pcap, Link-Typ EN10MB (Ethernet)
2.006698 ARP, Abfrage wer-hat 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, Länge 50
2.013815 ARP, Abfrage wer-hat 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, Länge 50
Schauen Sie sich jetzt die an tcpdump für zweite-101-0.pcap.
$ tcpdump -nn -tt -r second-101-0.pcap
Sie können nun sehen, dass Knoten 101 wirklich der Teilnehmer am Echoaustausch ist.
Lesen aus Datei second-101-0.pcap, Link-Typ EN10MB (Ethernet)
2.006698 ARP, Abfrage wer-hat 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, Länge 50
2.006698 ARP, Antwort 10.1.2.101 is-at 00:00:00:00:00:67, Länge 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, Länge 1024
2.013803 ARP, Abfrage wer-hat 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, Länge 50
2.013828 ARP, Antwort 10.1.2.1 is-at 00:00:00:00:00:03, Länge 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, Länge 1024
Models, Attribute und Realität
Dies ist ein bequemer Ort, um einen kleinen Ausflug zu machen und einen wichtigen Punkt zu machen. Es kann
oder für Sie vielleicht nicht offensichtlich, aber wenn Sie eine Simulation verwenden, ist es wichtig,
verstehen genau, was modelliert wird und was nicht. Es ist verlockend, zum Beispiel zu
Stellen Sie sich die CSMA-Geräte und -Kanäle vor, die im vorherigen Abschnitt verwendet wurden, als wären sie echt
Ethernet-Geräte; und zu erwarten, dass ein Simulationsergebnis direkt widerspiegelt, was passieren wird
in einem echten Ethernet. Das ist nicht der Fall.
Ein Modell ist per Definition eine Abstraktion der Realität. Es liegt letztendlich in der Verantwortung
des Simulationsskript-Autors zur Ermittlung des sogenannten "Genauigkeitsbereichs" und "Domain
der Anwendbarkeit" der Simulation als Ganzes und damit ihrer Bestandteile.
In einigen Fällen, wie Csma, es kann ziemlich einfach sein zu bestimmen, was ist nicht modelliert. Durch
Lesen Sie die Modellbeschreibung (csma.h) können Sie feststellen, dass es keine Kollisionserkennung gibt
im CSMA-Modell und entscheiden Sie, wie anwendbar seine Verwendung in Ihrer Simulation sein wird oder was
Vorbehalte, die Sie möglicherweise in Ihre Ergebnisse aufnehmen möchten. In anderen Fällen kann es ganz einfach sein
um Verhaltensweisen zu konfigurieren, die möglicherweise nicht mit der Realität übereinstimmen, die Sie kaufen können. Es
Es wird sich als lohnenswert erweisen, einige Zeit damit zu verbringen, ein paar solcher Fälle zu untersuchen, und wie?
leicht können Sie in Ihren Simulationen die Grenzen der Realität verlassen.
Wie du gesehen hast, NS-3 bietet Attribute die ein Benutzer leicht einstellen kann, um das Modell zu ändern
Verhalten. Betrachten Sie zwei der Attribute dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog. CsmaNetDevice: Mtu und
Kapselungsmodusdem „Vermischten Geschmack“. Seine Mtu Attribut gibt die maximale Übertragungseinheit an die
Gerät. Dies ist die Größe der größten Protocol Data Unit (PDU), die das Gerät verarbeiten kann
senden.
Die MTU ist standardmäßig auf 1500 Byte im CsmaNetDevice. Diese Vorgabe entspricht einer Zahl
gefunden in RFC 894, "A Standard for the Transmission of IP Datagrams over Ethernet"
Netzwerke." Die Zahl leitet sich eigentlich von der maximalen Paketgröße für 10Base5 . ab
(Full-Spec-Ethernet) Netzwerke -- 1518 Byte. Wenn Sie die DIX-Kapselung abziehen
Overhead für Ethernet-Pakete (18 Byte) erhalten Sie eine maximal mögliche Datengröße
(MTU) von 1500 Byte. Man kann auch feststellen, dass die MTU für IEEE 802.3-Netzwerke ist 1492
Bytes. Dies liegt daran, dass die LLC/SNAP-Kapselung zusätzliche acht Byte an Overhead hinzufügt
das Paket. In beiden Fällen kann die zugrunde liegende Hardware nur 1518 Byte senden, aber die Daten
größe ist unterschiedlich.
Um den Kapselungsmodus einzustellen, CsmaNetDevice bietet ein Attribut namens
Kapselungsmodus die die Werte annehmen können Dix or GMBH. Diese entsprechen Ethernet
bzw. LLC/SNAP-Framing.
Wenn man das verlässt Mtu bei 1500 Byte und ändert den Kapselungsmodus auf GMBH, das Ergebnis
wird ein Netzwerk sein, das 1500-Byte-PDUs mit LLC/SNAP-Framing kapselt, was zu
Pakete von 1526 Byte, was in vielen Netzwerken illegal wäre, da sie a
maximal 1518 Byte pro Paket. Dies würde höchstwahrscheinlich zu einer Simulation führen, die
ganz subtil spiegelt nicht die Realität wider, die Sie vielleicht erwarten.
Um das Bild zu verkomplizieren, gibt es Jumbo-Frames (1500 < MTU <= 9000 Byte) und
Super-Jumbo (MTU > 9000 Byte) Frames, die nicht offiziell von IEEE sanktioniert, aber
in einigen Hochgeschwindigkeitsnetzwerken (Gigabit) und NICs verfügbar. Man könnte die lassen
Kapselungsmodus auf eingestellt Dixund stellen Sie die Mtu Attribut auf einem CsmaNetDevice bis 64000 Byte
-- obwohl ein assoziierter CsmaChannel Datenrate wurde auf 10 Megabit pro Sekunde eingestellt. Dies
würde im Wesentlichen einen Ethernet-Switch modellieren, der aus von Vampiren angezapftem 1980Base10 im Stil der 5er Jahre besteht
Netzwerke, die Super-Jumbo-Datagramme unterstützen. Das war sicher nicht so
jemals erstellt wurde und wahrscheinlich auch nie hergestellt werden wird, aber es ist für Sie recht einfach zu konfigurieren.
Im vorherigen Beispiel haben Sie die Befehlszeile verwendet, um eine Simulation mit 100 . zu erstellen
Csma Knoten. Genauso einfach hätten Sie eine Simulation mit 500 Knoten erstellen können. wenn du
modellierten tatsächlich das 10Base5-Vampire-Tap-Netzwerk, die maximale Länge eines Full-Spec
Das Ethernet-Kabel ist 500 Meter lang, mit einem Mindestabstand von 2.5 Metern. Das heißt dort
könnten nur 200 Taps in einem echten Netzwerk sein. Du hättest ganz leicht einen illegalen bauen können
auch so vernetzen. Dies kann zu einer sinnvollen Simulation führen oder auch nicht
je nachdem, was Sie modellieren möchten.
Ähnliche Situationen können vielerorts in NS-3 und in jedem Simulator. Beispielsweise,
Sie können Knoten möglicherweise so positionieren, dass sie den gleichen Platz an der einnehmen
gleichzeitig, oder Sie können möglicherweise Verstärker oder Rauschpegel konfigurieren, die gegen die
Grundgesetze der Physik.
NS-3 begünstigt im Allgemeinen Flexibilität, und viele Modelle ermöglichen eine freie Einstellung Attribute
ohne zu versuchen, eine willkürliche Konsistenz oder eine bestimmte zugrunde liegende Spezifikation durchzusetzen.
Das kann man davon mit nach Hause nehmen NS-3 wird eine superflexible Basis bieten
damit Sie experimentieren können. Es liegt an Ihnen zu verstehen, was Sie vom System verlangen
zu tun und sicherzustellen, dass die von Ihnen erstellten Simulationen eine gewisse Bedeutung haben und einige
Verbindung mit einer von Ihnen definierten Realität.
zum a Wireless Network Topologie
In dieser Rubrik werden wir unser Wissen über NS-3 Netzwerkgeräte und
Kanäle, um ein Beispiel für ein drahtloses Netzwerk abzudecken. NS-3 bietet eine Reihe von 802.11-Modellen
die versuchen, eine genaue MAC-Level-Implementierung der 802.11-Spezifikation bereitzustellen
und ein "nicht so langsames" PHY-Level-Modell der 802.11a-Spezifikation.
Genauso wie wir sowohl Punkt-zu-Punkt- als auch CSMA-Topologie-Hilfsobjekte gesehen haben, wenn
Wenn wir Punkt-zu-Punkt-Topologien konstruieren, werden wir Äquivalente sehen WLAN Topologie-Helfer in
diese Abteilung. Das Aussehen und die Bedienung dieser Helfer sollte Ihnen ziemlich bekannt vorkommen
Sie.
Wir bieten ein Beispielskript in unserem Beispiele/Tutorial Verzeichnis. Dieses Skript baut auf
zweite.cc Skript und fügt ein Wifi-Netzwerk hinzu. Mach weiter und öffne
Beispiele/Tutorial/Third.cc in Ihrem Lieblingseditor. Ihr werdet schon genug gesehen haben
NS-3 Code, um das meiste von dem zu verstehen, was in diesem Beispiel vor sich geht, aber es gibt ein paar neue
Dinge, also werden wir das gesamte Skript durchgehen und einen Teil der Ausgabe untersuchen.
Genau wie im zweite.cc Beispiel (und insgesamt NS-3 Beispiele) die Datei beginnt mit einem emacs
mode-Zeile und einige GPL-Boilerplate.
Sehen Sie sich die ASCII-Grafik (unten wiedergegeben) an, die die Standard-Netzwerktopologie zeigt
im Beispiel aufgebaut. Sie sehen, dass wir unser Beispiel noch weiter ausbauen werden
indem Sie ein drahtloses Netzwerk von der linken Seite abhängen. Beachten Sie, dass dies ein Standardnetzwerk ist
Topologie, da Sie die Anzahl der Knoten, die auf dem kabelgebundenen und dem kabellosen Netzwerk erstellt werden, tatsächlich variieren können
Netzwerke. Genau wie im zweite.cc Skriptfall, wenn Sie sich ändern nCsma, es wird dir einen geben
Anzahl "zusätzlicher" CSMA-Knoten. Ebenso können Sie einstellen nWLAN um zu kontrollieren, wie viele STA
(Stations-)Knoten werden in der Simulation erstellt. Es wird immer einen geben AP (Zugangspunkt)
Knoten im drahtlosen Netzwerk. Standardmäßig gibt es drei "zusätzliche" CSMA-Knoten und drei
kabellos STA Knoten.
Der Code beginnt mit dem Laden von Include-Dateien des Moduls, genau wie im zweite.cc Beispiel.
Es gibt ein paar neue Features, die dem Wifi-Modul und der Mobilität entsprechen
Modul, das wir im Folgenden besprechen werden.
#include "ns3/core-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/network-module.h"
#include "ns3/applications-module.h"
#include "ns3/wifi-module.h"
#include "ns3/mobility-module.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
Die Abbildung der Netzwerktopologie folgt:
// Standard-Netzwerktopologie
//
// WLAN 10.1.3.0
// AP
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// Punkt-zu-Punkt | | | |
// ================
//LAN 10.1.2.0
Sie können sehen, dass wir dem Knoten auf der linken Seite des ein neues Netzwerkgerät hinzufügen
Punkt-zu-Punkt-Verbindung, die zum Zugangspunkt für das drahtlose Netzwerk wird. Eine Anzahl von
drahtlose STA-Knoten werden erstellt, um das neue 10.1.3.0-Netzwerk wie links gezeigt auszufüllen
Seite der Abbildung.
Nach der Veranschaulichung NS-3 Namensraum ist benutzt und eine Protokollierungskomponente wird definiert.
Das sollte jetzt alles ziemlich bekannt sein.
Verwenden des Namensraums ns3;
NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");
Das Hauptprogramm beginnt wie zweite.cc durch Hinzufügen einiger Befehlszeilenparameter für
Aktivieren oder Deaktivieren von Protokollierungskomponenten und zum Ändern der Anzahl der erstellten Geräte.
bool verbose = wahr;
uint32_tnCsma = 3;
uint32_t nWifi = 3;
Befehlszeile cmd;
cmd.AddValue ("nCsma", "Anzahl \"zusätzlicher\" CSMA-Knoten/Geräte", nCsma);
cmd.AddValue ("nWifi", "Anzahl der WLAN-STA-Geräte", nWifi);
cmd.AddValue ("ausführlich", "Echo-Anwendungen anweisen, zu protokollieren, wenn wahr", ausführlich);
cmd.Parse (argc, argv);
wenn (ausführlich)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}
Wie in allen vorherigen Beispielen besteht der nächste Schritt darin, zwei Knoten zu erstellen, die wir
über die Punkt-zu-Punkt-Verbindung verbinden.
NodeContainer p2pNodes;
p2pNodes.Create (2);
Als nächstes sehen wir einen alten Freund. Wir instanziieren a PointToPointHelper und stellen Sie das zugehörige
Standard Attribute damit wir auf Geräten einen Sender mit fünf Megabit pro Sekunde erstellen
erstellt mit dem Helfer und einer Verzögerung von zwei Millisekunden auf Kanälen, die vom Helfer erstellt wurden.
Wir haben dann Gesamt die Geräte auf den Knoten und den Kanal zwischen ihnen.
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);
Als nächstes erklären wir ein anderes NodeContainer um die Knoten zu halten, die Teil des Busses sein werden
(CSMA) Netzwerk.
NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);
Die nächste Codezeile Ruft der erste Knoten (als ob er einen Index von eins hätte) aus dem
Punkt-zu-Punkt-Knotencontainer und fügt ihn dem Container der Knoten hinzu, die CSMA erhalten
Geräte. Der fragliche Knoten wird mit einem Punkt-zu-Punkt-Gerät und einem CSMA enden
Gerät. Wir erstellen dann eine Reihe von "zusätzlichen" Knoten, die den Rest des CSMA bilden
Netzwerk.
Wir instanziieren dann a CsmaHelper und setzen Sie seine Attribute wie im vorherigen Beispiel.
Wir schaffen eine NetDeviceContainer um den Überblick über die erstellten CSMA-Netzgeräte zu behalten und dann wir
Installieren CSMA-Geräte auf den ausgewählten Knoten.
CsmaHelper-csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));
NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);
Als nächstes werden wir die Knoten erstellen, die Teil des Wifi-Netzwerks sein werden. Wir sind
eine Anzahl von "Station"-Knoten erstellen, wie durch das Befehlszeilenargument angegeben, und
Wir werden den Knoten "ganz links" der Punkt-zu-Punkt-Verbindung als Knoten für die
Zugangspunkt.
NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);
Das nächste Bit des Codes konstruiert die WLAN-Geräte und den Verbindungskanal zwischen
diese WLAN-Knoten. Zuerst konfigurieren wir die PHY- und Kanal-Helfer:
YansWifiChannelHelper-Kanal = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Default ();
Der Einfachheit halber verwendet dieser Code die Standardkonfiguration der PHY-Schicht und die Kanalmodelle
die in der API-Doxygen-Dokumentation für die . dokumentiert sind
YansWifiChannelHelper::Standard und YansWifiPhyHelper::Standard Methoden. Sobald diese Objekte
erstellt werden, erstellen wir ein Kanalobjekt und verknüpfen es mit unserem PHY-Schichten-Objektmanager
um sicherzustellen, dass alle PHY-Schichtobjekte, die von der YansWifiPhyHelper Aktien der
gleichen zugrunde liegenden Kanal, d. h. sie teilen sich das gleiche drahtlose Medium und können
Kommunikation und Einmischung:
phy.SetChannel (channel.Create());
Sobald der PHY-Helfer konfiguriert ist, können wir uns auf die MAC-Schicht konzentrieren. Hier entscheiden wir uns zu arbeiten
mit Nicht-Qos-MACs, daher verwenden wir ein NqosWifiMacHelper-Objekt, um MAC-Parameter einzustellen.
WifiHelper wifi = WifiHelper::Default ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");
NqosWifiMacHelper mac = NqosWifiMacHelper::Default ();
Die SetRemoteStationManager Methode teilt dem Helfer den Typ des Ratensteuerungsalgorithmus mit
benutzen. Hier fordert es den Helfer auf, den AARF-Algorithmus zu verwenden --- Details sind natürlich
erhältlich in Doxygen.
Als nächstes konfigurieren wir den MAC-Typ, die SSID des Infrastrukturnetzwerks, das wir wollen
Setup und stellen Sie sicher, dass unsere Stationen keine aktive Sondierung durchführen:
Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
"Ssid", SsidValue (ssid),
"ActiveProbing", Boolescher Wert (falsch));
Dieser Code erstellt zuerst ein 802.11 Service Set Identifier (SSID)-Objekt, das verwendet wird
um den Wert von "Ssid" einzustellen Attribut der MAC-Schicht-Implementierung. Das Besondere
Art der MAC-Schicht, die vom Helfer erstellt wird, wird angegeben durch Attribut als von
der Typ "ns3::StaWifiMac". Die Verwendung von NqosWifiMacHelper wird sicherstellen, dass die
"Qosunterstützt" Attribut für erstellte MAC-Objekte wird auf false gesetzt. Die Kombination aus diesen
zwei Konfigurationen bedeutet, dass die als nächstes erstellte MAC-Instanz ein Nicht-QoS-Nicht-AP ist
Station (STA) in einem Infrastruktur-BSS (dh einem BSS mit einem AP). Endlich, das
"ActiveProbing" Attribut ist auf false gesetzt. Das bedeutet, dass Sondierungsanfragen nicht
von MACs gesendet, die von diesem Helfer erstellt wurden.
Sobald alle stationsspezifischen Parameter vollständig konfiguriert sind, sowohl am MAC als auch am PHY
Schichten, können wir uns auf unser jetzt Vertrautes berufen Installieren Methode, um die WLAN-Geräte dieser zu erstellen
Stationen:
NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);
Wir haben Wifi für alle unsere STA-Knoten konfiguriert und müssen jetzt den AP konfigurieren
(Zugangspunkt) Knoten. Wir beginnen diesen Prozess, indem wir die Standardeinstellung ändern Attribute dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog.
NqosWifiMacHelper um die Anforderungen des AP widerzuspiegeln.
mac.SetType ("ns3::ApWifiMac",
"Ssid", SsidValue (ssid));
In diesem Fall NqosWifiMacHelper wird MAC-Layer des "ns3::ApWifiMac" erstellen,
Letzteres legt fest, dass eine als AP konfigurierte MAC-Instanz erstellt werden soll, mit dem
Hilfstyp, der andeutet, dass "QosSupported" Attribut sollte auf false gesetzt werden - deaktivieren
QoS-Unterstützung im 802.11e/WMM-Stil bei erstellten APs.
Die nächsten Zeilen erstellen den einzelnen AP, der die gleichen PHY-Level teilt Attribute (und
Kanal) als Sender:
NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);
Jetzt werden wir Mobilitätsmodelle hinzufügen. Wir möchten, dass die STA-Knoten mobil sind und wandern
innerhalb eines Begrenzungsrahmens herum, und wir möchten den AP-Knoten stationär machen. Wir benutzen das
Mobilitätshelfer um uns das leicht zu machen. Zuerst instanziieren wir a Mobilitätshelfer Objekt
und setze etwas Attribute Steuerung der Funktion "Positionszuordner".
MobilitätHelfermobilität;
mobility.SetPositionAllocator ("ns3::GridPositionAllocator",
"MinX", DoubleValue (0.0),
"MinY", DoubleValue (0.0),
"DeltaX", DoubleValue (5.0),
"DeltaY", DoubleValue (10.0),
"GridWidth", UintegerValue (3),
"LayoutType", StringValue ("RowFirst"));
Dieser Code weist den Mobilitätshelfer an, ein zweidimensionales Raster zu verwenden, um die
STA-Knoten. Fühlen Sie sich frei, das Doxygen für den Unterricht zu erkunden ns3::GridPositionAllocator um zu sehen,
genau was gemacht wird.
Wir haben unsere Knoten in einem anfänglichen Raster angeordnet, aber jetzt müssen wir ihnen sagen, wie sie sich bewegen sollen.
Wir wählen die Randomwalk2dmobilityModel bei dem sich die Knoten in eine zufällige Richtung bewegen bei
eine zufällige Geschwindigkeit innerhalb eines Begrenzungsrahmens.
mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Grenzen", RectangleValue (Rechteck (-50, 50, -50, 50)));
Wir sagen jetzt die Mobilitätshelfer um die Mobilitätsmodelle auf den STA-Knoten zu installieren.
Mobilität.Installieren (wifiStaNodes);
Wir möchten, dass der Access Point während der Simulation an einer festen Position bleibt. Wir
erreichen Sie dies, indem Sie das Mobilitätsmodell für diesen Knoten so einstellen, dass es
ns3::ConstantPositionMobilityModel:
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
Mobilität.Installieren (wifiApNode);
Wir haben jetzt unsere Knoten, Geräte und Kanäle erstellt und Mobilitätsmodelle für die . ausgewählt
Wifi-Knoten, aber wir haben keine Protokollstapel vorhanden. So wie wir es zuvor schon viele gemacht haben
mal werden wir die InternetStackHelper um diese Stacks zu installieren.
InternetStackHelper-Stack;
stack.Installieren (csmaNodes);
stack.Installieren (wifiApNode);
stack.Install (wifiStaNodes);
Genau wie im zweite.cc Beispielskript verwenden wir das IPv4AddressHelper zu
unseren Geräteschnittstellen IP-Adressen zuweisen. Zuerst verwenden wir das Netzwerk 10.1.1.0 um
die beiden Adressen, die für unsere beiden Punkt-zu-Punkt-Geräte benötigt werden. Dann verwenden wir das Netzwerk 10.1.2.0
um dem CSMA-Netzwerk Adressen zuzuweisen und dann weisen wir Adressen aus dem Netzwerk 10.1.3.0 zu
sowohl zu den STA-Geräten als auch zum AP im drahtlosen Netzwerk.
IPv4AddressHelper-Adresse;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfaces;
p2pInterfaces = address.Assign (p2pDevices);
address.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = address.Assign (csmaDevices);
address.SetBase ("10.1.3.0", "255.255.255.0");
Adresse.Zuordnen (staDevices);
Adresse.Assign (apDevices);
Wir setzen den Echo-Server auf den "ganz rechts"-Knoten in der Abbildung am Anfang des
Datei. Wir haben dies bereits getan.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Sekunden (1.0));
serverApps.Stop (Sekunden (10.0));
Und wir legen den Echo-Client auf den letzten STA-Knoten, den wir erstellt haben, und verweisen ihn auf den Server auf
das CSMA-Netzwerk. Ähnliche Operationen haben wir auch schon erlebt.
UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Sekunden (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));
ApplicationContainer-ClientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Sekunden (2.0));
clientApps.Stop (Sekunden (10.0));
Da wir hier ein Internetwork aufgebaut haben, müssen wir ebenso das Internetwork-Routing aktivieren
wir haben in der zweite.cc Beispielskript.
Ipv4GlobalRoutingHelper::RoutingTables bevölkern ();
Eine Sache, die einige Benutzer überraschen kann, ist die Tatsache, dass die Simulation, die wir gerade erstellt haben
wird nie "natürlich" aufhören. Dies liegt daran, dass wir den Wireless Access Point gebeten haben,
Leuchtfeuer erzeugen. Es wird für immer Beacons generieren, und dies führt zu einem Simulator
Ereignisse, die auf unbestimmte Zeit in die Zukunft geplant sind, also müssen wir dem Simulator sagen, dass er aufhören soll
obwohl möglicherweise Beacon-Generierungsereignisse geplant sind. Die folgende Codezeile
sagt dem Simulator, dass er anhalten soll, damit wir nicht für immer Beacons simulieren und eingeben, was ist
im Wesentlichen eine Endlosschleife.
Simulator::Stop (Sekunden (10.0));
Wir erstellen gerade genug Tracing, um alle drei Netzwerke abzudecken:
pointToPoint.EnablePcapAll ("dritte");
phy.EnablePcap ("dritter", apDevices.Get (0));
csma.EnablePcap ("dritte", csmaDevices.Get (0), true);
Diese drei Codezeilen starten die pcap-Ablaufverfolgung auf beiden Punkt-zu-Punkt-Knoten, die
dient als unser Rückgrat, startet einen promiskuitiven (Monitor-) Modus-Trace im Wifi-Netzwerk,
und startet einen promiskuitiven Trace im CSMA-Netzwerk. Dies wird uns alle sehen lassen
Datenverkehr mit einer minimalen Anzahl von Trace-Dateien.
Schließlich führen wir die Simulation tatsächlich aus, bereinigen und beenden dann das Programm.
Simulator::Run ();
Simulator::Zerstören ();
Rückkehr 0;
}
Um dieses Beispiel auszuführen, müssen Sie die dritte.cc Beispielskript in die
Scratch-Verzeichnis und verwenden Sie Waf, um genau so zu erstellen, wie Sie es mit dem gemacht haben zweite.cc Beispiel. wenn du
befinden sich im obersten Verzeichnis des Repositorys, das Sie eingeben würden,
$ cp Beispiele/tutorial/third.cc scratch/mythird.cc
$ ./waf
$ ./waf --run scratch/mythird
Da wir die UDP-Echo-Anwendungen genauso eingerichtet haben wie im zweite.cc
script, sehen Sie eine ähnliche Ausgabe.
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' eingeben
Waf: Verlassen des Verzeichnisses `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' erfolgreich abgeschlossen (0.407s)
Zum Zeitpunkt 2s sendete der Client 1024 Bytes an 10.1.2.4 Port 9
Zum Zeitpunkt 2.01796s erhielt der Server 1024 Bytes von 10.1.3.3 Port 49153
Zum Zeitpunkt 2.01796s sendete der Server 1024 Bytes an 10.1.3.3 Port 49153
Zum Zeitpunkt 2.03364s Client erhielt 1024 Bytes von 10.1.2.4 Port 9
Denken Sie daran, dass die erste Nachricht, Sent 1024 Bytes zu 10.1.2.4," ist der UDP-Echo-Client
ein Paket an den Server senden. In diesem Fall befindet sich der Client im drahtlosen Netzwerk
(10.1.3.0). Die zweite Nachricht "Empfangene 1024 Bytes für 10.1.3.3," stammt aus dem UDP-Echo
Server, der generiert wird, wenn er das Echopaket empfängt. Die letzte Nachricht "Empfangene 1024
Bytes für 10.1.2.4," kommt vom Echo-Client und zeigt an, dass er sein Echo empfangen hat
vom Server zurück.
Wenn Sie nun im obersten Verzeichnis nachsehen, finden Sie vier Trace-Dateien von
dieser Simulation, zwei von Knoten Null und zwei von Knoten eins:
third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap
Die Datei "dritter-0-0.pcap" entspricht dem Punkt-zu-Punkt-Gerät auf Knoten Null -- die
linke Seite des "Rückgrats". Die Datei "dritter-1-0.pcap" entspricht dem Punkt-zu-Punkt
Gerät auf Knoten eins -- die rechte Seite des "Backbone". Die Datei "dritter-0-1.pcap" wird
den promiskuitiven (Monitormodus) Trace aus dem Wifi-Netzwerk und die Datei "third-1-1.pcap"
wird die promiskuitive Spur aus dem CSMA-Netzwerk sein. Können Sie dies überprüfen, indem Sie nachsehen?
der Code?
Da sich der Echo-Client im Wifi-Netzwerk befindet, beginnen wir dort. Werfen wir einen Blick auf die
promiskuitiver (Monitormodus) Trace, den wir in diesem Netzwerk erfasst haben.
$ tcpdump -nn -tt -r dritte-0-1.pcap
Sie sollten einige WLAN-ähnliche Inhalte sehen, die Sie hier noch nicht gesehen haben:
Lesen aus Datei Third-0-1.pcap, Link-Typ IEEE802_11 (802.11)
0.000025 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.000308 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000324 Acknowledgment RA:00:00:00:00:00:08
0.000402 Assoc-Antwort AID(0) :: Erfolgreich
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.000737 Acknowledgment RA:00:00:00:00:00:07
0.000824 Assoc-Antwort AID(0) :: Erfolgreich
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Assoc Request (ns-3-ssid) [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit]
0.001150 Acknowledgment RA:00:00:00:00:00:09
0.001273 Assoc-Antwort AID(0) :: Erfolgreich
0.001417 Acknowledgment RA:00:00:00:00:00:0a
0.102400 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.204800 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
0.307200 Beacon (ns-3-ssid) [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS
Sie können sehen, dass der Verbindungstyp jetzt wie erwartet 802.11 ist. Du kannst wahrscheinlich
Verstehen Sie, was vor sich geht und finden Sie die IP-Echo-Anfrage- und Antwortpakete darin
verfolgen. Wir belassen es als Übung, den Trace-Dump vollständig zu analysieren.
Sehen Sie sich nun die pcap-Datei auf der rechten Seite des Punkt-zu-Punkt-Links an.
$ tcpdump -nn -tt -r dritte-0-0.pcap
Auch hier sollten Sie einige vertraut aussehende Inhalte sehen:
Lesen aus der Datei Third-0-0.pcap, Link-Type PPP (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, Länge 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, Länge 1024
Dies ist das Echopaket, das von links nach rechts (von Wifi zu CSMA) und wieder zurück geht
die Punkt-zu-Punkt-Verbindung.
Sehen Sie sich nun die pcap-Datei auf der rechten Seite des Punkt-zu-Punkt-Links an.
$ tcpdump -nn -tt -r dritte-1-0.pcap
Auch hier sollten Sie einige vertraut aussehende Inhalte sehen:
Lesen aus der Datei Third-1-0.pcap, Link-Type PPP (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, Länge 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, Länge 1024
Dies ist auch das Echopaket, das von links nach rechts (von Wifi zu CSMA) und wieder zurück geht
über die Punkt-zu-Punkt-Verbindung mit etwas anderen Timings, als Sie vielleicht erwarten.
Der Echo-Server befindet sich im CSMA-Netzwerk, schauen wir uns die promiskuitive Spur dort an:
$ tcpdump -nn -tt -r dritte-1-1.pcap
Sie sollten einige vertraut aussehende Inhalte sehen:
Lesen aus Datei Third-1-1.pcap, Link-Typ EN10MB (Ethernet)
2.017837 ARP, Abfrage wer-hat 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, Länge 50
2.017861 ARP, Antwort 10.1.2.4 is-at 00:00:00:00:00:06, Länge 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, Länge 1024
2.022966 ARP, Abfrage wer-hat 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, Länge 50
2.022966 ARP, Antwort 10.1.2.1 is-at 00:00:00:00:00:03, Länge 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, Länge 1024
Dies sollte leicht zu verstehen sein. Wenn Sie es vergessen haben, gehen Sie zurück und sehen Sie sich die Diskussion an
in zweite.cc. Dies ist die gleiche Sequenz.
Jetzt haben wir viel Zeit damit verbracht, Mobilitätsmodelle für das drahtlose Netzwerk einzurichten, und so ist es
Es wäre eine Schande, fertig zu werden, ohne zu zeigen, dass sich die STA-Knoten tatsächlich bewegen
während der Simulation herum. Lassen Sie uns dies tun, indem Sie sich in die Mobilitätsmodell Kurs
Trace-Quelle ändern. Dies ist nur ein kleiner Einblick in den detaillierten Tracing-Bereich, der ist
kommen, aber dies scheint ein sehr schöner Ort zu sein, um ein Beispiel zu erhalten.
Wie im Abschnitt "Optimierung von ns-3" erwähnt, ist die NS-3 Tracing-System ist unterteilt in Trace
Quellen und Trace-Senken, und wir stellen Funktionen bereit, um die beiden zu verbinden. Wir werden die verwenden
Mobilitätsmodell vordefinierte Kursänderungs-Trace-Quelle, um die Trace-Ereignisse auszulösen. Wir
müssen eine Trace-Senke schreiben, um eine Verbindung zu dieser Quelle herzustellen, die einige hübsche Anzeigen anzeigt
Informationen für uns. Trotz seines Rufs als schwierig, ist es eigentlich ganz einfach.
Kurz vor dem Hauptprogramm der scratch/mythird.cc Skript (dh kurz nach dem
NS_LOG_COMPONENT_DEFINE Anweisung), fügen Sie die folgende Funktion hinzu:
ungültig
CourseChange (std::string Kontext, Ptr Modell)
{
Vektorposition = Modell->GetPosition ();
NS_LOG_UNCOND (Kontext <
" x = " << Position.x << ", y = " << Position.y);
}
Dieser Code holt sich einfach die Positionsinformationen aus dem Mobilitätsmodell und das bedingungslos
protokolliert die x- und y-Position des Knotens. Wir werden diese Funktion arrangieren
wird jedes Mal aufgerufen, wenn der Funkknoten mit dem Echo-Client seine Position ändert. Wir machen das
Verwendung der Konfig::Verbinden Funktion. Fügen Sie dem Skript einfach die folgenden Codezeilen hinzu
Vor dem Simulator::Ausführen Anruf.
std::ostringstream oss;
oss <
"/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () <
"/$ns3::MobilityModel/CourseChange";
Config::Connect (oss.str (), MakeCallback (&CourseChange));
Was wir hier tun, ist eine Zeichenfolge zu erstellen, die den Tracing-Namespace-Pfad des Ereignisses enthält
an die wir uns anschließen möchten. Zuerst müssen wir herausfinden, welchen Knoten wir verwenden möchten
GetId Methode wie zuvor beschrieben. Bei der Standardnummer von CSMA und
Wireless-Knoten, stellt sich heraus, dass dies Knoten sieben ist und der Tracing-Namespace-Pfad zum
Mobilitätsmodell aussehen würde,
/NodeList/7/$ns3::MobilityModel/CourseChange
Aus der Diskussion im Abschnitt zur Ablaufverfolgung können Sie schließen, dass dieser Ablaufverfolgungspfad
verweist auf den siebten Knoten in der globalen NodeList. Es gibt an, was an . genannt wird
aggregiertes Objekt vom Typ ns3::Mobilitätsmodell. Das Dollarzeichen-Präfix impliziert, dass die
MobilityModel wird auf Knoten sieben aggregiert. Die letzte Komponente des Pfades bedeutet, dass wir
haken sich in das "CourseChange"-Ereignis dieses Modells ein.
Wir stellen eine Verbindung zwischen der Trace-Quelle in Knoten sieben mit unserer Trace-Senke her, indem wir aufrufen
Konfig::Verbinden und Übergeben dieses Namespace-Pfads. Sobald dies erledigt ist, ändert sich jeder Kurs
Ereignis auf Knoten sieben wird in unsere Trace-Senke eingehakt, die wiederum die
neue Position.
Wenn Sie nun die Simulation ausführen, werden Ihnen die Kursänderungen so angezeigt, wie sie passieren.
'build' erfolgreich abgeschlossen (5.989s)
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.3841, y = 0.923277
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2049, y = 1.90708
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8136, y = 1.11368
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.8452, y = 2.11318
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.9797, y = 3.10409
Zum Zeitpunkt 2s sendete der Client 1024 Bytes an 10.1.2.4 Port 9
Zum Zeitpunkt 2.01796s erhielt der Server 1024 Bytes von 10.1.3.3 Port 49153
Zum Zeitpunkt 2.01796s sendete der Server 1024 Bytes an 10.1.3.3 Port 49153
Zum Zeitpunkt 2.03364s Client erhielt 1024 Bytes von 10.1.2.4 Port 9
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.3273, y = 4.04175
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.013, y = 4.76955
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.4317, y = 5.67771
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.4607, y = 5.91681
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.0155, y = 6.74878
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.0076, y = 6.62336
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.6285, y = 5.698
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.32, y = 4.97559
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.1134, y = 3.99715
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.8359, y = 4.68851
/NodeList/7/$ns3::MobilityModel/CourseChange x = 13.5953, y = 3.71789
/NodeList/7/$ns3::MobilityModel/CourseChange x = 12.7595, y = 4.26688
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.7629, y = 4.34913
/NodeList/7/$ns3::MobilityModel/CourseChange x = 11.2292, y = 5.19485
/NodeList/7/$ns3::MobilityModel/CourseChange x = 10.2344, y = 5.09394
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.3601, y = 4.60846
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.40025, y = 4.32795
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.14292, y = 4.99761
/NodeList/7/$ns3::MobilityModel/CourseChange x = 9.08299, y = 5.99581
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.26068, y = 5.42677
/NodeList/7/$ns3::MobilityModel/CourseChange x = 8.35917, y = 6.42191
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.66805, y = 7.14466
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.71414, y = 6.84456
/NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42489, y = 7.80181
TRACING
Hintergrund
Wie in UsingTracingSystem erwähnt, ist der Sinn der Ausführung eines NS-3 Simulation ist zu
Output für das Studium generieren. Sie haben zwei grundlegende Strategien, um eine Ausgabe von . zu erhalten NS-3:
Verwenden von generischen vordefinierten Massenausgabemechanismen und Parsing ihres Inhalts zum Extrahieren
interessante Information; oder irgendwie einen Ausgabemechanismus zu entwickeln, der genau vermittelt
(und vielleicht nur) die gewünschten Informationen.
Die Verwendung vordefinierter Massenausgabemechanismen hat den Vorteil, dass keine Änderungen erforderlich sind
NS-3, erfordert jedoch möglicherweise das Schreiben von Skripts zum Analysieren und Filtern nach interessierenden Daten. Oft,
PCAP oder NS_LOG Ausgabenachrichten werden während Simulationsläufen gesammelt und separat ausgeführt
durch Skripte, die verwenden grep, Durst or awk um die Nachrichten zu analysieren und zu reduzieren und zu transformieren
die Daten in eine überschaubare Form. Programme müssen geschrieben werden, um die Transformation durchzuführen, also dies
kommt nicht umsonst. NS_LOG Ausgabe wird nicht als Teil der NS-3 API und kann
zwischen den Veröffentlichungen ohne Vorwarnung ändern. In Ergänzung, NS_LOG Ausgabe ist nur verfügbar in
Debug-Builds, so dass das Vertrauen darauf eine Leistungseinbuße mit sich bringt. Natürlich, wenn die
Informationen von Interesse sind in keinem der vordefinierten Ausgabemechanismen vorhanden, dies
Ansatz scheitert.
Wenn Sie den vordefinierten Massenmechanismen einige Informationen hinzufügen müssen, kann dies
sicherlich getan werden; und wenn Sie eines der NS-3 Mechanismen, kann Ihr Code hinzugefügt werden
als Beitrag.
NS-3 bietet einen weiteren Mechanismus namens Tracing, der einige der inhärenten Probleme vermeidet
in den Massenausgabemechanismen. Es hat mehrere wichtige Vorteile. Zuerst kannst du
Reduzieren Sie die Datenmenge, die Sie verwalten müssen, indem Sie nur die Ereignisse verfolgen, die für Sie von Interesse sind
(Bei großen Simulationen kann das Ablegen aller Daten auf die Festplatte für die Nachbearbeitung E/A erzeugen
Engpässe). Zweitens können Sie mit dieser Methode das Ausgabeformat steuern
direkt, damit Sie den Nachbearbeitungsschritt mit vermeiden Durst, awk, perl or python Skripte. Wenn
Wenn Sie möchten, kann Ihre Ausgabe direkt in eine von gnuplot akzeptable Form formatiert werden, z
Beispiel (siehe auch GnuplotHelper). Sie können dem Kern Haken hinzufügen, die dann
auf die andere Benutzer zugreifen, die jedoch keine Informationen liefern, es sei denn, sie werden ausdrücklich dazu aufgefordert
tun Sie dies. Aus diesen Gründen glauben wir, dass die NS-3 Tracing-System ist der beste Weg, um zu bekommen
Informationen aus einer Simulation und ist damit auch einer der wichtigsten Mechanismen
verstehen in NS-3.
Blunt Instrumente
Es gibt viele Möglichkeiten, Informationen aus einem Programm zu erhalten. Der einfachste Weg ist
um die Informationen einfach direkt in die Standardausgabe zu drucken, wie in:
#einschließen
...
ungültig
SomeFunction (ungültig)
{
uint32_t x = EINIGE_INTERESSANTE_WERTE;
...
std::cout << "Der Wert von x ist " << x << std::endl;
...
}
Niemand wird dich daran hindern, tief in den Kern von . vorzudringen NS-3 und Druck hinzufügen
Aussagen. Das geht wahnsinnig einfach und du hast schließlich die volle Kontrolle über dein
besitzen NS-3 Ast. Das wird wohl auf Dauer nicht sehr zufriedenstellend ausfallen
Begriff, aber.
Da die Anzahl der print-Anweisungen in Ihren Programmen zunimmt, wird die Aufgabe, mit den
viele Ausgaben werden immer komplizierter. Irgendwann fühlst du dich vielleicht
die Notwendigkeit zu kontrollieren, welche Informationen auf irgendeine Weise gedruckt werden, vielleicht durch Einschalten
und aus bestimmten Kategorien von Drucken oder Erhöhen oder Verringern der Menge von
Informationen, die Sie möchten. Wenn Sie diesen Weg fortsetzen, werden Sie möglicherweise feststellen, dass Sie
neu implementiert NS_LOG (siehe UsingLogging). Um das zu vermeiden, einer von
Das erste, was Sie in Betracht ziehen könnten, ist die Verwendung NS_LOG sich.
Wir haben oben erwähnt, dass eine Möglichkeit, Informationen zu erhalten, aus NS-3 ist es, vorhandenes zu analysieren NS_LOG
Ausgabe für interessante Informationen. Wenn Sie feststellen, dass Sie einige Leckerbissen
In vorhandener Protokollausgabe muss nicht vorhanden sein, Sie könnten den Kern bearbeiten NS-3 und einfach hinzufügen
Ihre interessanten Informationen in den Ausgabestrom. Nun, das ist sicherlich besser als
Hinzufügen Ihrer eigenen print-Anweisungen, da folgt NS-3 Codierungskonventionen und könnte
möglicherweise für andere Leute als Patch für den bestehenden Kern nützlich sein.
Wählen wir ein zufälliges Beispiel. Wenn Sie der NS-3 TCP-Socket
(tcp-socket-base.cc) könnten Sie einfach eine neue Nachricht unten in der Implementierung hinzufügen. Notiz
das in TcpSocketBase::ReceivedAck() es gibt keine Protokollnachricht für den Fall ohne ACK. Sie
könnte einfach einen hinzufügen und den Code ändern. Hier ist das Original:
/** Neu empfangenes ACK verarbeiten */
ungültig
TcpSocketBase::ReceivedAck (Ptr Paket, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (dieser << tcpHeader);
// ACK erhalten. Vergleichen Sie die ACK-Nummer mit der höchsten nicht bestätigten Seqno
if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignorieren, wenn kein ACK-Flag
}
...
Um den No-ACK-Fall zu protokollieren, können Sie einen neuen hinzufügen NS_LOG_LOGIC begann if Anweisungstext:
/** Neu empfangenes ACK verarbeiten */
ungültig
TcpSocketBase::ReceivedAck (Ptr Paket, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (dieser << tcpHeader);
// ACK erhalten. Vergleichen Sie die ACK-Nummer mit der höchsten nicht bestätigten Seqno
if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignorieren, wenn kein ACK-Flag
NS_LOG_LOGIC ("TcpSocketBase " << dies << " kein ACK-Flag");
}
...
Dies mag auf den ersten Blick ziemlich einfach und befriedigend erscheinen, aber etwas, das es zu beachten gilt
dass Sie Code zum Hinzufügen schreiben werden NS_LOG Aussagen und Sie müssen auch schreiben
Code (wie in grep, Durst or awk -Skripte), um die Protokollausgabe zu parsen, um Ihre zu isolieren
Information. Dies liegt daran, dass Sie zwar eine gewisse Kontrolle darüber haben, was von ausgegeben wird
Protokollierungssystems haben Sie nur die Kontrolle bis hinunter zur Ebene der Protokollkomponenten, was normalerweise der Fall ist
eine ganze Quellcodedatei.
Wenn Sie Code zu einem vorhandenen Modul hinzufügen, müssen Sie auch mit der Ausgabe leben
die jeder andere Entwickler interessant fand. Sie können das finden, um die zu erhalten
Wenn Sie eine kleine Menge an Informationen benötigen, müssen Sie sich möglicherweise durch riesige Mengen von Informationen wühlen
irrelevante Nachrichten, die für Sie nicht von Interesse sind. Möglicherweise müssen Sie ein riesiges Protokoll speichern
Dateien auf die Festplatte und verarbeiten Sie sie bis auf wenige Zeilen, wann immer Sie etwas tun möchten.
Da es keine Garantien gibt NS-3 über die Stabilität von NS_LOG Ausgabe können Sie auch
Stellen Sie fest, dass Teile der Protokollausgabe, auf die Sie angewiesen sind, verschwinden oder zwischen ihnen wechseln
Freigaben. Wenn Sie sich auf die Struktur der Ausgabe verlassen, finden Sie möglicherweise andere Meldungen
hinzugefügt oder gelöscht, was sich auf Ihren Parsing-Code auswirken kann.
Schließlich NS_LOG Die Ausgabe ist nur in Debug-Builds verfügbar, von denen Sie keine Protokollausgabe erhalten können
optimierte Builds, die etwa doppelt so schnell laufen. Verlassen auf NS_LOG erzwingt eine Leistung
Strafe.
Aus diesen Gründen ziehen wir Drucke in Erwägung std :: cout und NS_LOG Nachrichten schnell sein und
schmutzige Wege, um mehr Informationen herauszuholen NS-3, aber nicht für ernsthafte Arbeiten geeignet.
Es ist wünschenswert, eine stabile Einrichtung zu haben, die stabile APIs verwendet, in die man hineingreifen kann
das Kernsystem und erhalten nur die erforderlichen Informationen. Es ist wünschenswert, dies tun zu können
ohne das Kernsystem ändern und neu kompilieren zu müssen. Noch besser wäre ein
System, das den Benutzercode benachrichtigt, wenn sich ein interessierender Punkt oder ein interessantes Ereignis geändert hat
passiert, damit der Benutzer nicht aktiv im System suchen muss
Dinge.
Die NS-3 Tracing-System wurde entwickelt, um in diese Richtung zu arbeiten und ist gut integriert mit
das Attribut und Config Subsysteme, die relativ einfache Anwendungsszenarien ermöglichen.
Übersicht
Die NS-3 Rückverfolgungssystem basiert auf den Konzepten unabhängiger Rückverfolgungsquellen und
Verfolgung von Senken, zusammen mit einem einheitlichen Mechanismus zum Verbinden von Quellen mit Senken.
Ablaufverfolgungsquellen sind Entitäten, die Ereignisse, die in einer Simulation auftreten, signalisieren und bereitstellen können
Zugang zu interessanten zugrunde liegenden Daten. Eine Ablaufverfolgungsquelle könnte beispielsweise anzeigen, wenn a
Paket wird von einem Netzgerät empfangen und bietet Zugriff auf den Paketinhalt für
interessierte Spurensenken. Eine Ablaufverfolgungsquelle kann auch anzeigen, wenn ein interessanter Zustand
Veränderung geschieht in einem Modell. Das Überlastungsfenster eines TCP-Modells ist beispielsweise eine Primzahl
Kandidat für eine Spurenquelle. Jedes Mal, wenn das Überlastungsfenster die verbundene Spur ändert
Senken werden mit dem alten und neuen Wert benachrichtigt.
Trace-Quellen allein sind nicht nützlich; sie müssen mit anderen Codestücken verbunden werden
die mit den von der Quelle bereitgestellten Informationen tatsächlich etwas Nützliches anstellen. Der
Entitäten, die Ablaufverfolgungsinformationen verbrauchen, werden als Ablaufverfolgungssenken bezeichnet. Spurenquellen sind
Datengeneratoren und Spurensenken sind Verbraucher. Diese explizite Aufteilung ermöglicht große
Anzahl von Spurenquellen, die an Stellen im System verstreut sind, die Autoren modellieren
glaube, könnte nützlich sein. Das Einfügen von Ablaufverfolgungsquellen führt zu einer sehr kleinen Ausführung
Overhead.
Es kann null oder mehr Konsumenten von Ablaufverfolgungsereignissen geben, die von einer Ablaufverfolgungsquelle generiert werden. Man kann
Stellen Sie sich eine Trace-Quelle als eine Art Punkt-zu-Mehrpunkt-Informationsverbindung vor. Dein Code
Die Suche nach Ablaufverfolgungsereignissen aus einem bestimmten Teil des Kerncodes könnte problemlos nebeneinander existieren
anderer Code tut etwas völlig anderes als die gleichen Informationen.
Wenn ein Benutzer eine Ablaufverfolgungssenke nicht mit einer dieser Quellen verbindet, wird nichts ausgegeben. Durch die Nutzung
das Ablaufverfolgungssystem, sowohl Sie als auch andere Personen, die an dieselbe Ablaufverfolgungsquelle angeschlossen sind, erhalten
genau das, was sie wollen, und nur das, was sie aus dem System herausholen wollen. Keiner von Ihnen ist
Auswirkungen auf andere Benutzer, indem geändert wird, welche Informationen vom System ausgegeben werden. Wenn du
Fügen Sie zufällig eine Trace-Quelle hinzu, die Ihre Arbeit als guter Open-Source-Bürger anderen ermöglichen kann
Benutzer können neue Dienstprogramme bereitstellen, die insgesamt vielleicht sehr nützlich sind, ohne sie zu erstellen
Änderungen an der NS-3 Ader.
Einfacher Beispiel
Nehmen wir uns ein paar Minuten Zeit und gehen wir ein einfaches Ablaufverfolgungsbeispiel durch. Wir werden brauchen
ein wenig Hintergrundinformationen zu Callbacks, um zu verstehen, was in dem Beispiel passiert, also wir
gleich einen kleinen Umweg nehmen.
Rückrufe
Das Ziel des Callback-Systems in NS-3 ist es, einem Stück Code zu erlauben, eine Funktion aufzurufen
(oder Methode in C++) ohne spezifische Inter-Modul-Abhängigkeit. Das bedeutet letztlich
Sie brauchen eine Art Umleitung – Sie behandeln die Adresse der aufgerufenen Funktion als a
Variable. Diese Variable wird Zeiger-auf-Funktion-Variable genannt. Die Beziehung
zwischen Funktion und Zeiger-auf-Funktion unterscheidet sich eigentlich nicht von Objekt und
Zeiger auf Objekt.
In C ist das kanonische Beispiel eines Zeigers auf eine Funktion a
Zeiger auf funktionsrückgebende Ganzzahl (PFI). Für einen PFI, der einen nimmt int Parameter, dieser
könnte so erklärt werden,
int (*pfi)(int arg) = 0;
(Aber lesen Sie die C++-FAQ Abschnitt 33 bevor Sie Code wie diesen schreiben!) Was Sie davon bekommen
ist eine einfach benannte Variable PFI das auf den Wert 0 initialisiert wird. Wenn Sie möchten
Initialisieren Sie diesen Zeiger auf etwas Sinnvolles, Sie müssen eine Funktion mit a haben
passende Signatur. In diesem Fall könnten Sie eine Funktion bereitstellen, die wie folgt aussieht:
int MyFunction (int arg) {}
Wenn Sie dieses Ziel haben, können Sie die Variable so initialisieren, dass sie auf Ihre Funktion zeigt:
pfi = MeineFunktion;
Sie können MyFunction dann indirekt aufrufen, indem Sie die suggestivere Form des Aufrufs verwenden:
int-Ergebnis = (*pfi) (1234);
Dies ist suggestiv, da es so aussieht, als würden Sie den Funktionszeiger nur dereferenzieren
wie Sie jeden Zeiger dereferenzieren würden. In der Regel nutzen die Menschen jedoch die Vorteile
Tatsache, dass der Compiler weiß, was vor sich geht und nur eine kürzere Form verwendet:
int-Ergebnis = pfi (1234);
Dies sieht so aus, als würden Sie eine Funktion mit dem Namen aufrufen PFI, aber der Compiler ist schlau genug
wissen, durch die Variable aufzurufen PFI indirekt zur Funktion MeineFunktion.
Konzeptionell funktioniert das Ablaufverfolgungssystem fast genau so. Im Grunde eine Spur
Waschbecken is ein Rückruf. Wenn eine Ablaufverfolgungssenke Interesse am Empfang von Ablaufverfolgungsereignissen bekundet, wird sie
fügt sich selbst als Callback zu einer Liste von Callbacks hinzu, die intern von der Ablaufverfolgungsquelle gehalten wird.
Wenn ein interessantes Ereignis eintritt, ruft die Ablaufverfolgungsquelle dieses auf Operator(...) Bereitstellung
null oder mehr Argumente. Die Operator(...) wandert schließlich in das System und
macht etwas bemerkenswert Ähnliches wie der indirekte Aufruf, den Sie gerade gesehen haben, und liefert null oder mehr
Parameter, genau wie der Aufruf an PFI oben einen Parameter an die Zielfunktion übergeben
MeineFunktion.
Der wichtige Unterschied, den das Ablaufverfolgungssystem hinzufügt, besteht darin, dass es für jede Ablaufverfolgungsquelle vorhanden ist
ist eine interne Liste von Callbacks. Anstatt nur einen indirekten Aufruf zu tätigen, eine Ablaufverfolgung
Quelle kann mehrere Callbacks aufrufen. Wenn eine Trace-Senke Interesse bekundet
Benachrichtigungen von einer Ablaufverfolgungsquelle, arrangiert es im Grunde nur, dass es seine eigene Funktion hinzufügt
die Rückrufliste.
Wenn Sie an weiteren Einzelheiten darüber interessiert sind, wie dies tatsächlich arrangiert ist NS-3, Gefühl
frei, den Callback-Bereich der zu lesen NS-3 Manual.
Exemplarische Vorgehensweise: vierte.cc
Wir haben Code bereitgestellt, um das wirklich einfachste Beispiel für Ablaufverfolgung zu implementieren
das lässt sich zusammenbauen. Sie finden diesen Code im Tutorial-Verzeichnis als vierte.cc.
Gehen wir es durch:
/* -*- Modus:C++; c-Dateistil:"gnu"; einrücken-tabs-modus:nil; -*- */
/*
* Dieses Programm ist freie Software; Sie können es weitergeben und/oder ändern
* es unter den Bedingungen der GNU General Public License Version 2 als
* veröffentlicht von der Free Software Foundation;
*
* Dieses Programm wird in der Hoffnung verteilt, dass es nützlich ist,
* jedoch OHNE JEGLICHE GARANTIE; auch ohne die stillschweigende garantie von
* MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die
* GNU General Public License für weitere Details.
*
* Sie sollten eine Kopie der GNU General Public License erhalten haben
* zusammen mit diesem Programm; wenn nicht, schreiben Sie an die Freie Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#einschließen
Verwenden des Namensraums ns3;
Der größte Teil dieses Codes sollte Ihnen vertraut sein. Wie oben erwähnt, das Trace-System
verwendet stark die Objekt- und Attributsysteme, daher müssen Sie sie einbeziehen.
Die ersten beiden Includes oben bringen die Deklarationen für diese Systeme explizit ein. Sie
könnte den Kernmodul-Header verwenden, um alles auf einmal zu bekommen, aber wir machen die Includes
explizit hier, um zu veranschaulichen, wie einfach das alles wirklich ist.
Die Datei, verfolgter-wert.h bringt die erforderlichen Erklärungen zur Rückverfolgung von Daten ein, die
gehorcht Wertesemantik. Im Allgemeinen bedeutet Wertsemantik nur, dass Sie die übergeben können
Objekt selbst herum, anstatt die Adresse des Objekts weiterzugeben. Was das alles wirklich
bedeutet, dass Sie alle Änderungen, die an einem TracedValue vorgenommen wurden, wirklich nachverfolgen können
einfacher Weg.
Da das Ablaufverfolgungssystem mit Attributen integriert ist und Attribute mit Objekten arbeiten,
es muss eine geben NS-3 Betreff für die Ablaufverfolgungsquelle. Das nächste Code-Snippet
deklariert und definiert ein einfaches Objekt, mit dem wir arbeiten können.
Klasse MyObject : öffentliches Objekt
{
Öffentlichkeit:
statische TypeId GetTypeId (ungültig)
{
statische TypeId tid = TypeId ("MyObject")
.SetParent (Objekt::GetTypeId ())
.Konstruktor hinzufügen ()
.AddTraceSource ("MyInteger",
"Ein ganzzahliger Wert, der verfolgt werden soll.",
MakeTraceSourceAccessor (&MyObject::m_myInt),
"ns3::Traced::Value::Int32Callback")
;
Rückkehr Gezeiten;
}
MeinObjekt () {}
Nachverfolgter Wert m_myInt;
};
Die zwei wichtigen Codezeilen oben in Bezug auf die Ablaufverfolgung sind die .TraceSource hinzufügen
und der Nachverfolgter Wert Erklärung von m_myInt.
Die .TraceSource hinzufügen stellt die "Hooks" bereit, die zum Verbinden der Ablaufverfolgungsquelle mit dem verwendet werden
Außenwelt über das Config-System. Das erste Argument ist ein Name für diese Ablaufverfolgung
source, was sie im Config-System sichtbar macht. Das zweite Argument ist eine Hilfszeichenfolge.
Schauen Sie sich nun das dritte Argument an, konzentrieren Sie sich tatsächlich auf das Argument des dritten Arguments:
&MyObject::m_myInt. Dies ist der TracedValue, der der Klasse hinzugefügt wird; es ist
immer ein Klassendatenelement. (Das letzte Argument ist der Name von a typedef für die
TracedValue-Typ als Zeichenfolge. Dies wird verwendet, um eine Dokumentation für die richtige zu erstellen
Callback-Funktionssignatur, die besonders für allgemeinere Arten von nützlich ist
Rückrufe.)
Die TraceWert<> -Deklaration stellt die Infrastruktur bereit, die den Rückruf steuert
Prozess. Jedes Mal, wenn der zugrunde liegende Wert geändert wird, stellt der TracedValue-Mechanismus dies bereit
sowohl der alte als auch der neue Wert dieser Variablen, in diesem Fall an int32_t Wert. Die Spur
Die Senkenfunktion für diesen TracedValue benötigt die Signatur
void (* TracedValueCallback) (const int32_t oldValue, const int32_t newValue);
Alle Ablaufverfolgungssenken, die diese Ablaufverfolgungsquelle verknüpfen, müssen diese Signatur aufweisen. Wir werden weiter unten diskutieren
wie Sie in anderen Fällen die erforderliche Callback-Signatur ermitteln können.
Sicher genug, weiter durch vierte.cc wir sehen:
ungültig
IntTrace (int32_t alterWert, int32_t neuerWert)
{
std::cout << "Traced " << oldValue << " bis " << newValue << std::endl;
}
Dies ist die Definition einer passenden Trace-Senke. Es entspricht direkt dem Rückruf
Funktionssignatur. Sobald die Verbindung hergestellt ist, wird diese Funktion immer dann aufgerufen, wenn die
Nachverfolgter Wert ändert.
Wir haben jetzt die Trace-Quelle und die Trace-Senke gesehen. Was bleibt, ist Code zum Verbinden
Quelle zur Senke, was in passiert Haupt-:
int
main (int argc, char *argv[])
{
Ptr myObject = CreateObject ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));
myObject->m_myInt = 1234;
}
Hier erstellen wir zuerst die MyObject-Instanz, in der sich die Ablaufverfolgungsquelle befindet.
Der nächste Schritt, die TraceConnectWithoutContext, bildet die Verbindung zwischen der Spur
Source und die Trace-Senke. Das erste Argument ist nur der Ablaufverfolgungsquellenname "MyInteger".
wir haben oben gesehen. Beachten Sie die MakeCallback Vorlagenfunktion. Diese Funktion macht die Magie
erforderlich, um den Basiswert zu erstellen NS-3 Callback-Objekt und verknüpfen Sie es mit der Funktion
IntTrace. TraceConnect stellt die Zuordnung zwischen Ihrer bereitgestellten Funktion und her
überladen Operator() in der nachverfolgten Variablen, auf die durch das "MyInteger"-Attribut verwiesen wird.
Nachdem diese Zuordnung hergestellt wurde, "feuert" die Ablaufverfolgungsquelle Ihren bereitgestellten Rückruf
Funktion.
Der Code, der all dies ermöglicht, ist natürlich nicht trivial, aber das Wesentliche ist das
Sie arrangieren etwas, das genauso aussieht wie das pfi() Beispiel oben aufgerufen werden
durch die Spurenquelle. Die Erklärung des Nachverfolgter Wert m_myInt; im Objekt
selbst führt die Magie aus, die erforderlich ist, um die überladenen Zuweisungsoperatoren bereitzustellen, die dies tun
verwenden Sie die Operator() um den Callback tatsächlich mit den gewünschten Parametern aufzurufen. Die
.TraceSource hinzufügen führt die Magie aus, um den Callback mit dem Config-System zu verbinden, und
TraceConnectWithoutContext führt die Magie aus, um Ihre Funktion mit der Ablaufverfolgung zu verbinden
Quelle, die durch Attributname angegeben wird.
Lassen Sie uns vorerst den Kontext ignorieren.
Schließlich die Zeile, die einen Wert zuweist m_myInt:
myObject->m_myInt = 1234;
sollte als Aufruf von interpretiert werden Operator = auf der Member-Variablen m_myInt mit
die ganze Zahl 1234 als Parameter übergeben.
Da m_myInt ist eine Nachverfolgter Wert, dieser Operator ist so definiert, dass er einen Callback ausführt
gibt void zurück und nimmt zwei ganzzahlige Werte als Parameter – einen alten Wert und einen neuen Wert
für die betreffende Ganzzahl. Das ist genau die Funktionssignatur für den Callback
Funktion, die wir bereitgestellt haben --- IntTrace.
Zusammenfassend ist eine Ablaufverfolgungsquelle im Wesentlichen eine Variable, die eine Liste von Rückrufen enthält. EIN
Ablaufsenke ist eine Funktion, die als Ziel eines Rückrufs verwendet wird. Das Attribut und der Objekttyp
Informationssysteme werden verwendet, um Trace-Quellen mit Trace-Senken zu verbinden.
Der Vorgang des "Treffens" einer Ablaufverfolgungsquelle ist das Ausführen eines Operators an der Ablaufverfolgungsquelle, der
löst Rückrufe aus. Dies führt zu Rückrufen der Trace-Senke, die Interesse an dem registrieren
Quelle wird mit den von der Quelle bereitgestellten Parametern aufgerufen.
Wenn Sie dieses Beispiel jetzt erstellen und ausführen,
$ ./waf --als viertes ausführen
Sie werden die Ausgabe von sehen IntTrace Funktion ausführen, sobald die Trace-Quelle ist
Schlag:
Zurückverfolgt von 0 bis 1234
Als wir den Code ausgeführt haben, meinObjekt->m_meinInt = 1234;, die Ablaufverfolgungsquelle ausgelöst und
automatisch die Vorher- und Nachher-Werte für die Trace-Senke bereitgestellt. Die Funktion
IntTrace dann druckte dies auf die Standardausgabe.
Verbinden mit Config
Die TraceConnectWithoutContext Aufruf oben im einfachen Beispiel ist eigentlich sehr
selten im System verwendet. Typischerweise die Config Subsystem wird verwendet, um eine Ablaufverfolgung auszuwählen
Quelle im System mit einem sogenannten a Config Weg. Ein Beispiel dafür haben wir in der gesehen
vorherigen Abschnitt, in dem wir das "CourseChange"-Ereignis verknüpft haben, als wir damit experimentierten
dritte.cc.
Denken Sie daran, dass wir eine Trace-Senke definiert haben, um Kursänderungsinformationen aus der Mobilität zu drucken
Modelle unserer Simulation. Es sollte Ihnen jetzt viel klarer sein, was diese Funktion ist
tun:
ungültig
CourseChange (std::string Kontext, Ptr Modell)
{
Vektorposition = Modell->GetPosition ();
NS_LOG_UNCOND (Kontext <
" x = " << Position.x << ", y = " << Position.y);
}
Als wir die Ablaufverfolgungsquelle "CourseChange" mit der obigen Ablaufverfolgungssenke verbunden haben, haben wir a verwendet
Config-Pfad zur Angabe der Quelle, wenn wir eine Verbindung zwischen den vordefinierten arrangiert haben
Trace-Quelle und die neue Trace-Senke:
std::ostringstream oss;
oss << "/Knotenliste/"
<< wifiStaNodes.Get (nWifi - 1)->GetId ()
<< "/$ns3::Mobilitätsmodell/Kurswechsel";
Config::Connect (oss.str (), MakeCallback (&CourseChange));
Lassen Sie uns versuchen, einen Sinn in dem zu finden, was manchmal als relativ mysteriöser Code angesehen wird.
Nehmen Sie zu Diskussionszwecken an, dass die von der zurückgegebene Knotennummer GetId() is
"7". In diesem Fall erweist sich der obige Pfad als
"/NodeList/7/$ns3::MobilityModel/CourseChange"
Das letzte Segment eines Konfigurationspfads muss ein sein Attribut eines Betreff. In der Tat, wenn Sie hatten
ein hinweis auf die Betreff das hat den "CourseChange" Attribut praktisch, das könntest du schreiben
genau wie wir es im vorherigen Beispiel getan haben. Sie wissen inzwischen, dass wir normalerweise speichern
Hinweise auf unsere Nodes in einem NodeContainer. In dem dritte.cc B. die Knoten von Interesse
sind in der gespeichert wifiStaNodes NodeContainer. In der Tat, während Sie den Weg zusammenstellen,
Wir haben diesen Container verwendet, um a zu bekommen Ptr die wir früher angerufen haben GetId(). Wir könnten haben
habe das benutzt Ptr So rufen Sie eine Connect-Methode direkt auf:
Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));
Im dritte.cc Beispielsweise wollten wir eigentlich, dass ein zusätzlicher "Kontext" mitgeliefert wird
mit den Callback-Parametern (die unten erklärt werden), damit wir die tatsächlich verwenden könnten
folgender äquivalenter Code:
Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));
Es stellt sich heraus, dass der interne Code für Config::ConnectWithoutContext und Konfig::Verbinden
finde eigentlich ein Ptr und den entsprechenden anrufen TraceConnect Methode am niedrigsten
Ebene.
Die Config Funktionen nehmen einen Pfad, der eine Kette von darstellt Betreff Zeiger. Jedes Segment
eines Pfades entspricht einem Objektattribut. Das letzte Segment ist das Attribut von
Interesse, und frühere Segmente müssen eingegeben werden, um Objekte zu enthalten oder zu finden. Die Config Code
analysiert und "geht" diesen Pfad, bis er das letzte Segment des Pfades erreicht. Es dann
interpretiert das letzte Segment als Attribut auf das letzte Objekt, das es beim Gehen gefunden hat
Weg. Die Config Funktionen rufen dann die entsprechenden auf TraceConnect or
TraceConnectWithoutContext Methode auf dem letzten Objekt. Mal sehen, was in Kürze passiert
mehr Details, wenn der obige Weg gegangen wird.
Das führende "/"-Zeichen im Pfad verweist auf einen sogenannten Namensraum. Einer der
vordefinierte Namespaces im Konfigurationssystem ist "NodeList", die eine Liste aller
Knoten in der Simulation. Auf Elemente in der Liste wird durch Indizes in der Liste verwiesen, also
"/NodeList/7" bezieht sich auf den achten Knoten in der während der Simulation erstellten Liste von Knoten
(Rückrufindizes beginnen bei 0 '). Dieses Referenz is berührt das Schneidwerkzeug a „Ptr ` und so ist ein
Unterklasse eines ns3::Objekt.
Wie im Abschnitt Objektmodell von beschrieben NS-3 Manuell machen wir weit verbreiteten Gebrauch
Objektaggregation. Dies ermöglicht es uns, eine Assoziation zwischen verschiedenen Objekten zu bilden
ohne einen komplizierten Vererbungsbaum zu erstellen oder vorher zu entscheiden, welche Objekte Teil davon sein sollen
eines Knotens. Jedes Objekt in einer Aggregation kann von den anderen Objekten aus erreicht werden.
In unserem Beispiel beginnt das nächste begehbare Wegsegment mit dem Zeichen „$“. Dies
zeigt dem Konfigurationssystem an, dass das Segment der Name eines Objekttyps ist, also a
Getobject sollte nach diesem Typ gesucht werden. Es stellt sich heraus, dass die Mobilitätshelfer
benutzt in dritte.cc arrangiert, ein Mobilitätsmodell jedem der zu aggregieren oder zuzuordnen
kabellos Nodes. Wenn Sie das "$" hinzufügen, fragen Sie nach einem anderen Objekt, das hat
vermutlich vorher aggregiert. Sie können sich dies als Umschaltzeiger vorstellen
der ursprüngliche Ptr wie von "/NodeList/7" angegeben zu seinem zugehörigen Mobilitätsmodell ---
was vom typ ist ns3::Mobilitätsmodell. Wenn Sie vertraut sind mit Getobject, haben wir gefragt
das System, um Folgendes zu tun:
Ptr mobilityModel = node->GetObject ()
Wir sind jetzt beim letzten Objekt im Pfad, also richten wir unsere Aufmerksamkeit auf die Attribute von
dieses Objekt. Die Mobilitätsmodell Klasse definiert ein Attribut namens "CourseChange". Du kannst
Sehen Sie sich dies an, indem Sie sich den Quellcode in ansehen src/mobility/model/mobility-model.cc und
Suchen Sie in Ihrem bevorzugten Editor nach "CourseChange". Du solltest finden
.AddTraceSource ("Kursänderung",
"Der Wert des Positions- und/oder Geschwindigkeitsvektors hat sich geändert",
MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace),
"ns3::MobilityModel::CourseChangeCallback")
was an dieser Stelle sehr bekannt vorkommen sollte.
Wenn Sie nach der entsprechenden Deklaration der zugrunde liegenden verfolgten Variablen suchen in
Mobilitätsmodell.h du wirst finden
TracedCallback > m_courseChangeTrace;
Die Typdeklaration TracedCallback identifiziert m_courseChangeTrace als spezielle Liste von
Callbacks, die mit den oben beschriebenen Config-Funktionen eingehakt werden können. Die typedef für
Die Callback-Funktionssignatur ist auch in der Header-Datei definiert:
typedef void (* CourseChangeCallback)(Ptr * Modell);
Die Mobilitätsmodell Die Klasse ist als Basisklasse konzipiert, die eine gemeinsame Schnittstelle für bietet
alle spezifischen Unterklassen. Wenn Sie bis zum Ende der Datei suchen, sehen Sie a
definierte Methode aufgerufen NotifyCourseChange():
ungültig
MobilityModel::NotifyCourseChange (void) const
{
m_courseChangeTrace(dies);
}
Abgeleitete Klassen rufen diese Methode immer dann auf, wenn sie eine Kursänderung zur Unterstützung vornehmen
Verfolgung. Diese Methode ruft auf Operator() auf dem Basiswert m_courseChangeTrace, Die
wird wiederum alle registrierten Callbacks aufrufen und alle Trace-Senken aufrufen
durch Aufruf einer Config-Funktion Interesse an der Trace-Quelle bekundet haben.
Also, in der dritte.cc Beispiel haben wir uns angesehen, wann immer ein Kurswechsel in einem der vorgenommen wird
Randomwalk2dmobilityModel Instanzen installiert, wird es eine geben NotifyCourseChange() rufen Sie uns an!
die in die ruft Mobilitätsmodell Basisklasse. Wie oben gesehen, ruft dies auf Operator()
on m_courseChangeTrace, die wiederum alle registrierten Ablaufverfolgungssenken aufruft. Im Beispiel
Der einzige Code, der ein Interesse registrierte, war der Code, der den Konfigurationspfad bereitstellte.
deshalb, die Kurswechsel Funktion, die von Knoten Nummer sieben eingehakt wurde, wird die sein
nur Rückruf angerufen.
Das letzte Puzzleteil ist der „Kontext“. Denken Sie daran, dass wir eine Ausgabe gesehen haben
etwas wie das folgende von dritte.cc:
/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y =
2.22677
Der erste Teil der Ausgabe ist der Kontext. Es ist einfach der Weg, durch den die
config-Code hat die Ablaufverfolgungsquelle lokalisiert. In dem Fall, den wir uns angesehen haben, kann dies der Fall sein
eine beliebige Anzahl von Ablaufverfolgungsquellen im System, die einer beliebigen Anzahl von Knoten entsprechen
Mobilitätsmodelle. Es muss eine Möglichkeit geben, zu identifizieren, um welche Trace-Quelle es sich tatsächlich handelt
derjenige, der den Rückruf ausgelöst hat. Der einfache Weg ist, sich mit zu verbinden Konfig::Verbinden, stattdessen
of Config::ConnectWithoutContext.
Erkenntnis Quellen
Die erste Frage, die sich für neue Benutzer des Tracing-Systems unweigerlich stellt, lautet: "In Ordnung,
I kennt zur Verbesserung der Gesundheitsgerechtigkeit dort sollen be Spur Quellen in Simulation Kern, aber wie do I gefunden was
Spur Quellen sind verfügbar zu ich? "
Die zweite Frage ist, "In Ordnung, I gefunden a Spur Quelle, wie do I Abbildung Config Weg
zu - wann I connect zu es?"
Die dritte Frage ist, "In Ordnung, I gefunden a Spur Quelle und Config Pfad, wie do I Abbildung
was Rückkehr tippe und formal Argumente of my callback Funktion technische zu sein?"
Die vierte Frage ist, "In Ordnung, I getippt zur Verbesserung der Gesundheitsgerechtigkeit alle in und habe fehlen uns die Worte. unglaublich bizarr Fehler
Botschaft, was in weltweit wie ausgehandelt und gekauft ausgeführt wird. die it bedeuten?"
Wir werden diese nacheinander ansprechen.
Verfügbare Quellen
Okay, I kennt zur Verbesserung der Gesundheitsgerechtigkeit dort sollen be Spur Quellen in Simulation Kern, aber wie do I gefunden
was Spur Quellen sind verfügbar zu ich?
Die Antwort auf die erste Frage finden Sie in der NS-3 API-Dokumentation. Wenn Sie zu gehen
Projekt-Website, NS-3 Projektfinden Sie in der Navigation einen Link zu "Dokumentation".
Bar. Wenn Sie diesen Link auswählen, werden Sie zu unserer Dokumentationsseite weitergeleitet. Da ist ein
Link zu "Latest Release", der Sie zur Dokumentation für den neuesten Stable führt
Veröffentlichung von NS-3. Wenn Sie den Link "API-Dokumentation" auswählen, werden Sie zur weitergeleitet
NS-3 API-Dokumentationsseite.
In der Seitenleiste sollten Sie eine beginnende Hierarchie sehen
· ns-3
· ns-3 Dokumentation
· Alle TraceSources
· Alle Attribute
· Alle globalen Werte
Die für uns hier interessante Liste ist "All TraceSources". Fahren Sie fort und wählen Sie diesen Link aus.
Sie werden, vielleicht nicht allzu überraschend, eine Liste aller verfügbaren Trace-Quellen sehen
in NS-3.
Scrollen Sie beispielsweise nach unten zu ns3::Mobilitätsmodell. Sie finden einen Eintrag für
CourseChange: Der Wert des Positions- und/oder Geschwindigkeitsvektors hat sich geändert
Sie sollten dies als die Trace-Quelle erkennen, die wir in verwendet haben dritte.cc Beispiel. Lesen
diese Liste wird hilfreich sein.
Config Paths
Okay, I gefunden a Spur Quelle, wie do I Abbildung Config Weg zu - wann I connect zu
es?
Wenn Sie wissen, für welches Objekt Sie sich interessieren, finden Sie im Abschnitt "Detaillierte Beschreibung" für die
-Klasse listet alle verfügbaren Ablaufverfolgungsquellen auf. Beginnen Sie beispielsweise mit der Liste „Alle
TraceSources", klicken Sie auf die ns3::Mobilitätsmodell Link, der Sie zu führt
Dokumentation für die Mobilitätsmodell Klasse. Fast ganz oben auf der Seite befindet sich eine Zeile
kurze Beschreibung der Klasse, die mit einem Link "Mehr..." endet. Klicken Sie auf diesen Link, um ihn zu überspringen
die API-Zusammenfassung und gehen Sie zur "Detaillierten Beschreibung" der Klasse. Am Ende von
Die Beschreibung besteht aus (bis zu) drei Listen:
· Config Paths: eine Liste typischer Konfigurationspfade für diese Klasse.
· Attribute: eine Liste aller Attribute, die von dieser Klasse bereitgestellt werden.
· TraceSources: eine Liste aller TraceSources, die von dieser Klasse verfügbar sind.
Zuerst besprechen wir die Konfigurationspfade.
Nehmen wir an, Sie haben gerade die Trace-Quelle „CourseChange“ in der Datei „All
TraceSources"-Liste und Sie möchten herausfinden, wie Sie sich damit verbinden können. Sie wissen, dass Sie es sind
mit (wieder, von der dritte.cc Beispiel) ein ns3::RandomWalk2dMobilityModel. Also entweder
Klicken Sie auf den Klassennamen in der Liste "Alle TraceSources" oder suchen Sie
ns3::RandomWalk2dMobilityModel in der „Klassenliste“. So oder so solltest du jetzt suchen
auf der Seite „ns3::RandomWalk2dMobilityModel Class Reference“.
Wenn Sie jetzt nach unten zum Abschnitt "Detaillierte Beschreibung" scrollen, wird nach der zusammenfassenden Liste von
Klassenmethoden und -attribute (oder klicken Sie einfach auf den Link "Mehr..." am Ende der Klasse
Kurzbeschreibung oben auf der Seite) sehen Sie die Gesamtdokumentation für die
Klasse. Wenn Sie weiter nach unten scrollen, finden Sie die Liste "Config Paths":
Config Paths
ns3::RandomWalk2dMobilityModel ist über die folgenden Pfade mit erreichbar
Konfig::Einstellen und Konfig::Verbinden:
· "/NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel"
In der Dokumentation erfahren Sie, wie Sie an die Randomwalk2dmobilityModel Objekt. Vergleichen
die Zeichenfolge oben mit der Zeichenfolge, die wir tatsächlich im Beispielcode verwendet haben:
"/NodeList/7/$ns3::MobilityModel"
Der Unterschied liegt darin begründet, dass zwei Getobject Aufrufe sind in der gefundenen Zeichenfolge enthalten
in der Dokumentation. Die erste, z $ns3::MobilityModel wird die Aggregation abfragen
die Basisklasse. Das zweite implizierte Getobject fordern $ns3::RandomWalk2dMobilityModel,
wird verwendet, um die Basisklasse in die konkrete Implementierungsklasse umzuwandeln. Die Dokumentation
zeigt Ihnen diese beiden Operationen. Es stellt sich heraus, dass Sie die eigentliche Spurenquelle sind
suchen wird in der Basisklasse gefunden.
Suchen Sie weiter unten im Abschnitt "Detaillierte Beschreibung" nach der Liste der Ablaufverfolgungsquellen.
Sie werden feststellen,
Für diesen Typ sind keine TraceSources definiert.
TraceSources definiert in Elternteil Klasse „ns3::MobilityModel“.
· Kurswechsel: Der Wert des Positions- und/oder Geschwindigkeitsvektors hat sich geändert.
Callback-Signatur: ns3::MobilityModel::CourseChangeCallback
Genau das müssen Sie wissen. Die interessierende Spurenquelle befindet sich in
ns3::Mobilitätsmodell (was du sowieso wusstest). Das Interessante an diesem Bit der API
Die Dokumentation sagt Ihnen, dass Sie diese zusätzliche Umwandlung im obigen Konfigurationspfad nicht benötigen
gelangen Sie zur konkreten Klasse, da sich die Ablaufverfolgungsquelle tatsächlich in der Basisklasse befindet.
Daher die zusätzliche Getobject ist nicht erforderlich und Sie verwenden einfach den Pfad:
"/NodeList/[i]/$ns3::MobilityModel"
was perfekt zum Beispielpfad passt:
"/NodeList/7/$ns3::MobilityModel"
Abgesehen davon gibt es eine andere Möglichkeit, den Konfigurationspfad zu finden grep herum in der NS-3 Codebasis
für jemanden, der es schon herausgefunden hat. Sie sollten immer versuchen, die von jemand anderem zu kopieren
Arbeitscode, bevor Sie anfangen, Ihren eigenen zu schreiben. Versuchen Sie etwas wie:
$finden. -name '*.cc' | xargs grep CourseChange | grep Verbinden
und Sie können Ihre Antwort zusammen mit dem funktionierenden Code finden. In diesem Fall z.
src/mobility/examples/main-random-topology.cc hat etwas, das nur darauf wartet, von Ihnen verwendet zu werden:
Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange));
Wir werden gleich auf dieses Beispiel zurückkommen.
Rückruf Unterschriften
Okay, I gefunden a Spur Quelle und Config Pfad, wie do I Abbildung was Rückkehr tippe
und formal Argumente of my callback Funktion technische zu sein?
Am einfachsten ist es, die Callback-Signatur zu untersuchen typedef, die in der gegeben ist
"Callback-Signatur" der Ablaufverfolgungsquelle in der "Detaillierten Beschreibung" für die Klasse, wie
oben gezeigt.
Wiederholen Sie den "CourseChange"-Trace-Source-Eintrag aus ns3::RandomWalk2dMobilityModel we
haben:
· Kurswechsel: Der Wert des Positions- und/oder Geschwindigkeitsvektors hat sich geändert.
Callback-Signatur: ns3::MobilityModel::CourseChangeCallback
Die Callback-Signatur wird als Link zum entsprechenden angegeben typedef, wo wir finden
typedef ungültig (* CourseChangeCallback)(konst std::string Kontext, Ptr
Mobilitätsmodell> * Modell);
TracedCallback Signatur für Kursänderungsmitteilungen.
Wird der Rückruf über verbunden ConnectWithoutContext weglassen Kontext Argument von
die Unterschrift.
Parameter:
[in] context Die Kontextzeichenfolge, die von der Trace-Quelle bereitgestellt wird.
[in] model Das Mobilitätsmodell, das seinen Kurs ändert.
Wie oben, um dies im Einsatz zu sehen grep herum in der NS-3 Codebasis für ein Beispiel. Das Beispiel
oben, ab src/mobility/examples/main-random-topology.cc, verbindet den "CourseChange"
Trace-Quelle auf die Kurswechsel Funktion in derselben Datei:
Statische Leere
CourseChange (std::string Kontext, Ptr Modell)
{
...
}
Beachten Sie, dass diese Funktion:
· Akzeptiert ein "Kontext"-String-Argument, das wir gleich beschreiben werden. (Falls der Rückruf
wird über die verbunden ConnectWithoutContext Funktion der Kontext Argument wird sein
weggelassen.)
· Hat die Mobilitätsmodell als letztes Argument angegeben (oder nur Argument if
ConnectWithoutContext wird genutzt).
· Kehrt zurück ungültig.
Wenn die Callback-Signatur zufällig nicht dokumentiert wurde und es keine Beispiele dafür gibt
arbeiten, kann das Bestimmen der richtigen Callback-Funktionssignatur, nun ja, eine Herausforderung sein
tatsächlich aus dem Quellcode herausfinden.
Bevor ich mich auf eine exemplarische Vorgehensweise des Codes begebe, werde ich freundlich sein und Ihnen nur einen einfachen Weg sagen
Um das herauszufinden: Der Rückgabewert Ihres Callbacks wird immer sein ungültig. Das formelle
Parameterliste für a TracedCallback finden Sie in der Vorlagenparameterliste in der
Erklärung. Denken Sie daran, dass dies für unser aktuelles Beispiel in ist Mobilitätsmodell.h, wo wir
habe bisher gefunden:
TracedCallback > m_courseChangeTrace;
Es besteht eine Eins-zu-Eins-Entsprechung zwischen der Vorlagenparameterliste in der
-Deklaration und die formalen Argumente der Callback-Funktion. Hier, da ist einer
Template-Parameter, der a Ptr Mobilitätsmodell>. Dies sagt Ihnen, dass Sie eine benötigen
Funktion, die void zurückgibt und a akzeptiert Ptr Mobilitätsmodell>. Zum Beispiel:
ungültig
Kurswechsel (Ptr Modell)
{
...
}
Das ist alles, was Sie brauchen, wenn Sie wollen Config::ConnectWithoutContext. Wenn Sie einen Kontext möchten,
Sie brauchen, um Konfig::Verbinden und dann eine Callback-Funktion verwenden, die einen String-Kontext übernimmt
die Template-Argumente:
ungültig
CourseChange (const std::string Kontext, Ptr Modell)
{
...
}
Wenn Sie sicherstellen möchten, dass Ihre CourseChangeCallback Funktion ist nur in Ihrer sichtbar
lokale Datei, können Sie das Schlüsselwort hinzufügen statisch und komme auf:
Statische Leere
CourseChange (const std::string path, Ptr Modell)
{
...
}
das ist genau das, was wir in der verwendet haben dritte.cc Beispiel.
Implementierung
Dieser Abschnitt ist vollkommen optional. Es wird eine holprige Fahrt werden, besonders für sie
mit den Details der Vorlagen nicht vertraut sind. Wenn Sie dies jedoch überstehen, werden Sie es tun
ein sehr guter Griff auf viele der NS-3 Redewendungen auf niedrigem Niveau.
Lassen Sie uns also noch einmal herausfinden, welche Signatur der Callback-Funktion für die erforderlich ist
Ablaufverfolgungsquelle "CourseChange". Das wird schmerzhaft sein, aber du musst es nur tun
Einmal. Nachdem Sie dies überstanden haben, können Sie sich einfach a ansehen TracedCallback und
es verstehen.
Als erstes müssen wir uns die Deklaration der Trace-Quelle ansehen. Erinnere dich daran
Das ist in Mobilitätsmodell.h, wo wir zuvor gefunden haben:
TracedCallback > m_courseChangeTrace;
Diese Erklärung ist für eine Vorlage. Der Vorlagenparameter befindet sich in den spitzen Klammern,
Wir sind also wirklich daran interessiert herauszufinden, was das ist TracedCallback<> ist. Wenn Sie haben
absolut keine ahnung wo das zu finden ist grep ist dein Freund.
Wir werden wahrscheinlich an einer Art Erklärung in der interessiert sein NS-3 Quelle, also
zunächst in die wechseln src Verzeichnis. Dann wissen wir, dass diese Erklärung muss
in einer Art Header-Datei sein, also einfach grep dafür mit:
$finden. -name '*.h' | xargs grep TracedCallback
Sie werden sehen, wie 303 Linien vorbeifliegen (ich habe das durchgeleitet wc um zu sehen, wie schlimm es war). Obwohl
das mag viel erscheinen, das ist nicht wirklich viel. Leiten Sie einfach den Ausgang durch mehr und
Fangen Sie an, es zu durchsuchen. Auf der ersten Seite sehen Sie einige sehr verdächtig
vorlagenähnliches Zeug.
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::TracedCallback ()
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext (c ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Connect (const CallbackB ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::DisconnectWithoutContext ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::Disconnect (const Callba ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (void) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1) const ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::operator() (T1 a1, T2 a2 ...
Es stellt sich heraus, dass all dies aus der Header-Datei stammt Traced-Callback.h was klingt
sehr vielversprechend. Da kann man sich schon mal umschauen Mobilitätsmodell.h und sehen, dass es eine Linie gibt
was diese Vermutung bestätigt:
#include "ns3/traced-callback.h"
Natürlich hätte man das auch aus der anderen Richtung angehen und mit dem Betrachten beginnen können
das beinhaltet in Mobilitätsmodell.h und bemerken das Einschließen von Traced-Callback.h und
daraus schließen, dass dies die gewünschte Datei sein muss.
In jedem Fall ist der nächste Schritt, einen Blick darauf zu werfen src/core/model/traced-callback.h in
Ihr Lieblingsredakteur, um zu sehen, was passiert.
Oben in der Datei sehen Sie einen Kommentar, der beruhigend sein sollte:
Ein ns3::TracedCallback hat aber fast genau die gleiche API wie ein normaler ns3::Callback
Anstatt Anrufe an eine einzelne Funktion weiterzuleiten (wie es ein ns3::Callback normalerweise tut),
es leitet Anrufe an eine Kette von ns3::Callback weiter.
Dies sollte Ihnen sehr vertraut vorkommen und Sie wissen lassen, dass Sie auf dem richtigen Weg sind.
Gleich nach diesem Kommentar finden Sie
Vorlage
Typname T3 = leer, Typname T4 = leer,
Typname T5 = leer, Typname T6 = leer,
Typname T7 = leer, Typname T8 = leer>
Klasse TracedCallback
{
...
Dies sagt Ihnen, dass TracedCallback eine auf Vorlagen basierende Klasse ist. Es hat acht mögliche Typen
Parameter mit Standardwerten. Gehen Sie zurück und vergleichen Sie dies mit der Erklärung, die Sie sind
versucht zu verstehen:
TracedCallback > m_courseChangeTrace;
Die Modellname T1 in der vorlagenbasierten Klassendeklaration entspricht der Ptr
Mobilitätsmodell> in der Erklärung oben. Alle anderen Typparameter bleiben unverändert
Voreinstellungen. Ein Blick auf den Konstruktor sagt nicht wirklich viel aus. Der einzige Ort, wo
Sie haben gesehen, dass eine Verbindung zwischen Ihrer Callback-Funktion und dem Ablaufverfolgungssystem hergestellt wurde
begann Verbinden und ConnectWithoutContext Funktionen. Wenn Sie nach unten scrollen, sehen Sie a
ConnectWithoutContext Methode hier:
Vorlage
Typname T3, Typname T4,
Typname T5, Typname T6,
Typname T7, Typname T8>
ungültig
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assign (Rückruf);
m_callbackList.push_back (cb);
}
Du bist jetzt im Bauch des Tieres. Wenn die Vorlage für die instanziiert wird
Erklärung oben, wird der Compiler ersetzen T1 mit Ptr Mobilitätsmodell>.
ungültig
TracedCallback ::ConnectWithoutContext ... cb
{
Rückrufen > cb;
cb.Assign (Rückruf);
m_callbackList.push_back (cb);
}
Sie können jetzt die Implementierung von allem sehen, worüber wir gesprochen haben. Der Code
erstellt einen Callback des richtigen Typs und weist ihm Ihre Funktion zu. Dies ist das
Äquivalent der PFI = MeineFunktion wir am Anfang dieses Abschnitts besprochen. Der Code
fügt dann den Callback zur Liste der Callbacks für diese Quelle hinzu. Bleibt nur noch
um sich die Definition von Callback anzusehen. Unter Verwendung des gleichen grep Trick, wie wir früher fanden
TracedCallback, finden Sie die Datei ./core/callback.h sind wir
anschauen muss.
Wenn Sie in der Datei nach unten schauen, werden Sie vieles sehen, das wahrscheinlich fast unverständlich ist
Vorlagencode. Sie werden schließlich zu einer API-Dokumentation für den Callback kommen
Template-Klasse, aber. Zum Glück gibt es etwas Englisch:
Rückruf Vorlagenklasse.
Diese Klassenvorlage implementiert das Functor-Entwurfsmuster. Es wird verwendet, um die zu deklarieren
Art eines Rückruf:
· Das erste nicht optionale Template-Argument repräsentiert den Rückgabetyp des Callbacks.
· die verbleibenden (optionalen) Template-Argumente repräsentieren den Typ des nachfolgenden
Argumente für den Rückruf.
· Bis zu neun Argumente werden unterstützt.
Wir versuchen herauszufinden, was die
Rückrufen > cb;
Deklaration bedeutet. Jetzt sind wir in der Lage zu verstehen, dass die erste (nicht optionale)
Vorlagenargument, ungültig, repräsentiert den Rückgabetyp des Callbacks. Der Zweite
(optional) Template-Argument, Ptr Mobilitätsmodell> stellt den Typ des ersten dar
Argument für den Rückruf.
Der fragliche Callback ist Ihre Funktion zum Empfangen der Trace-Ereignisse. Daraus können Sie
schließen, dass Sie eine Funktion benötigen, die zurückkehrt ungültig und nimmt a Ptr Mobilitätsmodell>.
Zum Beispiel,
ungültig
CourseChangeCallback (Ptr Modell)
{
...
}
Das ist alles, was Sie brauchen, wenn Sie wollen Config::ConnectWithoutContext. Wenn Sie einen Kontext möchten,
Sie brauchen, um Konfig::Verbinden und verwenden Sie eine Callback-Funktion, die einen String-Kontext annimmt. Dies
liegt daran, dass die Verbinden Funktion stellt den Kontext für Sie bereit. Du brauchst:
ungültig
CourseChangeCallback (std::string Kontext, Ptr Modell)
{
...
}
Wenn Sie sicherstellen möchten, dass Ihre CourseChangeCallback ist nur in Ihrer lokalen Datei sichtbar,
Sie können das Schlüsselwort hinzufügen statisch und komme auf:
Statische Leere
CourseChangeCallback (std::string path, Ptr Modell)
{
...
}
das ist genau das, was wir in der verwendet haben dritte.cc Beispiel. Vielleicht solltest du jetzt zurückgehen und
Lesen Sie noch einmal den vorherigen Abschnitt (Glauben Sie mir beim Wort).
Wenn Sie an weiteren Details zur Implementierung von Callbacks interessiert sind, zögern Sie nicht
einen Blick auf die zu werfen NS-3 Handbuch. Sie sind eines der am häufigsten verwendeten Konstrukte in
die Low-Level-Teile von NS-3. Das ist meiner Meinung nach eine ziemlich elegante Sache.
Nachverfolgte Werte
Weiter oben in diesem Abschnitt haben wir einen einfachen Codeabschnitt vorgestellt, der a verwendet
Nachverfolgter Wert um die Grundlagen des Ablaufverfolgungscodes zu demonstrieren. Wir haben es nur beschönigt
was ein TracedValue wirklich ist und wie man den Rückgabetyp und die formalen Argumente dafür findet
der Rückruf.
Wie bereits erwähnt, die Datei, verfolgter-wert.h bringt die erforderlichen Erklärungen für die Rückverfolgung ein
von Daten, die der Wertsemantik gehorchen. Im Allgemeinen bedeutet Wertsemantik nur, dass Sie es können
Geben Sie das Objekt selbst herum, anstatt die Adresse des Objekts weiterzugeben. Wir verlängern
diese Anforderung, den vollständigen Satz von Operatoren im Zuweisungsstil einzuschließen, die vorhanden sind
vordefiniert für POD-Typen (Plain-Old-Data):
–
│Operator = (Aufgabe) │ │
├─────────────────────────────────┼───────
│Betreiber*= │ Operator/= │
├─────────────────────────────────┼───────
│Betreiber+= │ Operator-= │
├─────────────────────────────────┼───────
│Operator++ (sowohl Präfix als auch │ │
│Postfix) │ │
├─────────────────────────────────┼───────
│Operator-- (sowohl Präfix als auch │ │
│Postfix) │ │
├─────────────────────────────────┼───────
│Betreiber<<= │ Betreiber>>= │
├─────────────────────────────────┼───────
│Operator&= │ Operator|= │
├─────────────────────────────────┼───────
│Betreiber%= │ Operator^= │
└─────────────────────────────────┻────
Was das alles wirklich bedeutet, ist, dass Sie alle Änderungen nachverfolgen können, die mit diesen vorgenommen wurden
Operatoren zu einem C++-Objekt, das Wertsemantik hat.
Die TraceWert<> Deklaration, die wir oben gesehen haben, stellt die Infrastruktur bereit, die die überlastet
oben genannten Operatoren und steuert den Rückrufprozess. Bei Verwendung eines der Operatoren
oben mit a Nachverfolgter Wert es liefert sowohl den alten als auch den neuen Wert dieser Variablen,
in diesem Fall ein int32_t Wert. Durch Inspektion der Nachverfolgter Wert Erklärung, wir kennen die
Trace-Senkenfunktion wird Argumente haben (konst int32_t alterWert, const int32_t neuer Wert).
Der Rückgabetyp für a Nachverfolgter Wert Callback-Funktion ist immer ungültig, also das erwartete
Die Callback-Signatur lautet:
void (* TracedValueCallback) (const int32_t oldValue, const int32_t newValue);
Die .TraceSource hinzufügen begann GetTypeId -Methode stellt die "Hooks" bereit, die zum Verbinden der verwendet werden
Trace-Quelle zur Außenwelt durch das Config-System. Die haben wir bereits besprochen
ersten drei agruments zu TraceSource hinzufügen: der Attributname für das Config-System, eine Hilfe
string und die Adresse des Datenmembers der TracedValue-Klasse.
Das letzte String-Argument, „ns3::Traced::Value::Int32“ im Beispiel, ist der Name von a
typedef für die Signatur der Callback-Funktion. Wir verlangen, dass diese Signaturen definiert werden,
und geben Sie den vollqualifizierten Typnamen an TraceSource hinzufügen, damit die API-Dokumentation dies kann
eine Ablaufverfolgungsquelle mit der Funktionssignatur verknüpfen. Für TracedValue ist die Signatur
einfach; Für TracedCallbacks haben wir bereits gesehen, dass die API-Dokumentation wirklich hilfreich ist.
Real Beispiel
Lassen Sie uns ein Beispiel aus einem der bekanntesten Bücher über TCP machen. "TCP/IP
Illustriert, Band 1: Die Protokolle“ von W. Richard Stevens ist ein Klassiker. Ich habe gerade umgedreht
Das Buch öffnete sich und lief über eine schöne Darstellung sowohl des Staufensters als auch der Sequenz
Zahlen gegen Zeit auf Seite 366. Stevens nennt dies „Abbildung 21.10. Wert von cwnd and
Sequenznummer senden, während Daten übertragen werden." Lassen Sie uns einfach den cwnd-Teil neu erstellen
dieser Handlung in NS-3 mit dem Rückverfolgungssystem und Gnuplot.
Verfügbare Quellen
Das erste, woran wir denken müssen, ist, wie wir die Daten herausbekommen wollen. Was haben wir
müssen verfolgen? Lassen Sie uns also die Liste "Alle Trace-Quellen" konsultieren, um zu sehen, was wir tun müssen
mit. Denken Sie daran, dass dies in der gefunden wird NS-3 API-Dokumentation. Wenn Sie durch die blättern
Liste finden Sie schließlich:
ns3::TCPNewReno
· Staufenster: Das Überlastungsfenster der TCP-Verbindung
· SlowStartThreshold: TCP-Schwellenwert für langsamen Start (Byte)
Es stellt sich heraus, dass die NS-3 Die TCP-Implementierung lebt (meistens) in der Datei
src/internet/model/tcp-socket-base.cc während Staukontrollvarianten in Dateien wie z
as src/internet/model/tcp-newreno.cc. Wenn Sie dies nicht wissen a priori, können Sie die
rekursive grep Trick:
$finden. -name '*.cc' | xargs grep -i tcp
Sie werden Seite für Seite Instanzen von tcp finden, die Sie auf diese Datei verweisen.
Aufrufen der Klassendokumentation für TCPNewReno und Springen zur Liste von
TraceSources finden Sie
TraceSources
· Staufenster: Das Überlastungsfenster der TCP-Verbindung
Callback-Signatur: ns3::Traced::Value::Uint322Callback
Klicken Sie auf den Rückruf typedef Link sehen wir die Signatur, die Sie jetzt erwarten:
typedef void(* ns3::Traced::Value::Int32Callback)(const int32_t oldValue, const int32_t newValue)
Sie sollten diesen Code jetzt vollständig verstehen. Wenn wir einen Hinweis auf die haben TCPNewReno,
wir können TraceConnect an die Ablaufverfolgungsquelle „CongestionWindow“, wenn wir eine entsprechende bereitstellen
Callback-Ziel. Dies ist die gleiche Art von Ablaufverfolgungsquelle, die wir in dem einfachen Beispiel gesehen haben
am Anfang dieses Abschnitts, außer dass wir darüber sprechen uint32_t statt
int32_t. Und wir wissen, dass wir eine Callback-Funktion mit dieser Signatur bereitstellen müssen.
Erkenntnis Beispiele
Es ist immer am besten, zu versuchen, funktionierenden Code zu finden, der herumliegt und den Sie ändern können
als bei Null anzufangen. Also ist die erste Aufgabe jetzt, einen Code zu finden, der das ist
hakt bereits die Ablaufverfolgungsquelle „CongestionWindow“ ein und prüft, ob wir sie ändern können. Wie gewöhnlich,
grep ist dein Freund:
$finden. -name '*.cc' | xargs grep CongestionWindow
Dies wird auf ein paar vielversprechende Kandidaten hinweisen: example/tcp/tcp-large-transfer.cc
und src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc.
Wir haben noch keinen der Testcodes besucht, also lasst uns dort einen Blick darauf werfen. Du wirst
finden normalerweise, dass der Testcode ziemlich minimal ist, also ist dies wahrscheinlich eine sehr gute Wette.
Öffnen src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc in Ihrem bevorzugten Editor und suchen Sie nach
"CongestionWindow". Du wirst finden,
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));
Dies sollte Ihnen sehr bekannt vorkommen. Wir haben oben erwähnt, dass wenn wir einen Zeiger auf die hätten
TCPNewReno, wir könnten TraceConnect zur Ablaufverfolgungsquelle "CongestionWindow". Das ist genau
was wir hier haben; Es stellt sich also heraus, dass diese Codezeile genau das tut, was wir wollen.
Lassen Sie uns fortfahren und den benötigten Code aus dieser Funktion extrahieren (Ns3TcpCwndTestCase1::DoRun
(Leere)). Wenn Sie sich diese Funktion ansehen, werden Sie feststellen, dass sie genau wie eine aussieht NS-3
Skript. Es stellt sich heraus, dass es genau das ist. Es ist ein Skript, das vom Test ausgeführt wird
Rahmen, so dass wir es einfach herausziehen und einpacken können Haupt- statt in DoRun. Eher
als Schritt für Schritt durchzugehen, haben wir die Datei bereitgestellt, die aus der Portierung resultiert
dieser Test zurück zu einem nativen NS-3 Skript -- beispiele/tutorial/fifth.cc.
Dynamisch Spur Quellen
Die fünfte.cc Beispiel zeigt eine äußerst wichtige Regel, die Sie verstehen müssen
bevor Sie irgendeine Art von Ablaufverfolgungsquelle verwenden: Sie müssen sicherstellen, dass das Ziel von a
Konfig::Verbinden Befehl existiert, bevor Sie versuchen, ihn zu verwenden. Das ist nicht anders als zu sagen
ein Objekt muss instanziiert werden, bevor versucht wird, es aufzurufen. Obwohl dies offensichtlich erscheinen mag
Wenn es so gesagt wird, bringt es viele Leute zum Stolpern, die versuchen, das System zum ersten Mal zu benutzen
Zeit.
Kehren wir für einen Moment zu den Grundlagen zurück. Es gibt drei grundlegende Ausführungsphasen, die in existieren
jedem NS-3 Skript. Die erste Phase wird manchmal als „Konfigurationszeit“ oder „Setup“ bezeichnet
Zeit" und existiert während der Zeit, in der die Haupt- Funktion Ihres Skripts läuft, aber
bevor Simulator::Ausführen wird genannt. Die zweite Phase wird manchmal als "Simulationszeit" bezeichnet.
und existiert während des Zeitraums, in dem Simulator::Ausführen führt seine Veranstaltungen aktiv aus.
Nachdem die Ausführung der Simulation abgeschlossen ist, Simulator::Ausführen wird die Kontrolle zurück an
Haupt- Funktion. Wenn dies geschieht, tritt das Skript in das ein, was als „Teardown
Phase", in der die während des Aufbaus erstellten Strukturen und Objekte auseinandergenommen und
freigegeben.
Der vielleicht häufigste Fehler bei dem Versuch, das Rückverfolgungssystem zu verwenden, besteht darin, dies anzunehmen
dynamisch konstruierte Entitäten im Simulation Zeit sind während der Konfiguration verfügbar
Zeit. Insbesondere ein NS-3 Steckdose ist ein dynamisches Objekt, das oft von erstellt wird Anwendungen zu
kommunizieren zwischen NodesEine NS-3 Anwendungs- hat immer eine "Startzeit" und ein "Ende".
Zeit" damit verbunden. In den allermeisten Fällen ist eine Anwendungs- werde es nicht versuchen
um ein dynamisches Objekt zu erstellen, bis seine Bewerbung starten Methode wird bei einigen "Start
Zeit". Damit soll sichergestellt werden, dass die Simulation vor der App vollständig konfiguriert ist
versucht irgendetwas zu tun (was passieren würde, wenn es versuchen würde, sich mit einem Knoten zu verbinden, der nicht existiert
noch während der Konfigurationszeit?). Infolgedessen ist dies während der Konfigurationsphase nicht möglich
Verbinden Sie eine Ablaufverfolgungsquelle mit einer Ablaufverfolgungssenke, wenn eine davon dynamisch während erstellt wird
Simulation.
Die beiden Lösungen für dieses Rätsel sind
1. Erstellen Sie ein Simulatorereignis, das ausgeführt wird, nachdem das dynamische Objekt erstellt wurde, und verknüpfen Sie das
verfolgen, wann dieses Ereignis ausgeführt wird; oder
2. Erstellen Sie das dynamische Objekt zur Konfigurationszeit, hängen Sie es dann ein und geben Sie das Objekt an
das während der Simulationszeit zu verwendende System.
Wir nahmen den zweiten Ansatz in der fünfte.cc Beispiel. Diese Entscheidung erforderte von uns zu schaffen
MyApp Anwendungs-, deren gesamter Zweck darin besteht, a Steckdose als ein Parameter.
Exemplarische Vorgehensweise: fünfte.cc
Werfen wir nun einen Blick auf das Beispielprogramm, das wir erstellt haben, indem wir die Überlastung analysiert haben
Fenstertest. Offen beispiele/tutorial/fifth.cc in Ihrem bevorzugten Editor. Das solltest du sehen
ein bekannt aussehender Code:
/* -*- Modus:C++; c-Dateistil:"gnu"; einrücken-tabs-modus:nil; -*- */
/*
* Dieses Programm ist freie Software; Sie können es weitergeben und/oder ändern
* es unter den Bedingungen der GNU General Public License Version 2 als
* veröffentlicht von der Free Software Foundation;
*
* Dieses Programm wird in der Hoffnung verteilt, dass es nützlich ist,
* jedoch OHNE JEGLICHE GARANTIE; auch ohne die stillschweigende garantie von
* MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Siehe die
* GNU General Public License für weitere Details.
*
* Sie sollten eine Kopie der GNU General Public License erhalten haben
* zusammen mit diesem Programm; wenn nicht, schreiben Sie an die Freie Software
* Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#einschließen
#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"
Verwenden des Namensraums ns3;
NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");
Dies wurde alles abgedeckt, also werden wir es nicht noch einmal aufwärmen. Die nächsten Quellenzeilen sind die
Netzwerkabbildung und einen Kommentar, der das oben beschriebene Problem anspricht Steckdose.
// ============================================== ==========================
//
// Knoten 0 Knoten 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | Punkt-zu-Punkt | | Punkt-zu-Punkt |
// +----------------+ +----------------+
// | |
// +---------------------+
// 5 Mbit/s, 2 ms
//
//
// Wir wollen uns die Änderungen im ns-3-TCP-Überlastungsfenster ansehen. Wir brauchen
// um einen Flow anzukurbeln und das CongestionWindow-Attribut auf den Socket zu haken
// des Absenders. Normalerweise würde man eine On-Off-Anwendung verwenden, um a zu generieren
// flow, aber das hat ein paar Probleme. Zuerst die Steckdose des Ein-Aus
// Die Anwendung wird nicht vor der Startzeit der Anwendung erstellt, also würden wir das nicht tun
// Kann den Socket (jetzt) zur Konfigurationszeit einhaken. Zweitens, auch wenn wir
// könnte einen Anruf nach der Startzeit vereinbaren, der Socket ist nicht öffentlich, also wir
// kam nicht drauf.
//
// Wir können uns also eine einfache Version der Ein-Aus-Anwendung ausdenken, die was tut
// wir wollen. Auf der positiven Seite brauchen wir nicht die ganze Komplexität des An-Aus
// Anwendung. Auf der Minusseite haben wir keinen Helfer, also müssen wir kommen
// etwas mehr in die Details verwickelt, aber das ist trivial.
//
// Also erstellen wir zuerst einen Socket und führen die Trace-Verbindung darauf aus; dann passieren wir
// diesen Socket in den Konstruktor unserer einfachen Anwendung, die wir dann
// im Quellknoten installieren.
// ============================================== ==========================
//
Auch dies sollte selbsterklärend sein.
Der nächste Teil ist die Erklärung der MyApp Anwendungs- die wir zusammengestellt haben, um zu ermöglichen
Steckdose zur Konfigurationszeit erstellt werden.
Klasse MyApp: öffentliche Anwendung
{
Öffentlichkeit:
Meine App ();
virtuell ~MyApp();
void Setup (Ptr Socket, Adressadresse, uint32_t packetSize,
uint32_t nPackets, DataRate dataRate);
Privatgelände:
virtuelle void StartApplication (void);
virtuelle Leere StopApplication (void);
void ScheduleTx (nichtig);
void Sendepaket (void);
Ptr m_socket;
Adresse m_peer;
uint32_t m_packetSize;
uint32_t m_nPakete;
Datenrate m_dataRate;
EventId m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};
Sie können sehen, dass diese Klasse von erbt NS-3 Anwendungs- Klasse. Schau es dir an
src/network/model/application.h wenn Sie daran interessiert sind, was vererbt wird. Das MyApp
Klasse ist verpflichtet, die zu überschreiben Bewerbung starten und Anwendung stoppen Methoden. Diese
Methoden werden automatisch aufgerufen, wenn MyApp ist erforderlich, um das Senden von Daten zu starten und zu stoppen
während der Simulation.
Starten/Stoppen Anwendungen
Es lohnt sich, ein wenig Zeit damit zu verbringen, zu erklären, wie die Ereignisse in der eigentlich beginnen
System. Dies ist eine weitere ziemlich tiefgründige Erklärung und kann ignoriert werden, wenn Sie es nicht sind
planen, sich in die Eingeweide des Systems vorzuwagen. Dabei ist es jedoch nützlich
die Diskussion berührt, wie einige sehr wichtige Teile von NS-3 Arbeit und macht einige frei
wichtige Redewendungen. Wenn Sie planen, neue Modelle zu implementieren, möchten Sie dies wahrscheinlich tun
diesen Abschnitt verstehen.
Die gebräuchlichste Art, Pumping-Events zu starten, ist das Starten eines Anwendungs-. Dies geschieht als
das Ergebnis der folgenden (hoffentlich) vertrauten Zeilen von an NS-3 Skript:
ApplicationContainer-Apps = ...
apps.Start (Sekunden (1.0));
apps.Stop (Sekunden (10.0));
Der Code des Anwendungscontainers (vgl src/network/helper/application-container.h wenn du bist
interessiert) durchläuft seine enthaltenen Anwendungen und Aufrufe,
app->SetStartTime (startTime);
als Ergebnis der apps.Start anrufen und
app->SetStopTime (stopTime);
als Ergebnis der apps.Stop Anruf.
Das Endergebnis dieser Anrufe ist, dass wir den Simulator automatisch haben wollen
telefonieren Sie in unsere Anwendungen um ihnen zu sagen, wann sie anfangen und aufhören sollen. Im Falle von
MyApp, erbt es von der Klasse Anwendungs- und überschreibt Bewerbung starten und
Anwendung stoppen. Dies sind die Funktionen, die vom Simulator aufgerufen werden
angemessene Zeit. Im Falle von MyApp Sie werden das finden MyApp::StartApplication die
die anfängliche Binden und Verbinden auf dem Socket und startet dann den Datenfluss durch Aufrufen
MyApp::SendPacket. MeineApp::StopApplication stoppt die Generierung von Paketen, indem es irgendwelche abbricht
Anstehende Sendeereignisse schließen dann den Socket.
Eines der schönen Dinge an NS-3 ist, dass Sie die Implementierung vollständig ignorieren können
Einzelheiten darüber, wie Ihre Anwendungs- wird vom Simulator "automatisch" an der richtigen Stelle aufgerufen
Zeit. Aber da haben wir uns schon tief hinein gewagt NS-3 schon, los geht's.
Wenn man sich src/network/model/application.cc Sie werden feststellen, dass die SetStartTime Methode
eines Anwendungs- setzt nur die Member-Variable m_startTime und der SetStopTime Methode
nur setzt m_stopTime. Von dort aus wird der Weg ohne einige Hinweise wahrscheinlich enden.
Der Schlüssel zum Wiederaufnehmen der Spur ist zu wissen, dass es eine globale Liste aller gibt
Knoten im System. Immer wenn Sie einen Knoten in einer Simulation erstellen, wird ein Zeiger auf diesen Knoten
wird der globalen hinzugefügt Knotenliste.
Wirf einen Blick auf src/network/model/node-list.cc und die Suche nach Knotenliste::Hinzufügen. Die Öffentlichkeit
statische Implementierung ruft eine private Implementierung auf, die aufgerufen wird NodeListPriv::Hinzufügen. Dies
ist ein relativ verbreitetes Idom in NS-3. Also, schau mal rein NodeListPriv::Hinzufügen. Da bist du
wird finden,
Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Initialize, node);
Dies sagt Ihnen, dass jedes Mal, wenn ein Knoten in einer Simulation erstellt wird, als Nebeneffekt ein Aufruf erfolgt
zu diesem Knoten Initialisieren Methode ist für Sie geplant, die zum Zeitpunkt Null geschieht. Nicht
Lesen Sie zu viel in diesen Namen, noch. Das bedeutet nicht, dass der Node damit anfangen wird
irgendetwas, es kann als Informationsaufruf in den Knoten interpretiert werden, der ihm mitteilt, dass die
Die Simulation hat begonnen, kein Handlungsaufruf, der den Knoten auffordert, etwas zu tun.
Damit Knotenliste::Hinzufügen plant indirekt einen Anruf an Knoten::Initialisieren zum Zeitpunkt Null a zu beraten
neuer Knoten, dass die Simulation gestartet wurde. Wenn du reinschaust src/network/model/node.h U
findet jedoch keine aufgerufene Methode Knoten::Initialisieren. Es stellt sich heraus, dass die
Initialisieren Die Methode wird von der Klasse geerbt Betreff. Alle Objekte im System können sein
benachrichtigt, wenn die Simulation beginnt, und Objekte der Klasse Node sind nur eine Art davon
Objekte.
Wirf einen Blick auf src/core/model/object.cc weiter und suchen Sie nach Objekt::Initialisieren. Dieser Code
ist nicht so einfach, wie Sie vielleicht erwartet haben NS-3 Objekte Support
Anhäufung. Der Code drin Objekt::Initialisieren durchläuft dann alle Objekte, die
wurden zusammen aggregiert und nennt ihre Doinitialisieren Methode. Dies ist eine andere Redewendung
das ist sehr verbreitet in NS-3, manchmal auch als „Template Design Pattern“ bezeichnet: ein öffentliches
nicht-virtuelle API-Methode, die über Implementierungen hinweg konstant bleibt und die a aufruft
private virtuelle Implementierungsmethode, die von Unterklassen geerbt und implementiert wird.
Die Namen sind normalerweise so etwas wie Methodenname für die öffentliche API und DoMethodName für
die private API.
Dies sagt uns, dass wir nach a suchen sollten Node::DoInitialize Methode in
src/network/model/node.cc für die Methode, die unsere Spur fortsetzen wird. Wenn Sie die finden
Code finden Sie eine Methode, die alle Geräte im Knoten durchläuft und dann
alle Anwendungen im Node-Aufruf Gerät -> Initialisieren und Anwendung -> Initialisieren
beziehungsweise.
Vielleicht kennen Sie diese Klassen bereits Gerät und Anwendungs- beide erben von der Klasse Betreff
und so wird der nächste Schritt sein, zu schauen, was wann passiert Anwendung::DoInitialize is
namens. Schauen Sie sich an src/network/model/application.cc und du findest:
ungültig
Anwendung::DoInitialize (void)
{
m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, this);
if (m_stopTime != TimeStep (0))
{
m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, this);
}
Objekt::DoInitialize ();
}
Hier kommen wir schließlich zum Ende des Weges. Wenn Sie alles richtig gehalten haben, wenn Sie
implementieren ein NS-3 Anwendungs-, erbt Ihre neue Anwendung von der Klasse Anwendungs-. Sie
überschreiben die Bewerbung starten und Anwendung stoppen Methoden und bieten Mechanismen für
Starten und Stoppen des Datenflusses aus Ihrem neuen Anwendungs-. Wenn ein Knoten ist
in der Simulation erstellt, wird es zu einem globalen hinzugefügt Knotenliste. Der Vorgang des Hinzufügens eines Knotens zu
fehlen uns die Worte. Knotenliste bewirkt, dass ein Simulatorereignis zum Zeitpunkt Null geplant wird, das die aufruft
Knoten::Initialisieren -Methode des neu hinzugefügten Knotens, die aufgerufen werden soll, wenn die Simulation beginnt.
Da ein Knoten erbt von Betreff, das ruft die Objekt::Initialisieren Methode auf dem Node
die wiederum die ruft Doinitialisieren Methoden auf allen Objekte aggregiert zum
Knoten (denken Sie an Mobilitätsmodelle). Da der Knoten Betreff hat überschrieben Doinitialisieren, Dass
-Methode wird aufgerufen, wenn die Simulation beginnt. Das Node::DoInitialize Methode ruft die
Initialisieren Methoden aller Anwendungen auf dem Knoten. Seit Anwendungen Auch
Objekte, Dies bewirkt Anwendung::DoInitialize heißen. Wann
Anwendung::DoInitialize aufgerufen wird, plant es Ereignisse für die Bewerbung starten und
Anwendung stoppen ruft die Anwendungs-. Diese Anrufe dienen zum Starten und Stoppen der
Datenfluss aus der Anwendungs-
Dies war eine weitere ziemlich lange Reise, aber sie muss nur einmal gemacht werden, und Sie jetzt
verstehe ein weiteres sehr tiefes Stück NS-3.
Die MyApp Anwendungs-
Die MyApp Anwendungs- benötigt natürlich einen Konstruktor und einen Destruktor:
MeineApp::MeineApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPakete (0),
m_dataRate (0),
m_sendEvent (),
m_running (falsch),
m_packetsGesendet (0)
{
}
MeineApp::~MeineApp()
{
m_socket = 0;
}
Die Existenz des nächsten Code-Bits ist der ganze Grund, warum wir dies geschrieben haben Anwendungs- in
den ersten Platz.
ungültig
MeineApp::Setup (Ptr Socket, Adressadresse, uint32_t packetSize,
uint32_t nPakete, DataRate dataRate)
{
m_socket = buchse;
m_peer = Adresse;
m_packetSize = Paketgröße;
m_nPakete = nPakete;
m_dataRate = dataRate;
}
Dieser Code sollte ziemlich selbsterklärend sein. Wir initialisieren nur Member-Variablen.
Das Wichtige aus Sicht der Rückverfolgung ist die Ptr Buchse welche wir
die der Anwendung während der Konfigurationszeit zur Verfügung gestellt werden müssen. Denken Sie daran, dass wir gehen
das erstellen Steckdose als ein TCPSocket (welches implementiert wird von TCPNewReno) und haken Sie es ein
Ablaufverfolgungsquelle "CongestionWindow", bevor Sie sie an die übergeben Einrichtung Methode.
ungültig
MyApp::StartApplication (nichtig)
{
m_running = wahr;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Verbinden (m_peer);
Paket senden ();
}
Der obige Code ist die überschriebene Implementierung Anwendung::Anwendung starten das wird sein
automatisch vom Simulator aufgerufen, um unsere zu starten Anwendungs- Laufen an der entsprechenden
Zeit. Sie können sehen, dass es a tut Steckdose Binden Betrieb. Wenn Sie sich auskennen
Berkeley Sockets sollte dies keine Überraschung sein. Es führt die erforderlichen Arbeiten auf der lokalen Ebene aus
Seite der Verbindung, so wie Sie es vielleicht erwarten. Folgende Verbinden wird tun, was ist
erforderlich, um eine Verbindung mit dem TCP herzustellen Adresse m_peer. Jetzt sollte es klar sein
warum wir viel davon auf die Simulationszeit verschieben müssen, da die Verbinden wird brauchen
ein voll funktionsfähiges Netzwerk zu vervollständigen. Nach dem Verbinden, der Anwendungs- dann beginnt
Erstellen von Simulationsereignissen durch Aufrufen Paket senden.
Das nächste Codebit erklärt die Anwendungs- wie man die Erstellung von Simulationsereignissen beendet.
ungültig
MyApp::StopApplication (nichtig)
{
m_running = falsch;
if (m_sendEvent.IsRunning ())
{
Simulator::Abbrechen (m_sendEvent);
}
wenn (m_socket)
{
m_socket->Schließen ();
}
}
Jedes Mal, wenn ein Simulationsereignis geplant ist, wird an Event geschaffen. Wenn die Event steht an
Ausführung oder Ausführung, seine Methode Läuft wird zurückkehren was immer dies auch sein sollte.. In diesem Code, wenn
Läuft() kehrt wahr, wir Abbrechen das Ereignis, das es aus dem Simulatorereignis entfernt
Warteschlange. Dadurch unterbrechen wir die Kette von Ereignissen, die die Anwendungs- verwendet, um zu halten
Senden seiner Pakete und der Anwendungs- geht ruhig. Nachdem wir das beruhigt haben Anwendungs- we
Menu der Socket, der die TCP-Verbindung abbaut.
Der Socket wird tatsächlich im Destruktor gelöscht, wenn die m_socket = 0 ausgeführt wird. Dies
entfernt den letzten Verweis auf den zugrunde liegenden Ptr was den Destruktor von bewirkt
das aufzurufende Objekt.
Erinnere dich daran Bewerbung starten namens Paket senden um die Kette von Ereignissen zu starten, die beschreibt
Anwendungs- Verhalten.
ungültig
MyApp::SendPacket (ungültig)
{
Ptr Paket = Erstellen (m_packetSize);
m_socket->Senden (Paket);
if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}
Hier siehst du das Paket senden tut genau das. Es entsteht ein Paket und macht dann a Absenden
was, wenn Sie Berkeley Sockets kennen, wahrscheinlich genau das ist, was Sie erwartet haben.
Es liegt in der Verantwortung der Anwendungs- um die Kette von Ereignissen zu planen, so dass die
Die nächsten Zeilen rufen an ScheduleTx um ein weiteres Sendeereignis zu planen (a Paket senden) bis zum
Anwendungs- entscheidet, dass es genug gesendet hat.
ungültig
MyApp::ScheduleTx (ungültig)
{
wenn (m_läuft)
{
Zeit tNext (Sekunden (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
Hier siehst du das ScheduleTx tut genau das. Wenn die Anwendungs- läuft (ggf
Anwendung stoppen nicht angerufen wurde) wird ein neues Ereignis geplant, das anruft Paket senden
wieder. Der aufmerksame Leser wird etwas entdecken, das auch neue Benutzer zum Stolpern bringt. Die Datenrate
eines Anwendungs- ist genau das. Es hat nichts mit der Datenrate eines Basiswerts zu tun
Kanal. Dies ist die Rate, mit der die Anwendungs- produziert Bits. Es nimmt nicht auf
Berücksichtigen Sie den Overhead für die verschiedenen Protokolle oder Kanäle, die zum Transport der verwendet werden
Daten. Stellt man die Datenrate auf eine Anwendungs- zum gleichen Datenkurs wie Ihr Basiswert
Kanal Sie erhalten schließlich einen Pufferüberlauf.
Spur Sinkt
Der springende Punkt dieser Übung ist es, Trace-Callbacks von TCP zu erhalten, die das angeben
Staufenster wurde aktualisiert. Das nächste Stück Code implementiert das entsprechende
Spurensenke:
Statische Leere
CwndChange (uint32_t alteCwnd, uint32_t neueCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}
Dies sollte Ihnen jetzt sehr vertraut sein, daher werden wir nicht auf die Details eingehen. Diese Funktion
protokolliert nur die aktuelle Simulationszeit und den neuen Wert des Staufensters jeden
Zeit es geändert wird. Sie können sich wahrscheinlich vorstellen, dass Sie die resultierende Ausgabe laden könnten
in ein Grafikprogramm (gnuplot oder Excel) und sehen sofort eine schöne Grafik der
Verhalten des Staufensters im Laufe der Zeit.
Wir haben eine neue Trace-Senke hinzugefügt, um anzuzeigen, wo Pakete verworfen werden. Wir werden einen Fehler hinzufügen
model auch zu diesem Code, also wollten wir diese Funktionsweise demonstrieren.
Statische Leere
RxDrop (Ptr p)
{
NS_LOG_UNCOND ("RxDrop bei " << Simulator::Now ().GetSeconds ());
}
Diese Trace-Senke wird mit der Trace-Quelle "PhyRxDrop" des Point-to-Point verbunden
NetDevice. Diese Ablaufverfolgungsquelle wird ausgelöst, wenn ein Paket von der physischen Schicht von a verworfen wird
NetDevice. Wenn Sie einen kleinen Abstecher zur Quelle machen
(src/point-to-point/model/point-to-point-net-device.cc) Sie werden sehen, dass diese Spur
Quelle verweist PointToPointNetDevice::m_phyRxDropTrace. Wenn du dann reinschaust
src/point-to-point/model/point-to-point-net-device.h für diese Mitgliedsvariable werden Sie
finde, dass es als deklariert ist TracedCallback Paket> >. Das sollte es dir sagen
dass das Callback-Ziel eine Funktion sein sollte, die void zurückgibt und eine Single akzeptiert
Parameter, der a ist Ptr Paket> (vorausgesetzt wir verwenden ConnectWithoutContext) -- Nur
was wir oben haben.
Main Mentessa for Good
Der folgende Code sollte Ihnen inzwischen sehr vertraut sein:
int
main (int argc, char *argv[])
{
NodeContainer-Knoten;
Knoten.Erstellen (2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Verzögerung", StringValue ("2ms"));
NetDeviceContainer-Geräte;
Geräte = pointToPoint.Install (Knoten);
Dadurch werden zwei Knoten mit einem Punkt-zu-Punkt-Kanal zwischen ihnen erstellt, genau wie in gezeigt
Abbildung am Anfang der Datei.
Die nächsten Codezeilen zeigen etwas Neues. Wenn wir eine Verbindung verfolgen, die sich verhält
perfekt, wir werden am Ende ein monoton steigendes Überlastungsfenster haben. Um irgendwelche zu sehen
interessantes Verhalten, wir wollen wirklich Verbindungsfehler einführen, die Pakete verwerfen,
verursachen doppelte ACKs und lösen die interessanteren Verhaltensweisen des Überlastungsfensters aus.
NS-3 bietet Fehlermodell Gegenstände, an die man sich heften kann Kanäle. Wir verwenden die
RateErrorModel was uns erlaubt, Fehler in a einzuführen Kanal zu gegebener Zeit Rate.
Ptr em = CreateObject ();
em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));
Der obige Code instanziiert a RateErrorModel Objekt, und wir setzen die "ErrorRate" Attribut
auf den gewünschten Wert. Wir setzen dann das Ergebnis instanziiert RateErrorModel als Fehler
Modell, das von der Punkt-zu-Punkt-Verbindung verwendet wird NetDevice. Dies wird uns einige Neuübertragungen geben und
unsere Handlung ein wenig interessanter machen.
InternetStackHelper-Stack;
stack.Install (Knoten);
IPv4AddressHelper-Adresse;
address.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer-Schnittstellen = address.Assign (Geräte);
Der obige Code sollte vertraut sein. Es installiert Internet-Stacks auf unseren beiden Knoten und
erstellt Schnittstellen und weist IP-Adressen für die Punkt-zu-Punkt-Geräte zu.
Da wir TCP verwenden, benötigen wir etwas auf dem Zielknoten, um TCP zu empfangen
Verbindungen und Daten. Das PaketSink Anwendungs- wird häufig in verwendet NS-3 dafür
Zweck.
uint16_t sinkPort = 8080;
Adresse sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
sinkApps.Start (Sekunden (0.));
sinkApps.Stop (Sekunden (20.));
Das sollte alles vertraut sein, mit Ausnahme von
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
Dieser Code instanziiert a PacketSinkHelper und weist es an, Sockets mit der Klasse zu erstellen
ns3::TCPSocketFactory. Diese Klasse implementiert ein Entwurfsmuster namens "Objektfabrik".
Dies ist ein häufig verwendeter Mechanismus zum Angeben einer Klasse, die zum Erstellen von Objekten in einer verwendet wird
abstrakter Weg. Anstatt die Objekte selbst erstellen zu müssen, stellen Sie hier die bereit
PacketSinkHelper eine Zeichenfolge, die a angibt Typ-ID Zeichenfolge verwendet, um ein Objekt zu erstellen, das
kann dann wiederum verwendet werden, um Instanzen der von der Factory erstellten Objekte zu erstellen.
Der verbleibende Parameter sagt die Anwendungs- welche Adresse und welchen Port es haben soll Binden nach.
Die nächsten beiden Codezeilen erstellen den Socket und verbinden die Ablaufverfolgungsquelle.
Ptr ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
TcpSocketFactory::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&CwndChange));
Die erste Anweisung ruft die statische Elementfunktion auf Sockel::CreateSocket und bietet eine
Knoten und eine explizite Typ-ID für die Objektfabrik, die zum Erstellen des Sockets verwendet wird. Das ist ein
etwas niedrigeres Niveau anrufen als die PacketSinkHelper oben aufrufen und verwendet ein explizites C++
type anstelle von einem, auf den durch eine Zeichenfolge verwiesen wird. Ansonsten ist es konzeptionell gleich
Ding.
Sobald die TCPSocket erstellt und an den Knoten angehängt ist, können wir verwenden
TraceConnectWithoutContext um die CongestionWindow-Ablaufverfolgungsquelle mit unserer Ablaufverfolgungssenke zu verbinden.
Denken Sie daran, dass wir ein kodiert haben Anwendungs- also könnten wir das nehmen Steckdose wir haben gerade gemacht (während
Konfigurationszeit) und verwenden Sie es in der Simulationszeit. Das müssen wir jetzt instanziieren
Anwendungs-. Wir haben uns keine Mühe gemacht, einen Helfer zu erstellen, um das zu verwalten Anwendungs- so
wir müssen es "manuell" erstellen und installieren. Das ist eigentlich ganz einfach:
Ptr app = CreateObject ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
nodes.Get (0)->AddApplication (app);
app->Start (Sekunden (1.));
app->Stop (Sekunden (20.));
Die erste Zeile erstellt eine Betreff oder Typ MyApp -- unser Anwendungs-. Die zweite Zeile erzählt
Anwendungs- was Steckdose zu verwenden, mit welcher Adresse eine Verbindung hergestellt werden soll, wie viele Daten gesendet werden sollen
jedes Sendeereignis, wie viele Sendeereignisse generiert werden sollen und mit welcher Rate Daten erzeugt werden sollen
von diesen Ereignissen.
Als nächstes fügen wir die manuell hinzu MyApp Anwendungs- zum Quellknoten und rufen Sie die explizit auf
Startseite und Stoppen Methoden auf dem Anwendungs- um ihm zu sagen, wann er damit beginnen und aufhören soll
Ding.
Wir müssen tatsächlich die Verbindung vom Empfänger Punkt-zu-Punkt herstellen NetDevice Ereignis fallen lassen
zu unserer RxDrop Rückruf jetzt.
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));
Es sollte nun offensichtlich sein, dass wir einen Hinweis auf das Empfangen bekommen Knoten NetDevice
aus seinem Container und verbindet die durch das Attribut "PhyRxDrop" definierte Trace-Quelle weiter
dieses Gerät an die Trace-Senke RxDrop.
Schließlich weisen wir den Simulator an, alle zu überschreiben Anwendungen und höre einfach auf zu verarbeiten
Ereignisse nach 20 Sekunden in die Simulation.
Simulator::Stopp (Sekunden(20));
Simulator::Run ();
Simulator::Zerstören ();
Rückkehr 0;
}
Daran erinnern, sobald Simulator::Ausführen wird aufgerufen, die Konfigurationszeit endet und die Simulation
Zeit beginnt. Die gesamte Arbeit, die wir orchestriert haben, indem wir die Anwendungs- und es zu lehren
wie eine Verbindung hergestellt und Daten gesendet werden, geschieht tatsächlich während dieses Funktionsaufrufs.
Sobald Simulator::Ausführen kehrt zurück, die Simulation ist abgeschlossen und wir treten in den Teardown ein
Phase. In diesem Fall, Simulator::Zerstören kümmert sich um die blutigen Details und wir kehren einfach zurück
einen Erfolgscode nach Abschluss.
Laufen fünfte.cc
Da haben wir die Datei bereitgestellt fünfte.cc für Sie, wenn Sie Ihre Distribution (in
Debug-Modus, da es verwendet NS_LOG -- Denken Sie daran, dass optimierte Builds optimiert werden NS_LOG) es
wird darauf warten, dass Sie laufen.
$ ./waf --fünfte ausführen
Waf: Verzeichnis `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build' eingeben
Waf: Verzeichnis „/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build“ verlassen
'build' erfolgreich abgeschlossen (0.684s)
1 536
1.0093 1072
1.01528 1608
1.02167 2144
...
1.11319 8040
1.12151 8576
1.12983 9112
RxDrop bei 1.13696
...
Sie können wahrscheinlich sofort einen Nachteil der Verwendung von Drucken jeglicher Art in Ihren Spuren erkennen.
Wir erhalten diese überflüssigen WAF-Nachrichten, die überall auf unseren interessanten Informationen gedruckt werden
mit diesen RxDrop-Nachrichten. Wir werden das bald beheben, aber ich bin sicher, Sie können es kaum erwarten, es zu sehen
die Ergebnisse all dieser Arbeit. Lassen Sie uns diese Ausgabe in eine Datei namens umleiten cwnd.dat:
$ ./waf --run five > cwnd.dat 2>&1
Bearbeiten Sie nun "cwnd.dat" in Ihrem bevorzugten Editor und entfernen Sie den WAF-Build-Status und löschen Sie ihn
Zeilen, wobei nur die nachverfolgten Daten übrig bleiben (Sie könnten die
TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop)); im Skript loszuwerden
der Tropfenabdrücke genauso einfach.
Sie können jetzt gnuplot ausführen (falls Sie es installiert haben) und ihm sagen, dass es etwas hübsches erzeugen soll
Bilder:
$gnuplot
gnuplot> Terminal-PNG-Größe 640,480 festlegen
gnuplot> Ausgabe "cwnd.png" setzen
gnuplot> Plotten Sie "cwnd.dat" mit dem 1:2-Titel "Congestion Window" mit Linienpunkten
gnuplot> beenden
Sie sollten jetzt ein Diagramm des Überlastungsfensters im Vergleich zur Zeit in der Datei haben
"cwnd.png" loading="lazy" das sieht so aus:
[Bild]
Die richtigen Mittlere Stufe Helpers
Im vorherigen Abschnitt haben wir gezeigt, wie man eine Ablaufverfolgungsquelle einklinkt und hoffnungsvoll erhält
interessante Informationen aus einer Simulation. Vielleicht erinnerst du dich, dass wir angerufen haben
Protokollierung zur Standardausgabe mit std :: cout ein "stumpfes Instrument" viel früher in diesem
Kapitel. Wir haben auch darüber geschrieben, dass es ein Problem war, die Protokollausgabe der Reihe nach zu parsen
interessante Informationen zu isolieren. Vielleicht ist Ihnen aufgefallen, dass wir gerade viel Geld ausgegeben haben
Zeit, ein Beispiel zu implementieren, das alle Probleme zeigt, die wir angeblich beheben wollen
NS-3 Rückverfolgungssystem! Du hättest recht. Aber ertrage es mit uns. Wir sind noch nicht fertig.
Eines der wichtigsten Dinge, die wir tun möchten, ist die Fähigkeit, es einfach zu machen
Steuern Sie die Ausgabemenge, die aus der Simulation kommt; und die wollen wir auch retten
Daten in eine Datei, damit wir später darauf zurückgreifen können. Wir können die Mid-Level-Trace-Helfer verwenden
bereitgestellt in NS-3 um genau das zu tun und das Bild zu vervollständigen.
Wir stellen ein Skript bereit, das die im Beispiel entwickelten cwnd change- und drop-Events schreibt
fünfte.cc in separaten Dateien auf die Festplatte. Die cwnd-Änderungen werden als tabulatorgetrenntes ASCII gespeichert
Datei und die Drop-Events werden in einer PCAP-Datei gespeichert. Die Änderungen, um dies zu ermöglichen, sind
ziemlich klein.
Exemplarische Vorgehensweise: sechste.cc
Werfen wir einen Blick auf die Änderungen, die erforderlich sind, um von zu gehen fünfte.cc zu sechste.cc. Öffnen
beispiele/tutorial/sechste.cc in Ihrem bevorzugten Editor. Sie können die erste Änderung von sehen
Suche nach CwndChange. Sie werden feststellen, dass wir die Signaturen für den Trace geändert haben
Senken und haben jeder Senke eine einzelne Zeile hinzugefügt, die die nachverfolgten Informationen in a schreibt
Stream, der eine Datei darstellt.
Statische Leere
CwndChange (Ptr Stream, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}
Statische Leere
RxDrop (Ptr Datei, Ptr p)
{
NS_LOG_UNCOND ("RxDrop bei " << Simulator::Now ().GetSeconds ());
file->Write(Simulator::Now(), p);
}
Wir haben einen „stream“-Parameter zum hinzugefügt CwndChange Spur sinken. Dies ist ein Objekt, das
hält (hält sicher am Leben) einen C++-Ausgabestrom. Es stellt sich heraus, dass dies sehr einfach ist
Objekt, sondern eines, das Lebensdauerprobleme für den Stream verwaltet und sogar ein Problem löst
erfahrene C++-Benutzer stoßen auf. Es stellt sich heraus, dass der Kopierkonstruktor für std::ostream
ist als privat gekennzeichnet. Dies bedeutet, dass std::ostreams gehorchen nicht der Wertsemantik und können es nicht
in jedem Mechanismus verwendet werden, der das Kopieren des Streams erfordert. Dazu gehört die NS-3
Callback-System, das, wie Sie sich vielleicht erinnern, Objekte erfordert, die der Wertesemantik gehorchen.
Beachten Sie außerdem, dass wir die folgende Zeile in hinzugefügt haben CwndChange Spur sinken
Implementierung:
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
Dies wäre ein sehr vertrauter Code, wenn Sie ihn ersetzen würden *stream->GetStream () mit std :: cout, wie
:
std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
Dies verdeutlicht, dass die Ptr ist wirklich nur herumtragen a
std::ofstream für Sie, und Sie können es hier wie jeden anderen Ausgabestrom verwenden.
Eine ähnliche Situation passiert in RxDrop außer dass das herumgereichte Objekt (a
Ptr) stellt eine PCAP-Datei dar. Es gibt einen Einzeiler in der Ablaufverfolgung zu versenken
Schreiben Sie einen Zeitstempel und den Inhalt des Pakets, das in die PCAP-Datei abgelegt wird:
file->Write(Simulator::Now(), p);
Wenn wir Objekte haben, die die beiden Dateien darstellen, müssen wir sie natürlich irgendwo erstellen
und auch bewirken, dass sie an die Trace-Senken weitergegeben werden. Schaut man in die Haupt- Funktion,
Sie werden neuen Code finden, um genau das zu tun:
AsciiTraceHelper AsciiTraceHelper;
Ptr stream = asciiTraceHelper.CreateFileStream ("sechste.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
...
PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("sechste.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, Datei));
Im ersten Abschnitt des obigen Code-Snippets erstellen wir die ASCII-Trace-Datei,
Erstellen eines Objekts, das für die Verwaltung verantwortlich ist, und Verwenden einer Variante des Callbacks
Erstellungsfunktion, um dafür zu sorgen, dass das Objekt an die Senke übergeben wird. Unser ASCII-Trace
Helfer bieten eine Vielzahl von Funktionen, um die Verwendung von Textdateien (ASCII) zu vereinfachen. Wir sind
Ich werde hier nur die Verwendung der Dateistream-Erstellungsfunktion veranschaulichen.
Die CreateFileStream Die Funktion wird im Grunde genommen a instanziieren std::ofstream Objekt und
Erstellen Sie eine neue Datei (oder kürzen Sie eine vorhandene Datei). Das std::ofstream ist verpackt in einem
NS-3 Objekt für die Verwaltung der Lebensdauer und die Lösung von Problemen mit dem Kopierkonstrukteur.
Das nehmen wir dann NS-3 Objekt, das die Datei darstellt, und übergeben Sie es an MakeBoundCallback().
Diese Funktion erstellt einen Callback wie MakeCallback(), aber es "bindet" einen neuen Wert an
der Rückruf. Dieser Wert wird dem Rückruf als erstes Argument vor ihm hinzugefügt
namens.
Grundsätzlich MakeBoundCallback(&CwndChange, Strom) bewirkt, dass die Ablaufverfolgungsquelle die hinzufügt
zusätzlicher "stream"-Parameter am Anfang der formalen Parameterliste vor dem Aufruf
der Rückruf. Dadurch ändert sich die erforderliche Signatur der CwndChange sinken, um dem einen zu entsprechen
oben gezeigt, der den "extra"-Parameter enthält Ptr Strom.
Im zweiten Codeabschnitt im obigen Snippet instanziieren wir a PcapHelper um das zu tun
Das Gleiche gilt für unsere PCAP-Trace-Datei, die wir mit der gemacht haben AsciiTraceHelper. Die Linie von
Code,
Ptr file = pcapHelper.CreateFile ("sechste.pcap",
"w", PcapHelper::DLT_PPP);
erstellt eine PCAP-Datei namens "sixth.pcap" mit dem Dateimodus "w". Das bedeutet, dass die neue Datei
wird abgeschnitten (Inhalt gelöscht), wenn eine vorhandene Datei mit diesem Namen gefunden wird. Das endgültige
Parameter ist der "Datenverbindungstyp" der neuen PCAP-Datei. Diese sind die gleichen wie die PCAP
Bibliotheksdatenverknüpfungstypen definiert in bpf.h wenn Sie mit PCAP vertraut sind. In diesem Fall,
DLT_PPP gibt an, dass die PCAP-Datei Pakete mit dem Präfix point to enthalten wird
Punktüberschriften. Dies gilt, da die Pakete von unserem Punkt-zu-Punkt-Gerät kommen
Treiber. Andere gängige Datenverbindungstypen sind DLT_EN10MB (10 MB Ethernet), geeignet für csma
Geräte und DLT_IEEE802_11 (IEEE 802.11) geeignet für WLAN-Geräte. Diese sind definiert
in src/network/helper/trace-helper.h wenn Sie daran interessiert sind, die Liste zu sehen. Das
Einträge in der Liste stimmen mit denen in überein bpf.h aber wir duplizieren sie, um eine PCAP-Quelle zu vermeiden
Abhängigkeit.
A NS-3 Objekt, das die PCAP-Datei darstellt, wird zurückgegeben CreateFile und in einem gebunden verwendet
Rückruf genau so, wie es im ASCII-Fall war.
Ein wichtiger Umweg: Es ist wichtig zu beachten, dass diese beiden Objekte zwar vorhanden sind
ganz ähnlich deklariert,
Ptr Datei ...
Ptr streamen ...
Die zugrunde liegenden Objekte sind völlig unterschiedlich. Zum Beispiel die Ptr ist eine
intelligenter Zeiger auf ein NS-3 Objekt, das eine ziemlich schwere Sache ist, die unterstützt
Attributes und ist in das Config-System integriert. Das Ptr, Auf die
Andererseits ist es ein intelligenter Zeiger auf ein referenzgezähltes Objekt, das sehr leicht ist
Sache. Denken Sie daran, sich das Objekt anzusehen, auf das Sie sich beziehen, bevor Sie Annahmen treffen
über die "Kräfte", die dieses Objekt haben kann.
Schauen Sie sich zum Beispiel an src/network/utils/pcap-file-wrapper.h im Vertrieb u
Notiz,
Klasse PcapFileWrapper : öffentliches Objekt
diese Klasse PcapFileWrapper ist ein NS-3 Objekt aufgrund seiner Vererbung. Dann schau mal
src/network/model/output-stream-wrapper.h und beachte,
Klasse OutputStreamWrapper : öffentlich
SimpleRefCount
dass dieses Objekt kein ist NS-3 Objekt überhaupt, es ist "nur" ein C++-Objekt, das passiert
Unterstützung der aufdringlichen Referenzzählung.
Der Punkt hier ist, dass nur weil Sie lesen Ptr es bedeutet nicht unbedingt
zur Verbesserung der Gesundheitsgerechtigkeit etwas ist ein NS-3 Objekt, an dem Sie sich aufhängen können NS-3 Attribute zum Beispiel.
Nun zurück zum Beispiel. Wenn Sie dieses Beispiel erstellen und ausführen,
$ ./waf --Run sechster
Sie werden die gleichen Meldungen sehen wie beim Ausführen von "fifth", aber zwei neue Dateien werden erscheinen
erscheinen im obersten Verzeichnis Ihrer NS-3 Verteilung.
sechste.cwnd sechste.pcap
Da "sixth.cwnd" eine ASCII-Textdatei ist, können Sie sie mit anzeigen Katze oder Ihre Lieblingsdatei
Zuschauer.
1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144
...
9.69256 5149 5204
9.89311 5204 5259
Sie haben eine tabulatorgetrennte Datei mit einem Zeitstempel, einem alten Staufenster und einem neuen
Staufenster geeignet zum direkten Import in Ihr Plotprogramm. Es gibt keine
Fremde Drucke in der Datei, es ist kein Parsen oder Bearbeiten erforderlich.
Da es sich bei "sixth.pcap" um eine PCAP-Datei handelt, können Sie diese mit ansehen tcpdump.
Lesen aus der Datei sixt.pcap, Linktyp PPP (PPP)
1.136956 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 17177:17681, ack 1, win 32768, Optionen [TS val 1133 ecr 1127,eol], Länge 504
1.403196 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 33280:33784, ack 1, win 32768, Optionen [TS val 1399 ecr 1394,eol], Länge 504
...
7.426220 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 785704:786240, ack 1, win 32768, Optionen [TS val 7423 ecr 7421,eol], Länge 536
9.630693 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 882688:883224, ack 1, win 32768, Optionen [TS val 9620 ecr 9618,eol], Länge 536
Sie haben eine PCAP-Datei mit den Paketen, die in der Simulation verworfen wurden. Es gibt keine
andere Pakete, die in der Datei vorhanden sind, und es ist nichts anderes vorhanden, um Leben zu machen
schwer.
Es war ein langer Weg, aber jetzt sind wir an einem Punkt angelangt, an dem wir das schätzen können NS-3
Rückverfolgungssystem. Wir haben wichtige Ereignisse aus der Mitte einer TCP-Implementierung herausgezogen
und einen Gerätetreiber. Wir haben diese Ereignisse direkt in Dateien gespeichert, die mit allgemein bekannten verwendet werden können
Werkzeug. Wir haben dies getan, ohne den beteiligten Kerncode zu ändern, und wir haben dies in
nur 18 Zeilen Code:
Statische Leere
CwndChange (Ptr Stream, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}
...
AsciiTraceHelper AsciiTraceHelper;
Ptr stream = asciiTraceHelper.CreateFileStream ("sechste.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));
...
Statische Leere
RxDrop (Ptr Datei, Ptr p)
{
NS_LOG_UNCOND ("RxDrop bei " << Simulator::Now ().GetSeconds ());
file->Write(Simulator::Now(), p);
}
...
PcapHelper pcapHelper;
Ptr file = pcapHelper.CreateFile ("sechste.pcap", "w", PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, Datei));
Spur Helpers
Die NS-3 Trace-Helfer bieten eine reichhaltige Umgebung zum Konfigurieren und Auswählen verschiedener
verfolgen Ereignisse und schreiben sie in Dateien. In den vorherigen Abschnitten hauptsächlich
BuildingTopologies haben wir mehrere Varianten der Trace-Helfermethoden gesehen, die entwickelt wurden
zur Verwendung in anderen (Geräte-)Helfern.
Vielleicht erinnern Sie sich noch daran, einige dieser Variationen gesehen zu haben:
pointToPoint.EnablePcapAll ("zweite");
pointToPoint.EnablePcap ("zweite", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("dritte", csmaDevices.Get (0), true);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
Was jedoch möglicherweise nicht offensichtlich ist, ist, dass es ein konsistentes Modell für alle
im System gefundene spurenbezogene Methoden. Wir werden uns jetzt ein wenig Zeit nehmen und schauen
beim "großen Bild".
Derzeit gibt es zwei Hauptanwendungsfälle der Tracing-Helfer in NS-3: Gerätehelfer
und Protokollhelfer. Gerätehelfer befassen sich mit dem Problem, welche Traces anzugeben sind
sollte über ein Paar (Knoten, Gerät) aktiviert werden. Beispielsweise möchten Sie möglicherweise angeben
dass die PCAP-Ablaufverfolgung auf einem bestimmten Gerät auf einem bestimmten Knoten aktiviert werden sollte. Das
folgt aus dem NS-3 konzeptionelles Modell des Geräts und auch die konzeptionellen Modelle der
diverse Gerätehelfer. Daraus folgen natürlich die erstellten Dateien a
- - Namenskonvention.
Protokollhelfer betrachten das Problem der Angabe, welche Traces aktiviert werden sollen
ein Protokoll- und Schnittstellenpaar. Dies folgt aus dem NS-3 Protokollstapel konzeptionell
-Modell und auch die konzeptionellen Modelle von Internet-Stack-Helfern. Natürlich die Spur
Dateien sollten a folgen - - Namenskonvention.
Die Spurenhelfer fallen daher natürlich in eine zweidimensionale Taxonomie. Es gibt
Feinheiten, die verhindern, dass sich alle vier Klassen identisch verhalten, aber wir bemühen uns,
dafür sorgen, dass sie alle so ähnlich wie möglich funktionieren; und wann immer möglich gibt es Analoga für
alle Methoden in allen Klassen.
┌────────────────┬──────┬───────┐
│ │ PCAP │ ASCII │
└────────────────────────────── ┘.
│Geräte-Helfer │ │ │
├────────────────────────────── ┤.
│Protokoll-Helfer │ │ │
└────────────────────────────── ┘.
Wir verwenden einen Ansatz namens a mixin um unseren Hilfsklassen Tracing-Funktionalität hinzuzufügen. EIN
mixin ist eine Klasse, die Funktionalität bereitstellt, wenn sie von einer Unterklasse geerbt wird.
Von einem Mixin zu erben wird nicht als eine Form der Spezialisierung angesehen, sondern ist wirklich eine Möglichkeit,
Funktionalität sammeln.
Werfen wir einen kurzen Blick auf alle vier dieser Fälle und ihre jeweiligen Mixins.
Gerät Helpers
PCAP
Das Ziel dieser Helfer ist es, das Hinzufügen einer konsistenten PCAP-Trace-Funktion zu einem zu vereinfachen
NS-3 Gerät. Wir möchten, dass alle verschiedenen Varianten der PCAP-Ablaufverfolgung überall gleich funktionieren
alle Geräte, so dass die Methoden dieser Helfer von Gerätehelfern geerbt werden. Schau mal
at src/network/helper/trace-helper.h wenn du der Diskussion beim Anschauen folgen möchtest
echter Code.
Die Klasse PcapHelperForDevice ist eine mixin bietet die High-Level-Funktionalität für die Verwendung
PCAP-Ablaufverfolgung in einem NS-3 Gerät. Jedes Gerät muss eine einzelne virtuelle Methode implementieren
von dieser Klasse geerbt.
virtual void EnablePcapInternal (std::string prefix, Ptr nd, bool promiskuitiv, bool expliziter Dateiname) = 0;
Die Signatur dieser Methode spiegelt die gerätezentrierte Sicht der Situation wider
eben. Alle öffentlichen Methoden, die von der Klasse geerbt wurden PcapUserHelperForDevice reduzieren
Aufruf dieser einzelnen geräteabhängigen Implementierungsmethode. Zum Beispiel die niedrigste Ebene
PCAP-Verfahren,
void EnablePcap (std::string Präfix, Ptr nd, bool promiscuous = false, bool explizitFilename = false);
ruft die Geräteimplementierung von . auf Aktivieren Sie PcapInternal direkt. Alle anderen öffentlichen PCAP
Tracing-Methoden bauen auf dieser Implementierung auf, um zusätzliche Benutzerebenen bereitzustellen
Funktionalität. Für den Benutzer bedeutet dies, dass alle Gerätehelfer im System
alle PCAP-Trace-Methoden verfügbar haben; und diese Methoden funktionieren alle gleich
geräteübergreifend, wenn das Gerät implementiert Aktivieren Sie PcapInternal korrekt.
Methoden
void EnablePcap (std::string Präfix, Ptr nd, bool promiscuous = false, bool explizitFilename = false);
void EnablePcap (std::string Präfix, std::string ndName, bool promiscuous = false, bool explizitFilename = false);
void EnablePcap (std::string prefix, NetDeviceContainer d, bool promiscuous = false);
void EnablePcap (std::string prefix, NodeContainer n, bool promiscuous = false);
void EnablePcap (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
void EnablePcapAll (std::string Präfix, bool promiscuous = false);
In jeder der oben gezeigten Methoden gibt es einen Standardparameter namens promiskuitiv zur Verbesserung der Gesundheitsgerechtigkeit
Standardmäßig ist falsch. Dieser Parameter gibt an, dass die Ablaufverfolgung nicht erfasst werden soll
promiskuitiver Modus. Wenn Sie möchten, dass Ihre Spuren den gesamten Datenverkehr des Geräts umfassen
(und wenn das Gerät einen Promiscuous-Modus unterstützt) fügen Sie einfach einen wahren Parameter zu einem der hinzu
Anrufe oben. Zum Beispiel,
Ptr nd;
...
helper.EnablePcap ("Präfix", nd, true);
aktiviert Promiscuous-Modus-Captures auf dem NetDevice spezifiziert durch nd.
Die ersten beiden Methoden enthalten auch einen Standardparameter namens explizitDateiname das wird
unten besprochen werden.
Sie werden ermutigt, die API-Dokumentation für den Unterricht zu lesen PcapHelperForDevice zu finden
die Einzelheiten dieser Methoden; aber zusammenfassend...
· Sie können PCAP-Tracing auf einem bestimmten Knoten/Netzgerät-Paar aktivieren, indem Sie a angeben
Ptr ein Aktivieren Sie Pcap Methode. Das Ptr ist implizit, da das Netzgerät
muss zu genau einem Knoten gehören. Zum Beispiel,
Ptr nd;
...
helper.EnablePcap ("Präfix", nd);
· Sie können PCAP-Tracing auf einem bestimmten Knoten/Netzgerät-Paar aktivieren, indem Sie a angeben
std::string einen Objektnamen-Service-String für einen . darstellen Aktivieren Sie Pcap Methode. Das
Ptr wird aus der Namenszeichenfolge nachgeschlagen. Wieder die ist implizit, da
Das benannte Netzgerät muss zu genau einem Knoten gehören. Zum Beispiel,
Namen::Hinzufügen ("Server" ...);
Namen::Add ("server/eth0" ...);
...
helper.EnablePcap ("Präfix", "server/ath0");
· Sie können die PCAP-Ablaufverfolgung für eine Sammlung von Knoten/Netzgerät-Paaren aktivieren, indem Sie a angeben
NetDeviceContainer. Für jedes NetDevice im Container wird der Typ geprüft. Für jede
Gerät des richtigen Typs (derselbe Typ, der vom Gerätehelfer verwaltet wird), die Ablaufverfolgung ist
aktiviert. Wieder die ist implizit, da das gefundene Netzgerät dazugehören muss
genau ein Knoten. Zum Beispiel,
NetDeviceContainer d = ...;
...
helper.EnablePcap ("Präfix", d);
· Sie können die PCAP-Ablaufverfolgung für eine Sammlung von Knoten/Netzgerät-Paaren aktivieren, indem Sie a angeben
NodeContainer. Für jeden Knoten in der NodeContainer es ist beigefügt NetGeräte werden iteriert.
Für jeden NetDevice an jeden Knoten im Container angehängt ist, ist der Typ dieses Geräts
überprüft. Für jedes Gerät des richtigen Typs (derselbe Typ, der von dem Gerät verwaltet wird
Helfer), die Ablaufverfolgung ist aktiviert.
NodeContainer n;
...
helper.EnablePcap ("Präfix", n);
· Sie können PCAP-Tracing auf Basis von Node-ID und Geräte-ID sowie mit aktivieren
explizit ptr. Jeder Knoten im System hat eine ganzzahlige Knoten-ID und jedes angeschlossene Gerät
zu einem Knoten hat eine ganzzahlige Geräte-ID.
helper.EnablePcap ("Präfix", 21, 1);
· Schließlich können Sie die PCAP-Ablaufverfolgung für alle Geräte im System mit demselben Typ aktivieren
wie die vom Gerätehelfer verwaltete.
helper.EnablePcapAll ("Präfix");
Dateinamen
Implizit in den obigen Methodenbeschreibungen ist die Konstruktion eines vollständigen Dateinamens durch
die Umsetzungsmethode. Konventionsgemäß sind PCAP-Spuren in der NS-3 System sind von der Form
- id>- id>.pcap
Wie bereits erwähnt, hat jeder Knoten im System eine vom System zugewiesene Knoten-ID; und
Jedes Gerät hat einen Schnittstellenindex (auch als Geräte-ID bezeichnet) relativ zu seinem Knoten.
Standardmäßig wird also eine PCAP-Ablaufverfolgungsdatei erstellt, wenn die Ablaufverfolgung auf der ersten aktiviert wird
Device von Node 21 mit dem Präfix „prefix“ wäre Präfix-21-1.pcap.
Sie können immer die verwenden NS-3 Object Name Service, um dies deutlicher zu machen. Zum Beispiel, wenn
Sie verwenden den Objektnamendienst, um dem Knoten 21, dem resultierenden PCAP, den Namen "Server" zuzuweisen
Trace-Dateiname wird automatisch, Präfix-Server-1.pcap und wenn Sie auch die zuweisen
Name "eth0" an das Gerät, Ihr PCAP-Dateiname wird automatisch abgeholt und sein
namens Präfix-server-eth0.pcap.
Schließlich zwei der oben gezeigten Methoden,
void EnablePcap (std::string Präfix, Ptr nd, bool promiscuous = false, bool explizitFilename = false);
void EnablePcap (std::string Präfix, std::string ndName, bool promiscuous = false, bool explizitFilename = false);
haben einen Standardparameter namens explizitDateiname. Wenn dieser Parameter auf "true" gesetzt ist,
deaktiviert den Mechanismus zur automatischen Vervollständigung von Dateinamen und ermöglicht Ihnen, eine explizite Datei zu erstellen
Dateinamen. Diese Option ist nur in den Methoden verfügbar, die die PCAP-Ablaufverfolgung auf a aktivieren
einzelnes Gerät.
Zum Beispiel, um zu veranlassen, dass ein Gerätehelfer ein einzelnes promiskuitives PCAP erstellt
Capture-Datei mit einem bestimmten Namen meine-pcap-datei.pcap Auf einem bestimmten Gerät könnte man:
Ptr nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);
Der Erste was immer dies auch sein sollte. Parameter aktiviert Promiscuous Mode Traces und der zweite sagt dem Helfer
die zu interpretieren Präfix Parameter als vollständiger Dateiname.
ASCII
Das Verhalten des ASCII-Trace-Helfers mixin ist der PCAP-Version im Wesentlichen ähnlich.
Wirf einen Blick auf src/network/helper/trace-helper.h wenn du die diskussion verfolgen willst
beim Betrachten von echtem Code.
Die Klasse AsciiTraceHelperForDevice fügt die High-Level-Funktionalität für die Verwendung von ASCII hinzu
Ablaufverfolgung zu einer Gerätehilfsklasse. Wie im PCAP-Fall muss jedes Gerät a implementieren
einzelne virtuelle Methode, die von der ASCII-Ablaufverfolgung geerbt wird mixin.
virtual void EnableAsciiInternal (Ptr Strom,
std::string-Präfix,
Ptr und,
bool expliziter Dateiname) = 0;
Die Signatur dieser Methode spiegelt die gerätezentrierte Sicht der Situation wider
eben; und auch die Tatsache, dass der Helfer möglicherweise in einen gemeinsam genutzten Ausgabestrom schreibt. Alle
die öffentlichen ASCII-Trace-bezogenen Methoden, die von der Klasse geerbt wurden AsciiTraceHelperForDevice
auf den Aufruf dieser einzelnen geräteabhängigen Implementierungsmethode reduzieren. Zum Beispiel die
ASCII-Trace-Methoden der niedrigsten Ebene,
void EnableAscii (std::string-Präfix, Ptr nd, bool expliziter Dateiname = false);
void EnableAscii (Ptr Strom, Ptr nd);
ruft die Geräteimplementierung von . auf AsciiInternal aktivieren direkt, entweder a
gültiges Präfix oder Stream. Alle anderen öffentlichen ASCII-Tracing-Methoden bauen darauf auf
Low-Level-Funktionen, um zusätzliche Funktionen auf Benutzerebene bereitzustellen. Was das bedeutet
der Benutzer ist, dass alle Gerätehelfer im System über alle ASCII-Trace-Methoden verfügen
erhältlich; und diese Methoden funktionieren auf allen Geräten gleich, wenn die Geräte
implementieren EnableAsciiInternal korrekt.
Methoden
void EnableAscii (std::string-Präfix, Ptr nd, bool expliziter Dateiname = false);
void EnableAscii (Ptr Strom, Ptr nd);
void EnableAscii (std::string prefix, std::string ndName, bool explizitFilename = false);
void EnableAscii (Ptr stream, std::string ndName);
void EnableAscii (std::string prefix, NetDeviceContainer d);
void EnableAscii (Ptr Stream, NetDeviceContainer d);
void EnableAscii (std::string Präfix, NodeContainer n);
void EnableAscii (Ptr stream, NodeContainer n);
void EnableAsciiAll (std::string-Präfix);
void EnableAsciiAll (Ptr Strom);
void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explizitFilename);
void EnableAscii (Ptr stream, uint32_t Knoten-ID, uint32_t Geräte-ID);
Sie werden ermutigt, die API-Dokumentation für den Unterricht zu lesen AsciiTraceHelperForDevice zu
finden Sie die Details dieser Methoden; aber zusammenfassend...
· Für ASCII-Tracing stehen doppelt so viele Methoden zur Verfügung wie für PCAP
Verfolgung. Dies liegt daran, dass neben dem PCAP-Modell auch Spuren von jedem vorhanden sind
eindeutige Knoten-/Gerätepaare in eine eindeutige Datei geschrieben werden, unterstützen wir ein Modell, in dem Trace
Informationen für viele Knoten/Geräte-Paare werden in eine gemeinsame Datei geschrieben. Dies bedeutet, dass die
- - Der Mechanismus zur Generierung von Dateinamen wird durch einen Mechanismus ersetzt, um
auf eine gemeinsame Datei verweisen; und die Anzahl der API-Methoden wird verdoppelt, um alle zu ermöglichen
Kombinationen.
· Genau wie beim PCAP-Tracing können Sie das ASCII-Tracing auf einem bestimmten (Knoten, Netzgerät) aktivieren.
paaren Sie, indem Sie a . angeben Ptr ein Ascii aktivieren Methode. Das Ptr ist implizit
da das Netzgerät zu genau einem Knoten gehören muss. Zum Beispiel,
Ptr nd;
...
helper.EnableAscii ("Präfix", nd);
· Die ersten vier Methoden enthalten auch einen Standardparameter namens explizitDateiname zur Verbesserung der Gesundheitsgerechtigkeit
arbeiten ähnlich wie äquivalente Parameter im PCAP-Fall.
In diesem Fall werden keine Trace-Kontexte in die ASCII-Trace-Datei geschrieben, da dies der Fall wäre
redundant. Das System wählt den zu erstellenden Dateinamen nach den gleichen Regeln wie
beschrieben im PCAP-Abschnitt, außer dass die Datei das Suffix hat .tr statt
.pcap.
· Wenn Sie die ASCII-Ablaufverfolgung auf mehr als einem Netzgerät aktivieren und alle Ablaufverfolgungen senden lassen möchten
auf eine einzelne Datei, können Sie dies auch tun, indem Sie ein Objekt verwenden, um auf eine einzelne Datei zu verweisen.
Wir haben dies bereits im obigen „cwnd“-Beispiel gesehen:
Ptr nd1;
Ptr nd2;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAscii (Stream, nd1);
helper.EnableAscii (Stream, nd2);
Verfolgen Sie in diesem Fall Kontexte sind in die ASCII-Trace-Datei geschrieben, da sie benötigt werden
um Spuren von den beiden Geräten zu eindeutig zu machen. Beachten Sie, dass der Benutzer vollständig ist
Bei Angabe des Dateinamens sollte die Zeichenfolge die enthalten , tr Suffix für Konsistenz.
· Sie können die ASCII-Ablaufverfolgung für ein bestimmtes Paar (Knoten, Netzgerät) aktivieren, indem Sie a angeben
std::string einen Objektnamen-Service-String für einen . darstellen Aktivieren Sie Pcap Methode. Das
Ptr wird aus der Namenszeichenfolge nachgeschlagen. Wieder die ist implizit, da
Das benannte Netzgerät muss zu genau einem Knoten gehören. Zum Beispiel,
Namen::Hinzufügen ("Client" ...);
Namen::Add ("client/eth0" ...);
Namen::Hinzufügen ("Server" ...);
Namen::Add ("server/eth0" ...);
...
helper.EnableAscii ("Präfix", "client/eth0");
helper.EnableAscii ("Präfix", "server/eth0");
Dies würde zu zwei Dateien mit den Namen „prefix-client-eth0.tr“ und „
``prefix-server-eth0.tr`` mit Ablaufverfolgungen für jedes Gerät in der
jeweilige Trace-Datei. Da alle ``EnableAscii``-Funktionen
überlastet sind, um einen Stream-Wrapper zu nehmen, können Sie dieses Formular als verwenden
Gut::
Namen::Hinzufügen ("Client" ...);
Namen::Add ("client/eth0" ...);
Namen::Hinzufügen ("Server" ...);
Namen::Add ("server/eth0" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAscii (Stream, „client/eth0“);
helper.EnableAscii (stream, "server/eth0");
Dies würde zu einer einzelnen Trace-Datei namens . führen Trace-Dateiname.tr das alles enthält
die Trace-Ereignisse für beide Geräte. Die Ereignisse würden durch den Trace-Kontext eindeutig gemacht
Saiten.
· Sie können die ASCII-Ablaufverfolgung für eine Sammlung von Paaren (Knoten, Netzgerät) aktivieren, indem Sie a angeben
NetDeviceContainer. Für jedes NetDevice im Container wird der Typ geprüft. Für jede
Gerät des richtigen Typs (derselbe Typ, der vom Gerätehelfer verwaltet wird), die Ablaufverfolgung ist
aktiviert. Wieder die ist implizit, da das gefundene Netzgerät dazugehören muss
genau ein Knoten. Zum Beispiel,
NetDeviceContainer d = ...;
...
helper.EnableAscii ("Präfix", d);
Dies würde dazu führen, dass eine Reihe von ASCII-Trace-Dateien erstellt werden,
die jeweils auf das `` folgen - - .tr``
Konvention.
Das Kombinieren aller Spuren in einer einzigen Datei wird ähnlich wie in den Beispielen durchgeführt
über:
NetDeviceContainer d = ...;
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAscii (Stream, d);
· Sie können die ASCII-Ablaufverfolgung für eine Sammlung von Paaren (Knoten, Netzgerät) aktivieren, indem Sie a angeben
NodeContainer. Für jeden Knoten in der NodeContainer es ist beigefügt NetGeräte werden iteriert.
Für jeden NetDevice an jeden Knoten im Container angehängt ist, ist der Typ dieses Geräts
überprüft. Für jedes Gerät des richtigen Typs (derselbe Typ, der von dem Gerät verwaltet wird
Helfer), die Ablaufverfolgung ist aktiviert.
NodeContainer n;
...
helper.EnableAscii ("Präfix", n);
Dies würde dazu führen, dass eine Reihe von ASCII-Trace-Dateien erstellt werden, von denen jede folgt
- id>- id>.tr Konvention. Kombinieren aller Spuren zu a
einzelne Datei wird ähnlich wie in den obigen Beispielen ausgeführt.
· Sie können PCAP-Tracing auf Basis von Node-ID und Geräte-ID sowie mit aktivieren
explizit ptr. Jeder Knoten im System hat eine ganzzahlige Knoten-ID und jedes angeschlossene Gerät
zu einem Knoten hat eine ganzzahlige Geräte-ID.
helper.EnableAscii ("Präfix", 21, 1);
Natürlich können die Spuren wie oben gezeigt in einer einzigen Datei kombiniert werden.
· Schließlich können Sie die PCAP-Ablaufverfolgung für alle Geräte im System mit demselben Typ aktivieren
wie die vom Gerätehelfer verwaltete.
helper.EnableAsciiAll ("Präfix");
Dies würde dazu führen, dass mehrere ASCII-Trace-Dateien erstellt werden, eine für jedes Gerät
im System des vom Helfer verwalteten Typs. Alle diese Dateien folgen der
- id>- id>.tr Konvention. Kombinieren aller Spuren zu einer einzigen
Datei wird ähnlich wie in den obigen Beispielen durchgeführt.
Dateinamen
Implizit in den obigen Methodenbeschreibungen im Präfixstil ist die Konstruktion des vollständigen
Dateinamen nach der Implementierungsmethode. Konventionsgemäß werden ASCII-Spuren in der NS-3 System
sind von der Form - id>- id>.tr
Wie bereits erwähnt, hat jeder Knoten im System eine vom System zugewiesene Knoten-ID; und
Jedes Gerät hat einen Schnittstellenindex (auch als Geräte-ID bezeichnet) relativ zu seinem Knoten.
Standardmäßig wird also eine ASCII-Ablaufverfolgungsdatei erstellt, wenn die Ablaufverfolgung auf der ersten aktiviert wird
Gerät von Node 21 unter Verwendung des Präfixes "prefix" wäre Präfix-21-1.tr.
Sie können immer die verwenden NS-3 Object Name Service, um dies deutlicher zu machen. Zum Beispiel, wenn
Sie verwenden den Objektnamensdienst, um dem Knoten 21 den Namen "Server" zuzuweisen, der resultierende
Der Name der ASCII-Trace-Datei wird automatisch zu Präfix-Server-1.tr und wenn du auch zuweist
Geben Sie dem Gerät den Namen "eth0" ein, der Name Ihrer ASCII-Trace-Datei wird automatisch übernommen
und gerufen werden Präfix-Server-eth0.tr.
Einige der Methoden haben einen Standardparameter namens explizitDateiname. Bei Einstellung auf
true, deaktiviert dieser Parameter den automatischen Dateinamen-Vervollständigungsmechanismus und lässt Sie zu
um einen eindeutigen Dateinamen zu erstellen. Diese Option ist nur in den Methoden verfügbar, die a annehmen
Präfix und aktivieren Sie die Ablaufverfolgung auf einem einzigen Gerät.
Protokoll Helpers
PCAP
Das Ziel dieser Mixins soll es einfach machen, eine konsistente PCAP-Trace-Funktion hinzuzufügen
Protokolle. Wir möchten, dass alle verschiedenen Varianten der PCAP-Ablaufverfolgung überall gleich funktionieren
Protokolle, so dass die Methoden dieser Helfer von Stapelhelfern geerbt werden. Schau es dir an
src/network/helper/trace-helper.h wenn du der Diskussion beim Anschauen folgen möchtest
echter Code.
In diesem Abschnitt werden wir die Methoden veranschaulichen, die auf das Protokoll angewendet werden Ipv4. Nach
Traces in ähnlichen Protokollen spezifizieren, ersetzen Sie einfach den entsprechenden Typ. Beispielsweise,
benutze einen Ptr statt a Ptr und Ruf an PcapIpv6 aktivieren statt PcapIpv4 aktivieren.
Die Klasse PcapHelperForIpv4 bietet die High-Level-Funktionalität für die Verwendung von PCAP-Tracing
begann Ipv4 Protokoll. Jeder Protokoll-Helper, der diese Methoden aktiviert, muss ein einzelnes
virtuelle Methode, die von dieser Klasse geerbt wurde. Es wird eine separate Implementierung für . geben
Ipv6, aber der einzige Unterschied besteht in den Methodennamen und Signaturen.
Zur Eindeutigkeit der Klasse sind unterschiedliche Methodennamen erforderlich Ipv4 für Ipv6 welche sind beide
von Klasse abgeleitet Betreff, und Methoden, die dieselbe Signatur verwenden.
virtual void EnablePcapIpv4Internal (std::string-Präfix,
Ptr ipv4,
uint32_t-Schnittstelle,
bool expliziter Dateiname) = 0;
Die Signatur dieser Methode spiegelt die protokoll- und schnittstellenzentrierte Sicht der
Situation auf dieser Ebene. Alle öffentlichen Methoden, die von der Klasse geerbt wurden PcapHelperForIpv4
auf den Aufruf dieser einzelnen geräteabhängigen Implementierungsmethode reduzieren. Zum Beispiel die
PCAP-Methode der niedrigsten Stufe,
void EnablePcapIpv4 (std::string-Präfix, Ptr ipv4, uint4_t-Schnittstelle, bool expliziter Dateiname = false);
ruft die Geräteimplementierung von . auf Aktivieren Sie PcapIpv4Internal direkt. Alle anderen öffentlichen
PCAP-Ablaufverfolgungsmethoden bauen auf dieser Implementierung auf, um eine zusätzliche Benutzerebene bereitzustellen
Funktionalität. Für den Benutzer bedeutet dies, dass alle Protokollhelfer im System
wird alle PCAP-Trace-Methoden zur Verfügung haben; und diese Methoden funktionieren alle in der
auf die gleiche Weise über Protokolle hinweg, wenn der Helfer implementiert Aktivieren Sie PcapIpv4Internal korrekt.
Methoden
Diese Methoden sind so konzipiert, dass sie in Eins-zu-Eins-Entsprechung mit dem Node- und stehen
NetDevice- zentrische Versionen der Geräteversionen. Anstelle von Knoten und NetDevice Paar
Beschränkungen verwenden wir Protokoll- und Schnittstellenbeschränkungen.
Beachten Sie, dass es wie in der Geräteversion sechs Methoden gibt:
void EnablePcapIpv4 (std::string-Präfix, Ptr ipv4, uint4_t-Schnittstelle, bool expliziter Dateiname = false);
void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explizitFilename = false);
void EnablePcapIpv4 (std::string prefix, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std::string-Präfix, NodeContainer n);
void EnablePcapIpv4 (std::string-Präfix, uint32_t-Knoten-ID, uint32_t-Schnittstelle, bool expliziter Dateiname);
void EnablePcapIpv4All (std::string-Präfix);
Sie werden ermutigt, die API-Dokumentation für den Unterricht zu lesen PcapHelperForIpv4 zu finden, die
Einzelheiten zu diesen Methoden; aber zusammenfassend...
· Sie können die PCAP-Ablaufverfolgung für ein bestimmtes Protokoll/Schnittstellenpaar aktivieren, indem Sie a angeben
Ptr und Schnittstelle ein Aktivieren Sie Pcap Methode. Zum Beispiel,
Ptr IPv4 = Knoten->GetObject ();
...
helper.EnablePcapIpv4 ("Präfix", IPv4, 0);
· Sie können PCAP-Tracing auf einem bestimmten Knoten/Netzgerät-Paar aktivieren, indem Sie a angeben
std::string einen Objektnamen-Service-String für einen . darstellen Aktivieren Sie Pcap Methode. Das
Ptr wird aus der Namenszeichenfolge nachgeschlagen. Zum Beispiel,
Namen::Hinzufügen ("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("Präfix", "serverIpv4", 1);
· Sie können die PCAP-Ablaufverfolgung für eine Sammlung von Protokoll-/Schnittstellenpaaren aktivieren, indem Sie eine angeben
IPv4InterfaceContainer. Für jedes Ipv4 / Schnittstellenpaar im Container das Protokoll
Typ wird überprüft. Für jedes Protokoll des richtigen Typs (derselbe Typ, der verwaltet wird von
der Gerätehelfer), ist die Ablaufverfolgung für die entsprechende Schnittstelle aktiviert. Zum Beispiel,
NodeContainer-Knoten;
...
NetDeviceContainer-Geräte = deviceHelper.Install (Knoten);
...
IPv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer-Schnittstellen = ipv4.Assign (Geräte);
...
helper.EnablePcapIpv4 ("Präfix", Schnittstellen);
· Sie können die PCAP-Ablaufverfolgung für eine Sammlung von Protokoll-/Schnittstellenpaaren aktivieren, indem Sie a angeben
NodeContainer. Für jeden Knoten in der NodeContainer das passende Protokoll gefunden wird.
Für jedes Protokoll werden seine Schnittstellen aufgezählt und die Ablaufverfolgung für das Ergebnis aktiviert
Paare. Zum Beispiel,
NodeContainer n;
...
helper.EnablePcapIpv4 ("Präfix", n);
· Sie können das PCAP-Tracing auch auf Basis von Node-ID und Schnittstelle aktivieren. In diesem
Fall wird die Knoten-ID in a übersetzt Ptr und das entsprechende Protokoll wird nachgeschlagen
im Knoten. Das resultierende Protokoll und die Schnittstelle werden verwendet, um das Ergebnis zu spezifizieren
Spurenquelle.
helper.EnablePcapIpv4 ("Präfix", 21, 1);
· Schließlich können Sie die PCAP-Ablaufverfolgung für alle Schnittstellen im System aktivieren, einschließlich zugehöriger
wobei das Protokoll vom gleichen Typ ist wie das vom Device Helper verwaltete.
helper.EnablePcapIpv4All ("Präfix");
Dateinamen
Implizit in allen obigen Methodenbeschreibungen ist die Konstruktion des vollständigen
Dateinamen nach der Implementierungsmethode. Per Konvention werden PCAP-Traces für Geräte in
NS-3 System haben die Form " - - .pcap". Im Fall von
Protokollspuren gibt es eine Eins-zu-eins-Entsprechung zwischen Protokollen und Nodes. Dies
ist, weil Protokoll Objekte werden aggregiert zu Knoten Objekte. Da gibt es keine globale
Protokoll-ID im System verwenden wir die entsprechende Node-ID bei der Dateibenennung. Deshalb
Es besteht die Möglichkeit von Dateinamenkollisionen in automatisch gewählten Trace-Dateinamen.
Aus diesem Grund wird die Dateinamenskonvention für Protokoll-Traces geändert.
Wie bereits erwähnt, hat jeder Knoten im System eine vom System zugewiesene Knoten-ID.
Da es eine Eins-zu-Eins-Entsprechung zwischen Protokollinstanzen und Knoteninstanzen gibt
Wir verwenden die Knoten-ID. Jede Schnittstelle hat eine Schnittstellen-ID relativ zu ihrem Protokoll. Wir gebrauchen
Das Treffen " -n -ich .pcap" für die Benennung von Trace-Dateien in
Protokoll-Helfer.
Daher wird standardmäßig eine PCAP-Ablaufverfolgungsdatei erstellt, wenn die Ablaufverfolgung aktiviert wird
Schnittstelle 1 des Ipv4-Protokolls von Node 21 mit dem Präfix „prefix“ wäre
"Präfix-n21-i1.pcap".
Sie können immer die verwenden NS-3 Object Name Service, um dies deutlicher zu machen. Zum Beispiel, wenn
Sie verwenden den Object Name Service, um dem Ptr den Namen "serverIpv4" zuzuweisen auf Knoten
21, der resultierende PCAP-Trace-Dateiname wird automatisch zu
"prefix-nserverIpv4-i1.pcap".
Einige der Methoden haben einen Standardparameter namens explizitDateiname. Bei Einstellung auf
true, deaktiviert dieser Parameter den automatischen Dateinamen-Vervollständigungsmechanismus und lässt Sie zu
um einen eindeutigen Dateinamen zu erstellen. Diese Option ist nur in den Methoden verfügbar, die a annehmen
Präfix und aktivieren Sie die Ablaufverfolgung auf einem einzigen Gerät.
ASCII
Das Verhalten der ASCII-Trace-Helfer ähnelt im Wesentlichen dem PCAP-Fall. Nimm ein
betrachten src/network/helper/trace-helper.h wenn du die Diskussion dabei verfolgen möchtest
Betrachten Sie echten Code.
In diesem Abschnitt werden wir die Methoden veranschaulichen, die auf das Protokoll angewendet werden Ipv4. Nach
Traces in ähnlichen Protokollen spezifizieren, ersetzen Sie einfach den entsprechenden Typ. Beispielsweise,
benutze einen Ptr statt a Ptr und Ruf an AsciiIpv6 aktivieren statt
AsciiIpv4 aktivieren.
Die Klasse AsciiTraceHelperForIpv4 fügt die High-Level-Funktionalität für die Verwendung von ASCII hinzu
Tracing zu einem Protokoll-Helfer. Jedes Protokoll, das diese Methoden ermöglicht, muss ein
einzelne virtuelle Methode, die von dieser Klasse geerbt wird.
virtual void EnableAsciiIpv4Internal (Ptr Strom,
std::string-Präfix,
Ptr ipv4,
uint32_t-Schnittstelle,
bool expliziter Dateiname) = 0;
Die Signatur dieser Methode spiegelt die protokoll- und schnittstellenzentrierte Sicht der
Situation auf dieser Ebene; und auch die Tatsache, dass der Helfer möglicherweise an eine gemeinsame Adresse schreibt
Ausgabestrom. Alle öffentlichen Methoden, die von der Klasse geerbt wurden
PcapAndAsciiTraceHelperForIpv4 auf das Aufrufen dieses einzelnen Gerätes reduzieren
Implementierungsmethode. Zum Beispiel die ASCII-Trace-Methoden der niedrigsten Ebene,
void EnableAsciiIpv4 (std::string-Präfix, Ptr ipv4, uint4_t-Schnittstelle, bool expliziter Dateiname = false);
void EnableAsciiIpv4 (Ptr Strom, Ptr ipv4, uint4_t-Schnittstelle);
ruft die Geräteimplementierung von . auf AsciiIpv4Internal aktivieren direkt, Bereitstellung entweder
das Präfix oder der Stream. Alle anderen öffentlichen ASCII-Tracing-Methoden bauen darauf auf
Low-Level-Funktionen, um zusätzliche Funktionen auf Benutzerebene bereitzustellen. Was das bedeutet
der Benutzer ist, dass alle Gerätehelfer im System über alle ASCII-Trace-Methoden verfügen
erhältlich; und diese Methoden funktionieren alle protokollübergreifend auf die gleiche Weise, wenn die
Protokolle implementieren AsciiIpv4Internal aktivieren korrekt.
Methoden
void EnableAsciiIpv4 (std::string-Präfix, Ptr ipv4, uint4_t-Schnittstelle, bool expliziter Dateiname = false);
void EnableAsciiIpv4 (Ptr Strom, Ptr ipv4, uint4_t-Schnittstelle);
void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explizitFilename = false);
void EnableAsciiIpv4 (Ptr stream, std::string ipv4Name, uint32_t-Schnittstelle);
void EnableAsciiIpv4 (std::string Präfix, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr Strom, IPv4InterfaceContainer c);
void EnableAsciiIpv4 (std::string Präfix, NodeContainer n);
void EnableAsciiIpv4 (Ptr stream, NodeContainer n);
void EnableAsciiIpv4All (std::string-Präfix);
void EnableAsciiIpv4All (Ptr Strom);
void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explizitFilename);
void EnableAsciiIpv4 (Ptr stream, uint32_t-Knoten-ID, uint32_t-Schnittstelle);
Sie werden ermutigt, die API-Dokumentation für den Unterricht zu lesen PcapAndASciiHelperForIpv4 zu
finden Sie die Details dieser Methoden; aber zusammenfassend...
· Für ASCII-Tracing stehen doppelt so viele Methoden zur Verfügung wie für PCAP
Verfolgung. Dies liegt daran, dass neben dem PCAP-Modell auch Spuren von jedem vorhanden sind
einzigartige Protokoll-/Schnittstellenpaare in eine eindeutige Datei geschrieben werden, unterstützen wir ein Modell, in dem
Trace-Informationen für viele Protokoll-/Schnittstellenpaare werden in eine gemeinsame Datei geschrieben. Dies
bedeutet, dass die -n - Dateinamengenerierungsmechanismus ist
durch einen Mechanismus ersetzt, um auf eine gemeinsame Datei zu verweisen; und die Anzahl der API-Methoden ist
verdoppelt, um alle Kombinationen zu ermöglichen.
· Genau wie bei der PCAP-Ablaufverfolgung können Sie die ASCII-Ablaufverfolgung für ein bestimmtes Protokoll/eine bestimmte Schnittstelle aktivieren
paaren Sie, indem Sie a . angeben Ptr und ein Schnittstelle ein Ascii aktivieren Methode. Zum Beispiel,
Ptr ipv4;
...
helper.EnableAsciiIpv4 ("Präfix", IPv4, 1);
In diesem Fall werden keine Trace-Kontexte in die ASCII-Trace-Datei geschrieben, da dies der Fall wäre
redundant. Das System wählt den zu erstellenden Dateinamen nach den gleichen Regeln wie
wie im PCAP-Abschnitt beschrieben, außer dass die Datei stattdessen die Endung „.tr“ hat
von ".pcap".
· Wenn Sie ASCII-Tracing auf mehr als einer Schnittstelle aktivieren und alle Traces senden lassen möchten
auf eine einzelne Datei, können Sie dies auch tun, indem Sie ein Objekt verwenden, um auf eine einzelne Datei zu verweisen.
Etwas Ähnliches haben wir bereits im obigen "cwnd"-Beispiel:
Ptr Protokoll4 = Knoten1->GetObject ();
Ptr Protokoll4 = Knoten2->GetObject ();
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAsciiIpv4 (Stream, Protokoll1, 1);
helper.EnableAsciiIpv4 (Stream, Protokoll2, 1);
In diesem Fall werden Trace-Kontexte in die ASCII-Trace-Datei geschrieben, da sie benötigt werden
um Spuren von den beiden Schnittstellen zu unterscheiden. Beachten Sie, dass der Benutzer vollständig ist
Wenn Sie den Dateinamen angeben, sollte die Zeichenfolge aus Konsistenzgründen das ", tr" enthalten.
· Sie können die ASCII-Ablaufverfolgung für ein bestimmtes Protokoll aktivieren, indem Sie a angeben std::string
einen Objektnamen-Service-String für einen . darstellen Aktivieren Sie Pcap Methode. Das Ptr is
aus der Namenszeichenfolge nachgeschlagen. Der in den resultierenden Dateinamen ist implizit, da
Es gibt eine Eins-zu-Eins-Entsprechung zwischen Protokollinstanzen und Knoten, z. B.
Namen::Hinzufügen ("node1Ipv4" ...);
Namen::Hinzufügen ("node2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("Präfix", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("Präfix", "node2Ipv4", 1);
Dies würde zu zwei Dateien mit dem Namen "prefix-nnode1Ipv4-i1.tr" und
"prefix-nnode2Ipv4-i1.tr" mit Traces für jede Schnittstelle in der jeweiligen Trace-Datei.
Da alle EnableAscii-Funktionen überladen sind, um einen Stream-Wrapper zu verwenden, können Sie
Verwenden Sie auch dieses Formular:
Namen::Hinzufügen ("node1Ipv4" ...);
Namen::Hinzufügen ("node2Ipv4" ...);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAsciiIpv4 (Stream, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (Stream, "node2Ipv4", 1);
Dies würde zu einer einzigen Ablaufverfolgungsdatei mit dem Namen "trace-file-name.tr" führen, die alle enthält
der Ablaufverfolgungsereignisse für beide Schnittstellen. Die Ereignisse würden durch Ablaufverfolgung disambiguiert
Kontextzeichenfolgen.
· Sie können die ASCII-Ablaufverfolgung für eine Sammlung von Protokoll-/Schnittstellenpaaren aktivieren, indem Sie eine angeben
IPv4InterfaceContainer. Für jedes Protokoll des richtigen Typs (derselbe Typ wie is
vom Device Helper verwaltet), ist die Ablaufverfolgung für die entsprechende Schnittstelle aktiviert.
Auch die ist implizit, da zwischen ihnen eine Eins-zu-Eins-Entsprechung besteht
Protokoll und seinen Knoten. Zum Beispiel,
NodeContainer-Knoten;
...
NetDeviceContainer-Geräte = deviceHelper.Install (Knoten);
...
IPv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer-Schnittstellen = ipv4.Assign (Geräte);
...
...
helper.EnableAsciiIpv4 ("Präfix", Schnittstellen);
Dies würde dazu führen, dass eine Reihe von ASCII-Trace-Dateien erstellt werden, von denen jede folgt
das -n -ich .tr-Konvention. Kombinieren aller Spuren zu a
einzelne Datei wird ähnlich wie in den obigen Beispielen durchgeführt:
NodeContainer-Knoten;
...
NetDeviceContainer-Geräte = deviceHelper.Install (Knoten);
...
IPv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer-Schnittstellen = ipv4.Assign (Geräte);
...
Ptr stream = asciiTraceHelper.CreateFileStream ("Trace-Dateiname.tr");
...
helper.EnableAsciiIpv4 (Stream, Schnittstellen);
· Sie können die ASCII-Ablaufverfolgung für eine Sammlung von Protokoll-/Schnittstellenpaaren aktivieren, indem Sie a angeben
NodeContainer. Für jeden Knoten in der NodeContainer das passende Protokoll gefunden wird.
Für jedes Protokoll werden seine Schnittstellen aufgezählt und die Ablaufverfolgung für das Ergebnis aktiviert
Paare. Zum Beispiel,
NodeContainer n;
...
helper.EnableAsciiIpv4 ("Präfix", n);
Dies würde dazu führen, dass eine Reihe von ASCII-Trace-Dateien erstellt werden, von denen jede folgt
das - - .tr-Konvention. Kombinieren aller Spuren in a
einzelne Datei wird ähnlich wie in den obigen Beispielen ausgeführt.
· Sie können die PCAP-Ablaufverfolgung auch auf der Basis von Knoten-ID und Geräte-ID aktivieren. In diesem
Fall wird die Knoten-ID in a übersetzt Ptr und das entsprechende Protokoll wird nachgeschlagen
im Knoten. Das resultierende Protokoll und die Schnittstelle werden verwendet, um das Ergebnis zu spezifizieren
Spurenquelle.
helper.EnableAsciiIpv4 ("Präfix", 21, 1);
Natürlich können die Spuren wie oben gezeigt in einer einzigen Datei kombiniert werden.
· Schließlich können Sie die ASCII-Ablaufverfolgung für alle Schnittstellen im System mit zugehörigen aktivieren
wobei das Protokoll vom gleichen Typ ist wie das vom Device Helper verwaltete.
helper.EnableAsciiIpv4All ("Präfix");
Dies würde dazu führen, dass mehrere ASCII-Trace-Dateien erstellt werden, eine für jede
Schnittstelle im System, die sich auf ein Protokoll des vom Helfer verwalteten Typs bezieht. Alle
Diese Dateien folgen dem -n -ich
Alle Ablaufverfolgungen in einer einzigen Datei werden ähnlich wie in den obigen Beispielen ausgeführt.
Dateinamen
Implizit in den obigen Methodenbeschreibungen im Präfixstil ist die Konstruktion des vollständigen
Dateinamen nach der Implementierungsmethode. Konventionsgemäß werden ASCII-Spuren in der NS-3 System
sind von der Form " - - .tr"
Wie bereits erwähnt, hat jeder Knoten im System eine vom System zugewiesene Knoten-ID.
Da es eine Eins-zu-Eins-Entsprechung zwischen Protokollen und Knoten gibt, verwenden wir die Knoten-ID
um die Protokollidentität zu identifizieren. Jede Schnittstelle auf einem bestimmten Protokoll hat einen
Schnittstellenindex (auch einfach eine Schnittstelle genannt) relativ zu seinem Protokoll. Standardmäßig,
dann eine ASCII-Ablaufverfolgungsdatei, die als Ergebnis der Aktivierung der Ablaufverfolgung auf dem ersten Gerät von erstellt wurde
Knoten 21, der das Präfix "prefix" verwendet, wäre "prefix-n21-i1.tr". Verwenden Sie das Präfix bis
Disambiguieren mehrerer Protokolle pro Knoten.
Sie können immer die verwenden NS-3 Object Name Service, um dies deutlicher zu machen. Zum Beispiel, wenn
Sie verwenden den Objektnamendienst, um dem Protokoll auf Node den Namen "serverIpv4" zuzuweisen
21, und geben Sie auch Schnittstelle eins an, wird der resultierende ASCII-Trace-Dateiname automatisch
werden, "prefix-nserverIpv4-1.tr".
Einige der Methoden haben einen Standardparameter namens explizitDateiname. Bei Einstellung auf
true, deaktiviert dieser Parameter den automatischen Dateinamen-Vervollständigungsmechanismus und lässt Sie zu
um einen eindeutigen Dateinamen zu erstellen. Diese Option ist nur in den Methoden verfügbar, die a annehmen
Präfix und aktivieren Sie die Ablaufverfolgung auf einem einzigen Gerät.
Zusammenfassung
NS-3 enthält eine extrem reichhaltige Umgebung, die es Benutzern auf mehreren Ebenen ermöglicht, sie anzupassen
die Arten von Informationen, die aus Simulationen extrahiert werden können.
Es gibt High-Level-Hilfsfunktionen, mit denen Benutzer einfach die Sammlung von steuern können
vordefinierte Ausgaben bis zu einer feinen Granularität. Es gibt Hilfsfunktionen auf mittlerer Ebene, die zugelassen werden können
erfahrenere Benutzer können anpassen, wie Informationen extrahiert und gespeichert werden; und da
sind Low-Level-Kernfunktionen, die es erfahrenen Benutzern ermöglichen, das System zu ändern, um neue und
zuvor nicht exportierte Informationen in einer Weise, die den Benutzern sofort zugänglich ist
höhere Stufen.
Dies ist ein sehr umfassendes System, und wir wissen, dass es besonders viel zu verdauen ist
für neue Benutzer oder diejenigen, die mit C++ und seinen Redewendungen nicht vertraut sind. Wir überlegen
das Rückverfolgungssystem ein sehr wichtiger Teil von NS-3 und so empfehlen sich so vertraut wie
damit möglich. Es ist wahrscheinlich so, dass das Verständnis für den Rest der NS-3 System
wird ganz einfach sein, sobald Sie das Ablaufverfolgungssystem beherrschen
DATEN KOLLEKTION
Unser letztes Tutorial-Kapitel stellt einige Komponenten vor, die hinzugefügt wurden NS-3 in version
3.18, die sich noch in der Entwicklung befinden. Dieser Tutorial-Abschnitt ist auch ein
Work-in-progress.
Motivation
Einer der Hauptpunkte beim Ausführen von Simulationen ist das Generieren von Ausgabedaten, entweder für
zu Forschungszwecken oder einfach um das System kennenzulernen. Im vorigen Kapitel haben wir
stellte das Tracing-Subsystem und das Beispiel vor sechste.cc. ab welchem PCAP- oder ASCII-Trace
Dateien werden generiert. Diese Spuren sind wertvoll für die Datenanalyse mit einer Vielzahl von
externe Tools, und für viele Benutzer sind solche Ausgabedaten ein bevorzugtes Mittel zum Sammeln
Daten (zur Analyse durch externe Tools).
Es gibt jedoch auch Anwendungsfälle für mehr als die Generierung von Ablaufverfolgungsdateien, einschließlich der
wie folgt vor:
· Generierung von Daten, die sich nicht gut auf PCAP- oder ASCII-Traces abbilden lassen, z. B. Nicht-Paket
Daten (z. B. Protokollzustandsmaschinenübergänge),
· große Simulationen, für die die Festplatten-E/A-Anforderungen zum Generieren von Ablaufverfolgungsdateien gelten
unerschwinglich oder umständlich, und
· das Bedürfnis nach Online Datenreduktion oder -berechnung im Verlauf der Simulation.
Ein gutes Beispiel dafür ist, eine Abbruchbedingung für die Simulation zu definieren, zu sagen
es, wann es aufhören soll, wenn es genügend Daten erhalten hat, um ein ausreichend enges Vertrauen zu bilden
Intervall um die Schätzung eines Parameters.
Die NS-3 Das Datenerfassungs-Framework wurde entwickelt, um diese zusätzlichen Funktionen bereitzustellen
jenseits der Trace-basierten Ausgabe. Wir empfehlen dem an diesem Thema interessierten Leser zu konsultieren
NS-3 Handbuch für eine detailliertere Behandlung dieses Frameworks; hier fassen wir mit zusammen
ein Beispielprogramm einige der Entwicklungsfunktionen.
Beispiel Code
Das Lernbeispiel Beispiele/Tutorial/Seventh.cc ähnelt dem sechste.cc Beispiel wir
zuvor überprüft, mit Ausnahme einiger Änderungen. Erstens wurde es für IPv6 aktiviert
Unterstützung mit einer Befehlszeilenoption:
Befehlszeile cmd;
cmd.AddValue ("useIpv6", "Use Ipv6", useV6);
cmd.Parse (argc, argv);
Wenn der Benutzer angibt Verwenden Sie IPv6, wird das Programm mit IPv6 anstelle von IPv4 ausgeführt.
Die Hilfe Option, verfügbar für alle NS-3 Programme, die das CommandLine-Objekt als unterstützen
oben gezeigt, kann wie folgt aufgerufen werden (bitte beachten Sie die Verwendung von doppelten Anführungszeichen):
./waf --run "seventh --help"
was produziert:
ns3-dev-seventh-debug [Programmargumente] [Allgemeine Argumente]
Programmargumente:
--useIpv6: Ipv6 verwenden [false]
Allgemeine Argumente:
--PrintGlobals: Druckt die Liste der Globals.
--PrintGroups: Drucken Sie die Liste der Gruppen.
--PrintGroup=[group]: Druckt alle TypeIds der Gruppe.
--PrintTypeIds: Alle TypeIds drucken.
--PrintAttributes=[typeid]: Gibt alle Attribute von typeid aus.
--PrintHelp: Drucken Sie diese Hilfenachricht.
Dieser Standard (Verwendung von IPv4, da useIpv6 falsch ist) kann durch Umschalten des booleschen Werts geändert werden
Wert wie folgt:
./waf --run "seventh --useIpv6=1"
und schauen Sie sich das generierte pcap an, z. B. mit tcpdump:
tcpdump -r siebter.pcap -nn -tt
Dies war ein kurzer Exkurs in die IPv6-Unterstützung und die Befehlszeile, was auch der Fall war
zuvor in diesem Tutorial eingeführt. Ein dediziertes Beispiel für die Verwendung der Befehlszeile finden Sie unter
bitte sehen src/core/examples/command-line-example.cc.
Nun zurück zur Datenerhebung. In dem Beispiele/Tutorial/ Geben Sie im Verzeichnis Folgendes ein
Befehl: diff -u sechste.cc siebte.cc, und untersuchen Sie einige der neuen Zeilen dieses Diffs:
+ std::string probeType;
+ std::string TracePath;
+ if (useV6 == false)
†
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+ }
+ sonst
†
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+ }
...
+ // Verwenden Sie GnuplotHelper, um die Anzahl der Paketbytes über die Zeit darzustellen
+ GnuplotHelper plotHelper;
+
+ // Konfiguriere den Plot. Das erste Argument ist das Präfix des Dateinamens
+ // für die generierten Ausgabedateien. Die zweite, dritte und vierte
+ // Argumente sind jeweils der Diagrammtitel, die x-Achse und die y-Achsenbeschriftung
+ plotHelper.ConfigurePlot ("siebtes-Paket-Byte-Anzahl",
+ "Paket-Byte-Anzahl vs. Zeit",
+ "Zeit (Sekunden)",
+ "Paket-Byte-Anzahl");
+
+ // Sondentyp, Trace-Quellpfad (im Konfigurations-Namespace) und angeben
+ // Ausgabe-Trace-Quelle ("OutputBytes") zum Plotten untersuchen. Das vierte Argument
+ // gibt den Namen der Datenreihenbeschriftung im Diagramm an. Das Letzte
+ // Das Argument formatiert den Plot, indem es angibt, wo der Schlüssel platziert werden soll.
+ plotHelper.PlotProbe (probeType,
+ TracePfad,
+ "Ausgabebytes",
+ "Paket-Byte-Anzahl",
+ GnuplotAggregator::KEY_BELOW);
+
+ // Verwenden Sie FileHelper, um die Anzahl der Paketbytes im Laufe der Zeit auszugeben
+ FileHelper fileHelper;
+
+ // Konfigurieren Sie die zu schreibende Datei und die Formatierung der Ausgabedaten.
+ fileHelper.ConfigureFile ("siebtes-Paket-Byte-Anzahl",
+ FileAggregator::FORMATTED);
+
+ // Legen Sie die Labels für diese formatierte Ausgabedatei fest.
+ fileHelper.Set2dFormat ("Zeit (Sekunden) = %.3e\tPacket Byte Count = %.0f");
+
+ // Geben Sie den Probe-Typ, den Probe-Pfad (im Konfigurations-Namespace) und an
+ // Ausgabe-Trace-Quelle ("OutputBytes") zum Schreiben prüfen.
+ fileHelper.WriteProbe (probeType,
+ TracePfad,
+ "OutputBytes");
+
Simulator::Stop (Sekunden (20));
Simulator::Run ();
Simulator::Zerstören ();
Der aufmerksame Leser wird beim Testen des obigen IPv6-Befehlszeilenattributs bemerkt haben,
zur Verbesserung der Gesundheitsgerechtigkeit siebte.cc hatte eine Reihe neuer Ausgabedateien erstellt:
siebtes-paket-byte-count-0.txt
siebtes-paket-byte-count-1.txt
siebtes-paket-byte-count.dat
siebtes-paket-byte-count.plt
siebentes-paket-byte-anzahl.png
siebtes-paket-byte-count.sh
Diese wurden durch die oben eingeführten zusätzlichen Anweisungen erstellt; insbesondere durch a
GnuplotHelper und ein FileHelper. Diese Daten wurden durch Einhaken der Datensammlung erzeugt
Komponenten NS-3 Trace-Quellen und Marshallen der Daten in eine formatierte Gnuplot und
in eine formatierte Textdatei. In den nächsten Abschnitten werden wir jede davon überprüfen.
GnuplotHelfer
Der GnuplotHelper ist ein NS-3 Hilfsobjekt, das auf die Produktion von ausgerichtet ist Gnuplot Grundstücke mit
so wenige Aussagen wie möglich für häufige Fälle. Es hakt NS-3 Quellen mit Daten verfolgen
Typen, die vom Datenerfassungssystem unterstützt werden. Nicht alle NS-3 Trace-Quellen-Datentypen sind
unterstützt, aber viele der gängigen Ablaufverfolgungstypen werden unterstützt, einschließlich TracedValues mit einfachem Alt
Datentypen (POD).
Schauen wir uns die von diesem Helfer erzeugte Ausgabe an:
siebtes-paket-byte-count.dat
siebtes-paket-byte-count.plt
siebtes-paket-byte-count.sh
Die erste ist eine Gnuplot-Datendatei mit einer Reihe von durch Leerzeichen getrennten Zeitstempeln und Paketen
Byte zählt. Wir werden unten behandeln, wie diese spezielle Datenausgabe konfiguriert wurde, aber lassen Sie uns
Fahren Sie mit den Ausgabedateien fort. Die Datei siebtes-paket-byte-count.plt ist ein Gnuplot-Plot
Datei, die innerhalb von gnuplot geöffnet werden kann. Leser, die die gnuplot-Syntax verstehen, können das
sehen Sie, dass dies eine formatierte Ausgabe-PNG-Datei mit dem Namen erzeugt
siebentes-paket-byte-anzahl.png. Zum Schluss noch ein kleines Shell-Skript
siebtes-paket-byte-count.sh führt diese Plotdatei durch gnuplot aus, um das gewünschte zu erzeugen
PNG (das in einem Bildbearbeitungsprogramm angezeigt werden kann); das heißt, der Befehl:
sh siebtes-paket-byte-anzahl.sh
wird nachgeben siebentes-paket-byte-anzahl.png. Warum wurde dieses PNG nicht in der ersten erstellt
Platz? Die Antwort ist, dass der Benutzer durch Bereitstellen der plt-Datei die
Ergebnis, falls gewünscht, bevor das PNG erzeugt wird.
Der Titel des PNG-Bildes besagt, dass dieses Diagramm ein Diagramm von "Packet Byte Count vs. Time" ist, und
dass es die untersuchten Daten entsprechend dem Ablaufverfolgungsquellenpfad darstellt:
/NodeList/*/$ns3::Ipv6L3Protocol/Tx
Beachten Sie den Platzhalter im Ablaufverfolgungspfad. Zusammenfassend ist das, was diese Handlung einfängt, die Handlung
von Paketbytes, die an der Übertragungsablaufverfolgungsquelle des Ipv6L3Protocol-Objekts beobachtet werden;
hauptsächlich 596-Byte-TCP-Segmente in eine Richtung und 60-Byte-TCP-Acks in die andere (zwei
Knoten-Trace-Quellen wurden mit dieser Trace-Quelle abgeglichen).
Wie wurde das konfiguriert? Ein paar Aussagen müssen gemacht werden. Zuerst der GnuplotHelper
Objekt muss deklariert und konfiguriert werden:
+ // Verwenden Sie GnuplotHelper, um die Anzahl der Paketbytes über die Zeit darzustellen
+ GnuplotHelper plotHelper;
+
+ // Konfiguriere den Plot. Das erste Argument ist das Präfix des Dateinamens
+ // für die generierten Ausgabedateien. Die zweite, dritte und vierte
+ // Argumente sind jeweils der Diagrammtitel, die x-Achse und die y-Achsenbeschriftung
+ plotHelper.ConfigurePlot ("siebtes-Paket-Byte-Anzahl",
+ "Paket-Byte-Anzahl vs. Zeit",
+ "Zeit (Sekunden)",
+ "Paket-Byte-Anzahl");
Bis zu diesem Punkt wurde ein leerer Plot konfiguriert. Das Dateinamenpräfix ist das erste
Argument, der Diagrammtitel ist das zweite, die x-Achsenbeschriftung die dritte und die y-Achsenbeschriftung
das vierte argument.
Der nächste Schritt besteht darin, die Daten zu konfigurieren, und hier wird die Ablaufverfolgungsquelle angeschlossen.
Beachten Sie zunächst, dass wir oben im Programm einige Variablen für die spätere Verwendung deklariert haben:
+ std::string probeType;
+ std::string TracePath;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
Wir verwenden sie hier:
+ // Sondentyp, Trace-Quellpfad (im Konfigurations-Namespace) und angeben
+ // Ausgabe-Trace-Quelle ("OutputBytes") zum Plotten untersuchen. Das vierte Argument
+ // gibt den Namen der Datenreihenbeschriftung im Diagramm an. Das Letzte
+ // Das Argument formatiert den Plot, indem es angibt, wo der Schlüssel platziert werden soll.
+ plotHelper.PlotProbe (probeType,
+ TracePfad,
+ "Ausgabebytes",
+ "Paket-Byte-Anzahl",
+ GnuplotAggregator::KEY_BELOW);
Die ersten beiden Argumente sind der Name des Sondentyps und der Ablaufverfolgungsquellenpfad. Diese
Zwei sind wahrscheinlich am schwierigsten zu bestimmen, wenn Sie versuchen, dieses Framework zu verwenden, um andere zu plotten
Spuren. Die Sondenspur hier ist die Tx Trace-Quelle der Klasse IPv6L3Protokoll. Wenn wir
Untersuchen Sie diese Klassenimplementierung (src/internet/model/ipv6-l3-protocol.cc) können wir beobachten:
.AddTraceSource ("Tx", "IPv6-Paket an ausgehende Schnittstelle senden.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))
Das sagt das Tx ist ein Name für eine Variable m_txTrace, die eine Erklärung enthält von:
/ **
* \kurz Rückruf zur Verfolgung von TX-(Übertragungs-)Paketen.
*/
TracedCallback , Ptr , uint6_t> m_txTrace;
Es stellt sich heraus, dass diese spezielle Ablaufverfolgungsquellensignatur von einer Probe-Klasse (what
brauchen wir hier) der Klasse Ipv6PacketProbe. Sehen Sie sich die Dateien an
src/internet/model/ipv6-packet-probe.{h,cc}.
In der obigen PlotProbe-Anweisung sehen wir also, dass die Anweisung die Ablaufverfolgung verknüpft
Quelle (identifiziert durch Pfadzeichenfolge) mit einer Übereinstimmung NS-3 Sondentyp von IPv6PacketProbe. Wenn
Wir haben diesen Sondentyp nicht unterstützt (übereinstimmende Trace-Quellensignatur), wir hätten es nicht tun können
diese Anweisung verwendet (obwohl einige kompliziertere Anweisungen auf niedrigerer Ebene hätten sein können
verwendet, wie im Handbuch beschrieben).
Die Ipv6PacketProbe exportiert selbst einige Trace-Quellen, die die Daten aus dem extrahieren
geprüftes Paketobjekt:
Typ-ID
Ipv6PacketProbe::GetTypeId ()
{
statische TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent ()
.Konstruktor hinzufügen ()
.AddTraceSource( "Ausgabe",
"Das Paket plus sein IPv6-Objekt und seine Schnittstelle, die als Ausgabe für diese Probe dienen",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource( "OutputBytes",
"Die Anzahl der Bytes im Paket",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
;
Rückkehr Gezeiten;
}
Das dritte Argument unserer PlotProbe-Anweisung gibt an, dass wir an der interessiert sind
Anzahl der Bytes in diesem Paket; insbesondere die "OutputBytes"-Ablaufverfolgungsquelle von
IPv6PacketProbe. Schließlich liefern die letzten beiden Argumente der Anweisung die Handlungslegende
für diese Datenreihe ("Packet Byte Count") und eine optionale gnuplot-Formatierungsanweisung
(GnuplotAggregator::KEY_BELOW) dass der Plotschlüssel unterhalb des Plots eingefügt werden soll.
Weitere Optionen sind NO_KEY, KEY_INSIDE und KEY_ABOVE.
Unterstützte Spur Typen
Zum jetzigen Zeitpunkt werden die folgenden nachverfolgten Werte mit Probes unterstützt:
" ────────────────────┐
│TracedValue-Typ │ Sondentyp │ Datei │
" ────────────────────┤
│double │ DoubleProbe │ stats/model/double-probe.h │
" ────────────────────┤
│uint8_t │ Uinteger8Probe │ stats/model/uinteger-8-probe.h │
" ────────────────────┤
│uint16_t │ Uinteger16Probe │ stats/model/uinteger-16-probe.h │
" ────────────────────┤
│uint32_t │ Uinteger32Probe │ stats/model/uinteger-32-probe.h │
" ────────────────────┤
│bool │ BooleanProbe │ stats/model/uinteger-16-probe.h │
" ────────────────────┤
│ns3::Time │ TimeProbe │ stats/model/time-probe.h │
" ────────────────────┘
Die folgenden TraceSource-Typen werden zum jetzigen Zeitpunkt von Probes unterstützt:
" ────schung schrikt das Rot kurz ──────────┐
" ────schung schrikt das Rot kurz ──────────┤
" ────schung schrikt das Rot kurz ──────────┤
" ────schung schrikt das Rot kurz ──────────┤
" ────schung schrikt das Rot kurz ──────────┤
" ────schung schrikt das Rot kurz ──────────┤
" ────schung schrikt das Rot kurz ──────────┘
Wie zu sehen ist, werden nur wenige Trace-Quellen unterstützt, und sie sind alle darauf ausgerichtet
Ausgabe der Paketgröße (in Bytes). Allerdings die meisten der grundlegenden Datentypen
als TracedValues verfügbar sind, können mit diesen Helfern unterstützt werden.
DateiHelper
Die FileHelper-Klasse ist nur eine Variation des vorherigen GnuplotHelper-Beispiels. Das
Das Beispielprogramm bietet eine formatierte Ausgabe der gleichen Zeitstempeldaten wie folgt:
Zeit (Sekunden) = 9.312e+00 Paketbyteanzahl = 596
Zeit (Sekunden) = 9.312e+00 Paketbyteanzahl = 564
Es werden zwei Dateien bereitgestellt, eine für Knoten „0“ und eine für Knoten „1“, wie in der zu sehen ist
Dateinamen. Schauen wir uns den Code Stück für Stück an:
+ // Verwenden Sie FileHelper, um die Anzahl der Paketbytes im Laufe der Zeit auszugeben
+ FileHelper fileHelper;
+
+ // Konfigurieren Sie die zu schreibende Datei und die Formatierung der Ausgabedaten.
+ fileHelper.ConfigureFile ("siebtes-Paket-Byte-Anzahl",
+ FileAggregator::FORMATTED);
Das Dateipräfix der Hilfsdatei ist das erste Argument, gefolgt von einem Formatbezeichner. Etwas
Weitere Formatierungsoptionen sind SPACE_SEPARATED, COMMA_SEPARATED und TAB_SEPARATED.
Benutzer können die Formatierung (falls FORMATTED angegeben ist) mit einer Formatzeichenfolge ändern
wie folgt:
+
+ // Legen Sie die Labels für diese formatierte Ausgabedatei fest.
+ fileHelper.Set2dFormat ("Zeit (Sekunden) = %.3e\tPacket Byte Count = %.0f");
Schließlich muss die interessierende Trace-Quelle eingehakt werden. Auch hier der probeType und der tracePath
Variablen in diesem Beispiel verwendet werden, und die Ausgabe-Trace-Quelle des Prüfpunkts „OutputBytes“ ist
süchtig:
+
+ // Sondentyp, Trace-Quellpfad (im Konfigurations-Namespace) und angeben
+ // Ausgabe-Trace-Quelle ("OutputBytes") zum Schreiben prüfen.
+ fileHelper.WriteProbe (probeType,
+ TracePfad,
+ "OutputBytes");
+
Die Platzhalterfelder in diesem Ablaufverfolgungsquellenbezeichner stimmen mit zwei Ablaufverfolgungsquellen überein. im Gegensatz zu den
GnuplotHelper-Beispiel, bei dem zwei Datenreihen auf demselben Plot überlagert wurden, hier zwei
separate Dateien werden auf die Festplatte geschrieben.
Zusammenfassung
Unterstützung für die Datenerfassung ist neu seit ns-3.18 und grundlegende Unterstützung für die Bereitstellung von Zeitreihen
Ausgang hinzugefügt. Das oben beschriebene Grundmuster kann innerhalb der repliziert werden
Umfang der Unterstützung der vorhandenen Probes und Trace-Quellen. Mehr Funktionen inkl
Statistikverarbeitung wird in zukünftigen Versionen hinzugefügt.
FAZIT
Futures
Dieses Dokument ist als lebendes Dokument gedacht. Wir hoffen und erwarten, dass es im Laufe der Zeit wächst
um immer mehr Schrauben und Muttern abzudecken NS-3.
Das Schreiben von Handbuch- und Tutorial-Kapiteln ist nicht etwas, worüber wir uns alle aufregen, aber es ist so
sehr wichtig für das Projekt. Wenn Sie Experte in einem dieser Bereiche sind, bitte
erwägen, dazu beizutragen NS-3 durch Bereitstellen eines dieser Kapitel; oder ein anderes Kapitel Sie
vielleicht für wichtig halten.
Schließen
NS-3 ist ein großes und kompliziertes System. Es ist unmöglich, alle Dinge, die Sie abdecken
müssen in einem kleinen Tutorial wissen. Leser, die mehr erfahren möchten, werden dazu ermutigt
lesen Sie die folgende zusätzliche Dokumentation:
· Das NS-3 manuell
· Das NS-3 Dokumentation der Modellbibliothek
· Das NS-3 Doxygen (API-Dokumentation)
· Das NS-3 Wiki
-- Das NS-3 Entwicklungsteam.
Verwenden Sie ns-3-tutorial online mit den Diensten von onworks.net