ns-3-tutorial - Online în cloud

Acesta este tutorialul ns-3-comandă care poate fi rulat în furnizorul de găzduire gratuit OnWorks folosind una dintre multiplele noastre stații de lucru online gratuite, cum ar fi Ubuntu Online, Fedora Online, emulator online Windows sau emulator online MAC OS

PROGRAM:

NUME


ns-3-tutorial - ns-3 Tutorial

Aceasta este ns-3 tutorial. Documentația principală pentru proiectul ns-3 este disponibilă în cinci
forme:

· ns-3 Oxigen: Documentarea API-urilor publice ale simulatorului

· Tutorial (acest document), Manual și Biblioteca de modele pentru Ultimele eliberaţi si
dezvoltare copac

· ns-3 Wiki

Acest document este scris în reStructuredText pentru Sfinx și se menține în
doc/tutorial directorul codului sursă al lui ns-3.

INTRODUCERE


ns-3 simulator este un simulator de rețea cu evenimente discrete, destinat în principal cercetării
și uz educațional. The ns-3 proiect, început în 2006, este un proiect open-source
în curs de dezvoltare ns-3.

Scopul acestui tutorial este de a introduce noi ns-3 utilizatorii la sistem într-o formă structurată
cale. Uneori este dificil pentru noii utilizatori să culeagă informații esențiale din detalii
manuale și pentru a converti aceste informații în simulări de lucru. În acest tutorial, noi
va construi câteva exemple de simulări, introducând și explicând concepte cheie și
caracteristici pe măsură ce mergem.

Pe măsură ce tutorialul se desfășoară, îl vom prezenta complet ns-3 documentatie si furnizati
indicii către codul sursă pentru cei interesați să aprofundeze funcționarea
sistemului.

Câteva puncte cheie merită remarcate la început:

· ns-3 este open-source, iar proiectul se străduiește să mențină un mediu deschis pentru
cercetătorii să contribuie și să-și partajeze software-ul.

· ns-3 nu este o extensie compatibilă cu versiunea inversă a ns-2; este un nou simulator. Cei doi
simulatoarele sunt ambele scrise în C++ dar ns-3 este un nou simulator care nu acceptă
ns-2 API-uri. Unele modele de la ns-2 au fost deja portate din ns-2 la ns-3.
proiectul va continua să se mențină ns-2 în timp ce ns-3 se construiește și va studia
mecanisme de tranziție și integrare.

Despre ns-3
ns-3 a fost dezvoltat pentru a oferi o platformă de simulare a rețelei deschisă, extensibilă, pt
cercetare și educație în rețele. Pe scurt, ns-3 oferă modele despre modul în care pachetele de date
rețelele funcționează și funcționează și oferă un motor de simulare pentru ca utilizatorii să le conducă
experimente de simulare. Câteva dintre motivele de utilizare ns-3 includ să efectueze studii care
sunt mai dificil sau imposibil de realizat cu sisteme reale, pentru a studia comportamentul sistemului
într-un mediu foarte controlat, reproductibil și pentru a afla cum funcționează rețelele.
Utilizatorii vor observa că modelul disponibil s-a instalat ns-3 se concentrează pe modelarea modului în care Internetul
protocoalele și rețelele funcționează, dar ns-3 nu se limitează la sistemele de internet; mai multi utilizatori
folosesc ns-3 pentru a modela sisteme care nu sunt bazate pe Internet.

Există multe instrumente de simulare pentru studiile de simulare a rețelei. Mai jos sunt câteva
caracteristici distinctive ale ns-3 spre deosebire de alte instrumente.

· ns-3 este conceput ca un set de biblioteci care pot fi combinate între ele și, de asemenea, cu altele
biblioteci de software externe. În timp ce unele platforme de simulare oferă utilizatorilor a
mediu de interfață grafică unică, integrată, în care sunt efectuate toate sarcinile
out, ns-3 este mai modular în acest sens. Mai mulți animatori externi și analiză de date
iar instrumentele de vizualizare pot fi folosite cu ns-3. Cu toate acestea, utilizatorii ar trebui să se aștepte să lucreze la
linia de comandă și cu instrumente de dezvoltare software C++ și/sau Python.

· ns-3 este folosit în principal pe sistemele Linux, deși există suport pentru FreeBSD, Cygwin
(pentru Windows) și suportul nativ pentru Windows Visual Studio este în curs de a fi
dezvoltat.

· ns-3 nu este un produs software acceptat oficial de nicio companie. Suport pentru ns-3
se face pe baza celor mai bune eforturi pe lista de corespondență ns-3-users.

Pentru ns-2 Utilizatori
Pentru cei familiarizați cu ns-2 (un instrument popular care a precedat ns-3), cel mai vizibil în exterior
schimbați când vă mutați ns-3 este alegerea limbajului de scripting. Programe în ns-2 sunt
scriptate în OTcl și rezultatele simulărilor pot fi vizualizate folosind Network Animator
nam. Nu este posibil să rulați o simulare în ns-2 pur din C++ (adică ca principal()
program fără nici un OTcl). Mai mult, unele componente ale ns-2 sunt scrise în C++ și
altele în OTcl. În ns-3, simulatorul este scris în întregime în C++, cu opțional Python
legături. Prin urmare, scripturile de simulare pot fi scrise în C++ sau în Python. Animatori noi
și vizualizatoare sunt disponibile și în curs de dezvoltare. De cand ns-3 generează pcap
fișiere de urmărire a pachetelor, alte utilitare pot fi utilizate și pentru a analiza urmele. In acest
tutorial, ne vom concentra mai întâi pe scriptarea directă în C++ și pe interpretarea rezultatelor
prin fișiere de urmărire.

Dar există și asemănări (ambele, de exemplu, se bazează pe obiecte C++, iar unele
cod de la ns-2 a fost deja portat la ns-3). Vom încerca să evidențiem diferențele
între ns-2 si ns-3 așa cum procedăm în acest tutorial.

O întrebare pe care o auzim adesea este „Ar trebui să mai folosesc ns-2 sau muta la ns-3?" In acest
opinia autorului, cu excepția cazului în care utilizatorul este într-un fel învestit ns-2 (fie pe baza existentei
confort personal cu și cunoaștere a ns-2, sau pe baza unui model de simulare specific care
este disponibil numai în ns-2), un utilizator va fi mai productiv cu ns-3 pentru următorii
motive:

· ns-3 este întreținut activ cu o listă de corespondență a utilizatorilor activă și receptivă, în timp ce ns-2 is
întreținut doar ușor și nu a cunoscut o dezvoltare semnificativă în arborele său principal de cod
de peste un deceniu.

· ns-3 oferă funcții care nu sunt disponibile în ns-2, cum ar fi execuția unui cod de implementare
mediu (permițând utilizatorilor să ruleze cod real de implementare în simulator)

· ns-3 oferă un nivel de bază mai scăzut de abstractizare în comparație cu ns-2, permițându-i să se alinieze
mai bine cu modul în care sistemele reale sunt puse împreună. Unele limitări găsite în ns-2 (precum
care acceptă corect mai multe tipuri de interfețe pe noduri) au fost remediate în ns-3.

ns-2 are un set mai divers de module contribuite decât are ns-3, datorită lungimii sale
istorie. In orice caz, ns-3 are modele mai detaliate în mai multe domenii populare de cercetare
(inclusiv modele LTE și WiFi sofisticate) și suportul său pentru codul de implementare
admite un spectru foarte larg de modele de înaltă fidelitate. Utilizatorii pot fi surprinși să afle asta
întreaga stivă de rețea Linux poate fi încapsulată într-un ns-3 nod, folosind Direct
Cadrul de executare a codului (DCE). ns-2 modelele pot fi uneori portate ns-3, în special
dacă au fost implementate în C++.

Dacă aveți îndoieli, un ghid bun ar fi să priviți ambele simulatoare (precum și altele
simulatoare), și în special modelele disponibile pentru cercetarea dvs., dar rețineți
ca experiența dumneavoastră să fie mai bună în utilizarea instrumentului care este dezvoltat în mod activ și
menținut (ns-3).

Contribuind
ns-3 este un simulator de cercetare și educație, de și pentru comunitatea de cercetare. Se va
se bazează pe contribuțiile continue ale comunității pentru a dezvolta noi modele, depanare sau
menține-le pe cele existente și împărtășește rezultatele. Există câteva politici care sperăm că vor fi
încurajează oamenii să contribuie la ns-3 cum au pentru ns-2:

· Licențiere open source bazată pe compatibilitatea GNU GPLv2

· Wiki

· A contribuit Cod pagina, similar cu ns-2Codul de contribuție popular al lui pagină

· Deschis bug tracker

Ne dăm seama că dacă citiți acest document, contribuția înapoi la proiect este
probabil că nu este preocuparea dvs. principală în acest moment, dar vrem să fiți conștienți de asta
a contribui este în spiritul proiectului și chiar și actul de a ne lăsa o notă
despre experiența dumneavoastră timpurie cu ns-3 (de exemplu, „această secțiune de tutorial nu a fost clară...”),
sunt foarte apreciate rapoartele de documentație învechită etc.

tutorial Organizație
Tutorialul presupune că utilizatorii noi ar putea urma inițial o cale precum următoarea:

· Încercați să descărcați și să creați o copie;

· Încercați să rulați câteva exemple de programe;

· Uitați-vă la ieșirea de simulare și încercați să o ajustați.

Drept urmare, am încercat să organizăm tutorialul de-a lungul secvențelor largi de mai sus
evenimente.

RESURSE


web
Există mai multe resurse importante dintre care oricare ns-3 utilizatorul trebuie să fie conștient. Web-ul principal
site-ul este situat la http://www.nsnam.org și oferă acces la informații de bază despre
ns-3 sistem. Documentația detaliată este disponibilă prin intermediul site-ului web principal la
http://www.nsnam.org/documentation/. De asemenea, puteți găsi documente referitoare la sistem
arhitectura din aceasta pagina.

Există un Wiki care completează principalul ns-3 site-ul web pe care îl veți găsi la
http://www.nsnam.org/wiki/. Veți găsi aici întrebări frecvente pentru utilizatori și dezvoltatori, precum și
ghiduri de depanare, cod contribuit de terți, lucrări etc.

Codul sursă poate fi găsit și răsfoit la http://code.nsnam.org/. Acolo vei gasi
arborele de dezvoltare curent din depozitul numit ns-3-dev. Lansări anterioare și
Acolo pot fi găsite și depozite experimentale ale dezvoltatorilor de bază.

ager
Sistemele software complexe au nevoie de o modalitate de a gestiona organizația și modificările aduse
codul și documentația de bază. Există multe modalități de a realiza această ispravă și este posibil
am auzit de unele dintre sistemele care sunt utilizate în prezent pentru a face acest lucru. Concurenta
Version System (CVS) este probabil cel mai cunoscut.

ns-3 proiectul folosește Mercurial ca sistem de management al codului sursă. Deși nu
trebuie să știți multe despre Mercurial pentru a finaliza acest tutorial, vă recomandăm
familiarizarea cu Mercurial și utilizarea acestuia pentru a accesa codul sursă. Mercurial are o
site web la http://www.selenic.com/mercurial/, din care puteți obține binar sau sursă
versiuni ale acestui sistem de management al configurației software (SCM). Selenic (dezvoltatorul
de Mercurial) oferă, de asemenea, un tutorial la
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/, și un ghid de pornire rapidă la
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.

De asemenea, puteți găsi informații vitale despre utilizarea Mercurial și ns-3 pe principal ns-3 web
site-ul.

waf
Odată ce ați descărcat codul sursă în sistemul dvs. local, va trebui să îl compilați
sursă pentru a produce programe utilizabile. La fel ca și în cazul managementului codului sursă, acolo
sunt multe instrumente disponibile pentru a îndeplini această funcție. Probabil cea mai cunoscută dintre acestea
instrumente este face. Pe lângă faptul că este cel mai cunoscut, face este probabil cel mai dificil
de utilizat într-un sistem foarte mare și foarte configurabil. Din această cauză, multe alternative
A fost dezvoltat. Recent, aceste sisteme au fost dezvoltate folosind Python
limba.

Sistemul de construcție Waf este utilizat pe ns-3 proiect. Este unul din noua generație de
Sisteme de construcție bazate pe Python. Nu va trebui să înțelegeți niciun Python pentru a construi
existent ns-3 sistemului.

Pentru cei interesați de detaliile sângeroase ale Waf, site-ul web principal poate fi găsit la
http://code.google.com/p/waf/.

Dezvoltare Mediu inconjurator
După cum am menționat mai sus, scripting în ns-3 se face în C++ sau Python. Cele mai multe dintre ns-3 API este
disponibil în Python, dar modelele sunt scrise în C++ în ambele cazuri. Un lucru
cunoștințele despre C++ și conceptele orientate pe obiecte sunt presupuse în acest document. Noi vom lua
ceva timp pentru a trece în revistă unele dintre conceptele mai avansate sau, eventual, limbajul necunoscut
caracteristici, expresii și modele de design așa cum apar. Nu vrem acest tutorial
transformăm într-un tutorial C++, totuși, așa că ne așteptăm la o comandă de bază a limbajului.
Există un număr aproape inimaginabil de surse de informații despre C++ disponibile pe
web sau în tipărire.

Dacă sunteți nou în C++, poate doriți să găsiți o carte sau un site web bazat pe tutoriale sau cărți de bucate
și studiați cel puțin caracteristicile de bază ale limbii înainte de a continua. Pentru
instanță, acest tutorial.

ns-3 sistemul folosește mai multe componente ale „lanțului de instrumente” GNU pentru dezvoltare. A
lanțul de instrumente software este setul de instrumente de programare disponibile în mediul dat. Pentru
o revizuire rapidă a ceea ce este inclus în lanțul de instrumente GNU vezi,
http://en.wikipedia.org/wiki/GNU_toolchain. ns-3 folosește gcc, GNU binutils și gdb.
Cu toate acestea, nu folosim instrumentele sistemului GNU build, nici make sau autotools. Folosim Waf
pentru aceste funcții.

De obicei un ns-3 autorul va lucra în Linux sau într-un mediu asemănător Linux. Pentru cei
rulând sub Windows, există medii care simulează mediul Linux
diverse grade. The ns-3 proiectul a fost susținut în trecut (dar nu în prezent).
dezvoltare în mediul Cygwin pentru acești utilizatori. Vedea http://www.cygwin.com/ pentru
detalii despre descărcare și vizitați ns-3 wiki pentru mai multe informații despre Cygwin și
ns-3. MinGW nu este în prezent acceptat oficial. O altă alternativă la Cygwin este să
instalați un mediu de mașină virtuală, cum ar fi serverul VMware și instalați un virtual Linux
mașină.

Priză Programare
Vom presupune o facilitate de bază cu API-ul Berkeley Sockets în exemplele utilizate în aceasta
tutorial. Dacă sunteți nou la socketuri, vă recomandăm să examinați API-ul și unele utilizări obișnuite
cazuri. Pentru o bună imagine de ansamblu asupra programării socket-urilor TCP/IP vă recomandăm TCP / IP Sockets in
C, Donahoo si Calvert.

Există un site web asociat care include sursa pentru exemplele din carte, care
puteti gasi la: http://cs.baylor.edu/~donahoo/practical/CSockets/.

Dacă înțelegeți primele patru capitole ale cărții (sau pentru cei care nu au acces
la o copie a cărții, clienții și serverele echo afișate pe site-ul web de mai sus).
fiți în formă pentru a înțelege tutorialul. Există o carte similară despre Multicast
Prize, multicast Prize, Makofske si Almeroth. care acoperă materialul de care este posibil să aveți nevoie
înțelegeți dacă vă uitați la exemplele multicast din distribuție.

PRIMII ÎNCEPUT


Această secțiune are ca scop aducerea unui utilizator într-o stare de lucru începând cu o mașină care
poate să nu fi avut niciodată ns-3 instalat. Acesta acoperă platformele acceptate, cerințele preliminare, modalitățile de a face acest lucru
obține ns-3, moduri de a construi ns-3, și modalități de a verifica crearea și rularea programelor simple.

Descriere
ns-3 este construit ca un sistem de biblioteci software care lucrează împreună. Programele utilizator pot fi
scris care face legătura cu (sau importă din) aceste biblioteci. Programele utilizatorului sunt scrise
fie limbajele de programare C++ sau Python.

ns-3 este distribuit ca cod sursă, ceea ce înseamnă că sistemul țintă trebuie să aibă un
mediu de dezvoltare software pentru a construi mai întâi bibliotecile, apoi a construi utilizatorul
programul. ns-3 ar putea fi distribuite în principiu ca biblioteci pre-construite pentru selectate
sisteme, iar în viitor poate fi distribuit astfel, dar în prezent, mulți utilizatori
chiar își fac treaba prin editare ns-3 în sine, deci având codul sursă în preajmă pentru a reconstrui
bibliotecile sunt utile. Dacă cineva ar dori să se angajeze să facă preconstruit
biblioteci și pachete pentru sisteme de operare, vă rugăm să contactați corespondența ns-developers
listă.

În cele ce urmează, ne vom uita la două moduri de descărcare și creare ns-3. Primul este
pentru a descărca și a crea o versiune oficială de pe site-ul web principal. Al doilea este să aducă
și construiți copii de dezvoltare ale ns-3. Vom parcurge ambele exemple de la instrumente
implicate sunt ușor diferite.

Descărcarea ns-3
ns-3 sistemul în ansamblu este un sistem destul de complex și are o serie de dependențe de
alte componente. Împreună cu sistemele cu care cel mai probabil te vei ocupa în fiecare zi (
GNU toolchain, Mercurial, un editor de text) va trebui să vă asigurați că un număr de
biblioteci suplimentare sunt prezente pe sistemul dumneavoastră înainte de a continua. ns-3 oferă un wiki
pagină care include pagini cu multe sugestii și sfaturi utile. O astfel de pagină este
Pagina „Instalare”, http://www.nsnam.org/wiki/Installation.

Secțiunea „Condiții preliminare” a acestei pagini wiki explică ce pachete sunt necesare
suport comun ns-3 opțiuni și oferă, de asemenea, comenzile folosite pentru a le instala
variantele comune de Linux. Utilizatorii Cygwin vor trebui să utilizeze programul de instalare Cygwin (dacă sunteți un
Utilizator Cygwin, l-ați folosit pentru a instala Cygwin).

Poate doriți să profitați de această ocazie pentru a explora ns-3 wiki un pic din moment ce chiar există
o multime de informatii acolo.

Din acest punct înainte, vom presupune că cititorul lucrează în Linux sau a
Mediu de emulare Linux (Linux, Cygwin etc.) și are instalat lanțul de instrumente GNU și
verificate împreună cu condițiile prealabile menționate mai sus. De asemenea, vom presupune că
aveți Mercurial și Waf instalate și rulează pe sistemul țintă.

ns-3 codul este disponibil în depozitele Mercurial de pe server http://code.nsnam.org.
De asemenea, puteți descărca o versiune tarball de la http://www.nsnam.org/release/, sau poți lucra
cu depozite folosind Mercurial. Vă recomandăm să utilizați Mercurial, cu excepția cazului în care există un bun
motiv pentru a nu. Consultați sfârșitul acestei secțiuni pentru instrucțiuni despre cum să obțineți un tarball
eliberare.

Cel mai simplu mod de a începe să utilizați depozitele Mercurial este să utilizați ns-3-alinonă
mediu inconjurator. Acesta este un set de scripturi care gestionează descărcarea și construirea
diverse subsisteme ale ns-3 Pentru dumneavoastră. Vă recomandăm să începeți ns-3 lucrează în asta
mediu. (envrironment)

O practică este să creați un director numit spațiu de lucru în directorul de acasă sub care
se pot păstra depozitele locale Mercurial. Orice nume de director va funcționa, dar vom presupune
acea spațiu de lucru este folosit aici (notă: odihnă poate fi folosit și în unele documentații ca un
exemplu nume director).

Descărcarea ns-3 Utilizarea a tarball
Un tarball este un format special de arhivă software în care sunt incluse mai multe fișiere
împreună și arhiva eventual comprimată. ns-3 versiunile de software sunt furnizate prin intermediul a
tarball descărcabil. Procesul de descărcare ns-3 via tarball este simplu; tu doar
trebuie să alegeți o versiune, să o descărcați și să o decomprimați.

Să presupunem că dvs., ca utilizator, doriți să construiți ns-3 într-un director local numit
spațiu de lucru. Dacă adoptați spațiu de lucru abordare director, puteți obține o copie a unei ediții
tastând următoarele în shell-ul dvs. Linux (înlocuiți numerele de versiune corespunzătoare,
desigur):

$ cd
$ mkdir spațiu de lucru
$ cd spațiu de lucru
$wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ tar xjf ns-allinone-3.22.tar.bz2

Dacă te schimbi în director ns-alinona-3.22 ar trebui să vedeți o serie de fișiere:

$ls
bake constante.py ns-3.22 README
build.py netanim-3.105 pybindgen-0.16.0.886 util.py

Acum sunteți gata să construiți baza ns-3 distribuție.

Descărcarea ns-3 Utilizarea Coace
Bake este un instrument de integrare și construcție distribuită, dezvoltat pentru ns-3 proiect.
Bake poate fi folosit pentru a prelua versiunile de dezvoltare ale ns-3 software, și pentru a descărca și
construiți extensii la bază ns-3 distribuție, cum ar fi executarea directă a codului
mediu, Network Simulation Cradle, capacitatea de a crea noi legături Python și altele.

Recent ns-3 versiuni, Bake a fost inclus în tarball-ul de lansare. Configurația
fișierul inclus în versiunea lansată va permite să descărcați orice software care a fost
curent la momentul lansării. Aceasta este, de exemplu, versiunea de Bake care este
distribuit cu ns-3.21 eliberarea poate fi folosită pentru a prelua componente pentru asta ns-3 eliberaţi
sau mai devreme, dar nu poate fi folosit pentru a prelua componente pentru versiuni ulterioare (cu excepția cazului în care
bakeconf.xml fișierul este actualizat).

De asemenea, puteți obține cea mai recentă copie a coace tastând următoarele în Linux
shell (presupunând că ați instalat Mercurial):

$ cd
$ mkdir spațiu de lucru
$ cd spațiu de lucru
clona $ hg http://code.nsnam.org/bake

Pe măsură ce se execută comanda hg (Mercurial), ar trebui să vedeți ceva de genul următor
afișat,

...
director de destinație: coacere
solicitând toate modificările
adăugarea seturilor de modificări
adăugarea de manifeste
adăugarea modificărilor de fișiere
a adăugat 339 de seturi de modificări cu 796 de modificări la 63 de fișiere
actualizare la ramura implicită
45 de fișiere actualizate, 0 fișiere îmbinate, 0 fișiere eliminate, 0 fișiere nerezolvate

După finalizarea comenzii de clonare, ar trebui să aveți un director numit coace, conținuturile
dintre care ar trebui să arate ceva de genul următor:

$ls
bake bakeconf.xml doc generate-binary.py TODO
bake.py exemple de testare

Observați că tocmai ați descărcat niște scripturi Python și un modul Python numit
coace. Următorul pas va fi să folosiți acele scripturi pentru a descărca și a construi ns-3
distribuție la alegere.

Există câteva obiective de configurare disponibile:

1. ns-3.22: modulul corespunzător lansării; va descărca componente similare
la eliberarea tarball.

2. ns-3-dev: un modul similar, dar folosind arborele de cod de dezvoltare

3. ns-alinona-3.22: modulul care include alte caracteristici opționale, cum ar fi clic
rutare, flux deschis pentru ns-3, și leagănul de simulare a rețelei

4. ns-3-alinonă: similar cu versiunea lansată a modulului allinone, dar pt
cod de dezvoltare.

Instantaneul actual al dezvoltării (nelansat) al ns-3 poate fi găsit la
http://code.nsnam.org/ns-3-dev/. Dezvoltatorii încearcă să păstreze aceste depozite în
stări consistente, de lucru, dar se află într-o zonă de dezvoltare cu cod nelansat
prezent, așa că poate doriți să vă gândiți să rămâneți cu o versiune oficială dacă nu aveți nevoie
caracteristici nou introduse.

Puteți găsi cea mai recentă versiune a codului fie prin inspecția listei de depozite
sau mergând la „ns-3 Lansări" pagina web și făcând clic pe linkul celei mai recente versiuni.
Vom continua în acest exemplu tutorial cu ns-3.22.

Acum vom folosi instrumentul de coacere pentru a trage în jos diferitele bucăți de ns-3 vei fi
folosind. Mai întâi, vom spune câteva cuvinte despre rularea coacerii.

bake funcționează prin descărcarea pachetelor sursă într-un director sursă și instalarea
biblioteci într-un director de compilare. bake poate fi rulat prin referire la binar, dar dacă unul
alege să ruleze bake din afara directorului în care a fost descărcat, este recomandabil
pentru a pune bake în calea dvs., cum urmează (exemplul Linux bash shell). În primul rând, schimbare
în directorul „coace”, apoi setați următoarele variabile de mediu

$ export BAKE_HOME=`pwd`
$ export PATH=$PATH:$BAKE_HOME:$BAKE_HOME/build/bin
$ export PYTHONPATH=$PYTHONPATH:$BAKE_HOME:$BAKE_HOME/build/lib

Acest lucru va pune programul bake.py în calea shell-ului și va permite altor programe
găsiți executabile și biblioteci create de bake. Deși mai multe cazuri de utilizare a coacerii nu
necesită setarea PATH și PYTHONPATH ca mai sus, versiuni complete de ns-3-allinone (cu
pachete opționale) fac de obicei.

Intră în directorul spațiului de lucru și tastați următoarele în shell:

$ ./bake.py configure -e ns-3.22

Apoi, îi vom cere pe bake să verifice dacă avem suficiente instrumente pentru a descărca diverse componente.
Tip:

$ ./bake.py verifica

Ar trebui să vezi ceva de genul următor,

> Python - OK
> Compilatorul GNU C++ - OK
> Mercurial - OK
> CVS - OK
> GIT - OK
> Bazar - OK
> Instrument gudron - OK
> Instrumentul de dezarhivare - OK
> Instrumentul Unrar - lipsește
> Utilitar de compresie a datelor 7z - OK
> Utilitar de compresie a datelor XZ - OK
> Faceți - OK
> cMake - OK
> instrument de corecție - OK
> instrument autoreconf - OK

> Calea căutată pentru instrumente: /usr/lib64/qt-3.3/bin /usr/lib64/ccache
/ / Local / bin usr / cos / usr / bin / usr / local / sbin / usr / sbin / sbin
/home/tomh/bină de gunoi

În special, instrumentele de descărcare precum Mercurial, CVS, GIT și Bazaar sunt principalele noastre
preocupări în acest moment, deoarece ne permit să preluăm codul. Vă rugăm să instalați lipsă
instrumente în această etapă, în modul obișnuit pentru sistemul dvs. (dacă puteți) sau contactați
administratorul de sistem după cum este necesar pentru a instala aceste instrumente.

Apoi, încercați să descărcați software-ul:

$ ./bake.py descărcare

ar trebui să producă ceva de genul:

>> Căutarea dependenței de sistem pygoocanvas - OK
>> Se caută dependența de sistem python-dev - OK
>> Căutarea dependenței de sistem pygraphviz - OK
>> Se descarcă pybindgen-0.16.0.886 - OK
>> Se caută dependența de sistem g++ - OK
>> Se caută dependența de sistem qt4 - OK
>> Se descarcă netanim-3.105 - OK
>> Se descarcă ns-3.22 - OK

Cele de mai sus sugerează că au fost descărcate trei surse. Verifică sursă director
acum și tastați ls; ar trebui sa vada:

$ls
netanim-3.105 ns-3.22 pybindgen-0.16.0.886

Acum sunteți gata să construiți ns-3 distribuție.

Clădire ns-3
Clădire cu construi.py
Când lucrați dintr-un tarball eliberat, prima dată când construiți ns-3 proiect pe care îl poți
construi folosind un program convenabil găsit în toate intr-unul director. Acest program este numit
construi.py. Acest program va configura proiectul pentru dvs. cel mai frecvent
mod util. Cu toate acestea, vă rugăm să rețineți că o configurație mai avansată și să lucrați cu ns-3 voi
implică de obicei folosirea nativului ns-3 build system, Waf, care va fi introdus mai târziu în acest articol
tutorial.

Dacă ați descărcat folosind un tarball, ar trebui să aveți un director numit ceva de genul
ns-alinona-3.22 în conformitate cu dvs. ~/spațiu de lucru director. Introduceți următoarele:

$ ./build.py --enable-examples --enable-tests

Pentru că lucrăm cu exemple și teste în acest tutorial și pentru că nu sunt
construit implicit în ns-3, argumentele pentru build.py îi spune să le construiască pentru noi. The
programul stabilește, de asemenea, toate modulele disponibile. Mai târziu, puteți construi ns-3
fără exemple și teste, sau eliminați modulele care nu sunt necesare pentru munca dvs.,
daca doresti.

Veți vedea o mulțime de mesaje tipice de ieșire ale compilatorului afișate pe măsură ce se construiește scriptul de compilare
diferitele piese pe care le-ați descărcat. În cele din urmă, ar trebui să vedeți următoarele:

Waf: Se părăsește directorul `/path/to/workspace/ns-allinone-3.22/ns-3.22/build'
„construire” finalizată cu succes (6m25.032s)

Module construite:
aplicații de antenă aodv
bridge buildings config-magazin
core csma csma-layout
dsdv dsr energie
fd-net-device monitorizare flux internet
lr-wpan lte mesh
mobilitate mpi netanim (fără Python)
rețea nix-vector-routing olsr
propagare punct la punct punct la punct
statistici de spectru sixlowpan
topologie de testare a podului (fără Python) citire
un val de dispozitiv virtual-net
wifi wimax

Modulele nu sunt construite (consultați tutorialul ns-3 pentru explicații):
brite click openflow
vizualizator

Ieșim din directorul `./ns-3.22'

Referitor la partea despre modulele neconstruite:

Modulele nu sunt construite (consultați tutorialul ns-3 pentru explicații):
brite click openflow
vizualizator

Asta înseamnă doar că unii ns-3 modulele care au dependențe de biblioteci externe nu pot
au fost construite sau că configurația a cerut în mod special să nu le construiască. Da
nu înseamnă că simulatorul nu s-a construit cu succes sau că va furniza greșit
rezultate pentru modulele enumerate ca fiind construite.

Clădire cu coace
Dacă ați folosit bake mai sus pentru a prelua codul sursă din depozitele de proiecte, puteți continua
folosește-l pentru a construi ns-3. Tip

$ ./bake.py build

și ar trebui să vezi ceva de genul:

>> Construire pybindgen-0.16.0.886 - OK
>> Construire netanim-3.105 - OK
>> Clădirea ns-3.22 - OK

Aluzie: tu poate să de asemenea efectua atât pași, Descarca si construi by apel 'coace.py desfășoară'.

Dacă se întâmplă să fie un eșec, vă rugăm să aruncați o privire la ce spune următoarea comandă
tu; poate oferi un indiciu cu privire la o dependență lipsă:

$ ./bake.py show

Aceasta va enumera diferitele dependențe ale pachetelor pe care încercați să le construiți.

Clădire cu waf
Până în acest moment, am folosit fie construi.py scenariul sau coace instrument, a obține
început cu construirea ns-3. Aceste instrumente sunt utile pentru construcție ns-3 și sprijin
biblioteci și apelează la ns-3 director pentru a apela instrumentul de compilare Waf pentru a face
clădire propriu-zisă. Majoritatea utilizatorilor trece rapid la utilizarea Waf direct pentru a configura și
construi ns-3. Deci, pentru a continua, vă rugăm să vă schimbați directorul de lucru în ns-3 director
pe care le-ați construit inițial.

Nu este strict obligatoriu în acest moment, dar va fi valoros să faceți un mic ocol
și vedeți cum să faceți modificări în configurația proiectului. Probabil cel mai mult
modificarea utilă a configurației pe care o puteți face va fi construirea versiunii optimizate a
cod. În mod implicit, ați configurat proiectul pentru a construi versiunea de depanare. Să spunem
proiectul pentru a realiza o construcție optimizată. Pentru a-i explica lui Waf că ar trebui să fie optimizat
versiuni care includ exemplele și testele, va trebui să executați următoarele
comenzi:

$ ./waf curat
$ ./waf --build-profile=optimized --enable-examples --enable-tests configure

Acest lucru rulează Waf din directorul local (care este oferit ca o comoditate pentru dvs.).
Prima comandă pentru curățarea versiunii anterioare nu este de obicei strict necesară, dar
este o practică bună (dar vezi Construi Profiluri, mai jos); va elimina cele construite anterior
biblioteci și fișiere obiect găsite în director construi/. Când proiectul este reconfigurat
iar sistemul de compilare verifică diferite dependențe, ar trebui să vedeți o ieșire care arată
similar cu următoarele:

Setarea top la : .
Pornind de la: construi
Se verifică „gcc” (compilator c): /usr/bin/gcc
Se verifică versiunea cc: 4.2.1
Se verifică „g++” (compilator c++): /usr/bin/g++
Verificarea amplificare include: 1_46_1
Verificarea boost libs: ok
Verificarea legăturii de amplificare: ok
Se verifică locația clicului: nu a fost găsit
Verificarea programului pkg-config: /sw/bin/pkg-config
Verificarea „gtk+-2.0” >= 2.12: da
Verificarea pentru „libxml-2.0” >= 2.7: da
Se verifică tipul uint128_t : nu a fost găsit
Se verifică tipul __uint128_t: da
Verificarea implementării de înaltă precizie: întreg de 128 de biți (implicit)
Verificarea antetului stdint.h: da
Verificarea antetului inttypes.h: da
Verificarea antetului sys/inttypes.h: nu a fost găsit
Verificarea antetului sys/types.h: da
Verificarea antetului sys/stat.h: da
Se verifică antetul dirent.h: da
Verificarea antetului stdlib.h: da
Se verifică semnalul antetului.h: da
Se verifică antetul pthread.h: da
Verificarea antetului stdint.h: da
Verificarea antetului inttypes.h: da
Verificarea antetului sys/inttypes.h: nu a fost găsit
Verificarea bibliotecii rt: nu a fost găsită
Se verifică antetul netpacket/packet.h : nu a fost găsit
Verificarea antetului sys/ioctl.h: da
Se verifică antetul net/if.h : nu a fost găsit
Verificarea antetului net/ethernet.h: da
Verificarea antetului linux/if_tun.h: nu a fost găsit
Se verifică antetul netpacket/packet.h : nu a fost găsit
Se verifică locația NSC: nu a fost găsită
Verificare pentru „mpic++”: da
Verificarea pentru „sqlite3”: da
Verificarea antetului linux/if_tun.h: nu a fost găsit
Verificarea programului sudo: /usr/bin/sudo
Verificarea programului valgrind: /sw/bin/valgrind
Verificare pentru „gsl”: da
Se verifică semnalul de compilare -Wno-error=deprecated-d... suport: ok
Se verifică semnalul de compilare -Wno-error=deprecated-d... suport: ok
Se verifică steag de compilare -fstrict-aliasing... suport: ok
Se verifică steag de compilare -fstrict-aliasing... suport: ok
Se verifică semnalul de compilare -Wstrict-aliasing... suport: ok
Se verifică semnalul de compilare -Wstrict-aliasing... suport: ok
Verificarea programului doxygen: /usr/local/bin/doxygen
---- Rezumatul caracteristicilor opționale NS-3:
Build profile: debug
Build director: build
Legături Python: activat
Integrare BRITE: nu este activată (BRITE nu este activată (vezi opțiunea --with-brite))
NS-3 Faceți clic pe Integrare: nu este activat (nsclick nu este activat (vezi opțiunea --with-nsclick))
GtkConfigStore : activat
XmlIo : activat
Threading Primitive: activat
Simulator în timp real: activat (librt nu este disponibil)
Dispozitiv net emulat : activat ( include nedetectat)
Descriptor de fișier NetDevice : activat
Atingeți FdNetDevice : nu este activat (necesită linux/if_tun.h)
Emulare FdNetDevice: nu este activată (necesită netpacket/packet.h)
PlanetLab FdNetDevice : neactivat (sistemul de operare PlanetLab nu a fost detectat (vezi opțiunea --force-planetlab))
Network Simulation Cradle : nu este activat (NSC nu a fost găsit (vezi opțiunea --with-nsc))
Suport MPI: activat
Integrare NS-3 OpenFlow: nu este activată (bibliotecile de amplificare necesare nu au fost găsite, lipsesc: sistem, semnale, sistem de fișiere)
Ieșirea datelor statistici SQLlite: activată
Atingeți Bridge : nu este activat ( include nedetectat)
Vizualizatorul PyViz: activat
Utilizați sudo pentru a seta suid bit: neactivat (opțiunea --enable-sudo nu este selectată)
Teste de construcție: activate
Exemple de construire: activat
Biblioteca științifică GNU (GSL) : activată
„configure” s-a terminat cu succes (1.944s)

Observați ultima parte a rezultatului de mai sus. niste ns-3 opțiunile nu sunt activate implicit sau
necesită sprijin din partea sistemului de bază pentru a funcționa corect. De exemplu, pentru a activa
XmlTo, biblioteca libxml-2.0 trebuie găsită pe sistem. Dacă această bibliotecă nu ar fi
găsit, corespunzătoare ns-3 caracteristica nu ar fi activată și ar fi un mesaj
afișat. Mai rețineți că există o caracteristică pentru a utiliza programul sudo pentru a stabili sudul
un pic din anumite programe. Acest lucru nu este activat în mod implicit și, prin urmare, această caracteristică este raportată
ca „neactivat”.

Acum mergeți mai departe și reveniți la versiunea de depanare care include exemplele și testele.

$ ./waf curat
$ ./waf --build-profile=debug --enable-examples --enable-tests configure

Sistemul de compilare este acum configurat și puteți construi versiunile de depanare ale ns-3
programe prin simpla tastare

$ ./waf

Bine, scuze, te-am pus să construiești ns-3 face parte din sistem de două ori, dar acum știi cum
modificați configurația și construiți codul optimizat.

Scriptul build.py discutat mai sus acceptă și --activați-exemple si enable-tests
argumente, dar, în general, nu susține direct alte opțiuni waf; de exemplu, aceasta
nu va funcționa:

$ ./build.py --disable-python

va avea ca rezultat

build.py: eroare: nu există o astfel de opțiune: --disable-python

Cu toate acestea, operatorul special -- poate fi folosit pentru a trece opțiuni suplimentare către waf, deci
în loc de cele de mai sus, vor funcționa următoarele:

$ ./build.py -- --disable-python

deoarece generează comanda de bază ./waff configura --disable-python.

Iată câteva sfaturi introductive despre Waf.

Configurați Raport Construi
Unele comenzi Waf sunt semnificative doar în timpul fazei de configurare, iar unele comenzi sunt
valabil în faza de construire. De exemplu, dacă doriți să utilizați funcțiile de emulare ale
ns-3, este posibil să doriți să activați setarea bitului suid folosind sudo așa cum este descris mai sus. Acest
se dovedește a fi o comandă în timp de configurare și, astfel, puteți reconfigura folosind
următoarea comandă care include și exemplele și testele.

$ ./waf configure --enable-sudo --enable-examples --enable-tests

Dacă faceți acest lucru, Waf va fi rulat sudo pentru a schimba programele creatoare de socket ale
cod de emulare pentru a rula ca root.

Există multe alte opțiuni de configurare și de construire disponibile în Waf. Pentru a le explora
opțiuni, tastați:

$ ./waf --ajutor

Vom folosi unele dintre comenzile legate de testare în secțiunea următoare.

Construi Profiluri
Am văzut deja cum puteți configura Waf pentru depana or optimizate construieste:

$ ./waf --build-profile=debug

Există, de asemenea, un profil de construcție intermediar, eliberaţi. -d este un sinonim pentru
--build-profile.

În mod implicit, Waf pune artefactele de construcție în construi director. Puteți specifica a
director de ieșire diferit cu --afara opțiune, de ex

$ ./waf configure --out=foo

Combinarea acestui lucru cu profilele de compilare vă permite să comutați între diferitele opțiuni de compilare
intr-un mod curat:

$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf build
...
$ ./waf configure --build-profile=optimized --out=build/optimized
$ ./waf build
...

Acest lucru vă permite să lucrați cu mai multe versiuni, mai degrabă decât să o suprascrieți întotdeauna pe ultima
construi. Când comutați, Waf va compila doar ceea ce trebuie, în loc să recompileze
Tot.

Când schimbați astfel de profiluri, trebuie să aveți grijă să oferiți același lucru
parametrii de configurare de fiecare dată. Poate fi convenabil să definiți un mediu
variabile pentru a vă ajuta să evitați greșelile:

$ export NS3CONFIG="--enable-examples --enable-tests"
$ export NS3DEBUG="--build-profile=debug --out=build/debug"
$ export NS3OPT=="--build-profile=optimized --out=build/optimized"

$ ./waf configura $NS3CONFIG $NS3DEBUG
$ ./waf build
...
$ ./waf configura $NS3CONFIG $NS3OPT
$ ./waf build

Compilatoare
În exemplele de mai sus, Waf folosește compilatorul GCC C++, g ++, pentru constructii ns-3. Cu toate acestea,
este posibil să schimbați compilatorul C++ folosit de Waf prin definirea CXX mediu inconjurator
variabil. De exemplu, pentru a utiliza compilatorul Clang C++, clang++,

$ CXX="clang++" ./waf configure
$ ./waf build

De asemenea, se poate configura Waf pentru a face compilare distribuită distcc intr-un mod similar:

$ CXX="distcc g++" ./waf configure
$ ./waf build

Mai multe informații despre distcc și o compilație distribuită poate fi găsită pe ea proiect pagină în
Sectiunea de documentatie.

Instalare
Waf poate fi folosit pentru a instala biblioteci în diferite locuri ale sistemului. Implicit
locația în care sunt construite bibliotecile și executabilele este în construi director, și pentru că
Waf știe locația acestor biblioteci și executabile, nu este necesar să se instaleze
bibliotecile din altă parte.

Dacă utilizatorii aleg să instaleze lucruri în afara directorului de compilare, utilizatorii pot emite fișierul
./waff instala comanda. În mod implicit, prefixul pentru instalare este / Usr / local, asa de ./waff
instala va instala programe în / / Local / bin usr, biblioteci în / Usr / local / lib și
anteturi în /usr/local/include. Privilegiile de superutilizator sunt de obicei necesare pentru a instala în
prefixul implicit, deci comanda tipică ar fi sudo ./waff instala. La alergare
programe cu Waf, Waf va prefera mai întâi să folosească biblioteci partajate în directorul de compilare,
apoi va căuta biblioteci în calea bibliotecii configurată în mediul local. Asa de
atunci când instalați biblioteci în sistem, este o bună practică să verificați dacă este prevăzut
sunt folosite biblioteci.

Utilizatorii pot alege să instaleze la un prefix diferit prin trecerea --prefix opțiune la
configurați timpul, cum ar fi:

./waf configure --prefix=/opt/local

Dacă mai târziu, după compilare, utilizatorul emite fișierul ./waff instala comanda, prefixul /opt/local
va fi folosit.

./waff curat comanda ar trebui utilizată înainte de a reconfigura proiectul dacă Waf va fi
folosit pentru a instala lucruri la un prefix diferit.

Pe scurt, nu este necesar să suni ./waff instala să utilizeze ns-3. Majoritatea utilizatorilor nu o vor face
nevoie de această comandă, deoarece Waf va prelua bibliotecile curente din construi director,
dar unii utilizatori ar putea considera că este util dacă cazul lor de utilizare implică lucrul cu programe din exterior
a ns-3 director.

O waf
Există un singur script Waf, la nivelul superior al ns-3 arborele sursă. Pe măsură ce lucrezi, tu
s-ar putea să te trezești petrecând mult timp în zgârietură/, sau adânc în src/..., și nevoia
invocă Waf. Vă puteți aminti unde vă aflați și să invocați Waf astfel:

$ ../../../waf ...

dar asta devine obositor și predispus la erori și există soluții mai bune.

Dacă ai tot ns-3 depozit, această mică bijuterie este un început:

$ cd $(hg root) && ./waf ...

Și mai bine este să definiți aceasta ca o funcție shell:

$ function waff { cd $(hg root) && ./waf $* ; }

$ waff build

Dacă aveți doar tarball, o variabilă de mediu vă poate ajuta:

$ export NS3DIR="$PWD"
$ function waff { cd $NS3DIR && ./waf $* ; }

$ cd scratch
$ waff build

Ar putea fi tentant într-un director de module să adăugați un trivial WAF scenariu pe linia lui
Exec ../../waf. Te rog nu. Este confuz pentru nou-veniți, iar atunci când este prost
duce la erori subtile de construcție. Soluțiile de mai sus sunt calea de urmat.

Testarea ns-3
Puteți rula testele unitare ale ns-3 distribuție prin rularea ./test.py -c CORE
scenariu:

$ ./test.py -c core

Aceste teste sunt efectuate în paralel de Waf. Ar trebui să vezi în cele din urmă un raport care spune asta

92 din 92 de teste au trecut (92 au trecut, 0 au eșuat, 0 s-au blocat, 0 erori de valgrind)

Acesta este mesajul important.

Veți vedea, de asemenea, rezultatul rezumat de la Waf și de la runnerul de testare care execută fiecare test,
care de fapt va arăta ceva de genul:

Waf: se introduce în directorul `/path/to/workspace/ns-3-allinone/ns-3-dev/build'
Waf: Se părăsește directorul `/path/to/workspace/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (1.799s)

Module construite:
aodv aplicații bridge
faceți clic pe config-store core
csma csma-layout dsdv
monitor de flux de energie emu
internet lte mesh
mobilitate mpi netanim
rețea nix-vector-routing ns3tcp
ns3wifi olsr openflow
propagare punct la punct punct la punct
statistici de spectru tap-bridge
instrumente de testare șablon
Citirea topologiei într-un dispozitiv virtual-net
vizualizator wifi wimax

PASS: TestSuite ns3-wifi-interference
PASS: histograma TestSuite

...

PASS: obiect TestSuite
PASS: generatoare de numere aleatoare TestSuite
92 din 92 de teste au trecut (92 au trecut, 0 au eșuat, 0 s-au blocat, 0 erori de valgrind)

Această comandă este de obicei rulată de utilizatori pentru a verifica rapid că un ns-3 distributia are
construit corect. (Rețineți ordinea TRECE: ... liniile pot varia, ceea ce este în regulă. Ceea ce este
important este ca rândul rezumat de la sfârșit să raporteze că toate testele au trecut; niciunul nu a eșuat sau
prăbușit.)

Alergare a Scenariu
De obicei rulăm scripturi sub controlul Waf. Acest lucru permite sistemului de construcție să se asigure
că căile de bibliotecă partajată sunt setate corect și că bibliotecile sunt disponibile la
timpul de rulare. Pentru a rula un program, pur și simplu utilizați --alerga opțiune în Waf. Hai să rulăm ns-3
echivalentul programului omniprezent Hello World, tastând următoarele:

$ ./waf --run hello-simulator

Waf verifică mai întâi pentru a se asigura că programul este construit corect și execută un build if
necesar. Waf execută apoi programul, care produce următoarea ieșire.

Salut Simulator

Felicitări! Acum sunteți utilizator ns-3!

Ce do I do if I nu face vedea il ieșire?

Dacă vedeți mesaje Waf care indică faptul că construirea a fost finalizată cu succes, dar nu
vezi ieșirea „Hello Simulator”, sunt șanse să fi trecut în modul de construire
optimizate în Clădire cu waf secțiunea, dar au ratat schimbarea înapoi la depana Mod.
Toate ieșirile din consolă utilizate în acest tutorial folosesc un special ns-3 componentă de logare care
este util pentru tipărirea mesajelor utilizatorului pe consolă. Ieșirea din această componentă este
este dezactivat automat când compilați cod optimizat -- este „optimizat”. daca tu
nu vedeți rezultatul „Hello Simulator”, introduceți următoarele:

$ ./waf configure --build-profile=debug --enable-examples --enable-tests

pentru a-i spune lui Waf să construiască versiunile de depanare ale ns-3 programe care includ exemplele
si teste. Încă trebuie să creați versiunea reală de depanare a codului tastând

$ ./waf

Acum, dacă rulați salut-simulator program, ar trebui să vedeți rezultatul așteptat.

Program Argumente
Pentru a furniza argumente de linie de comandă unui ns-3 programul folosește acest model:

$ ./waf --run --command-template="%s "

Înlocuiți numele programului dvs. pentru , iar argumentele pentru .
--șablon-comandă argumentul pentru Waf este practic o rețetă pentru construirea realului
linia de comandă ar trebui să o folosească Waf pentru a executa programul. Waf verifică dacă build-ul este
complet, setează căile de bibliotecă partajată, apoi invocă executabilul folosind aplicația furnizată
șablon de linie de comandă, inserând numele programului pentru %s substituent. (Recunosc asta
este puțin ciudat, dar așa este. Patch-uri binevenite!)

Un alt exemplu deosebit de util este acela de a rula o suită de teste de la sine. Să presupunem că a
testul meu suita de teste există (nu există). Mai sus, am folosit ./test.py script pentru a rula un întreg
o mulțime de teste în paralel, invocând în mod repetat programul de testare real, alergător de încercare.
A invoca alergător de încercare direct pentru un singur test:

$ ./waf --run test-runner --command-template="%s --suite=mytest --verbose"

Aceasta trece argumentele către alergător de încercare program. De cand testul meu nu există, an
va fi generat un mesaj de eroare. Pentru a imprima cele disponibile alergător de încercare opţiuni:

$ ./waf --run test-runner --command-template="%s --help"

Depanarea
A alerga ns-3 programe aflate sub controlul unui alt utilitar, cum ar fi un depanator (de exemplu gDB)
sau verificator de memorie (de exemplu valgrind), folosiți un similar --command-template="..." formular.

De exemplu, pentru a rula dvs ns-3 program salut-simulator cu argumentele în temeiul
gDB depanator:

$ ./waf --run=hello-simulator --command-template="gdb %s --args "

Observați că ns-3 numele programului merge cu --alerga argument și utilitatea de control
(Aici gDB) este primul jeton din --command-template argument. The --args spune gDB
că restul liniei de comandă aparține programului „inferior”. (Niste gDB's
nu inteleg --args caracteristică. În acest caz, omiteți argumentele programului din
--șablon-comandă, și folosiți gDB comandă set args.)

Putem combina această rețetă cu cea anterioară pentru a rula un test sub depanator:

$ ./waf --run test-runner --command-template="gdb %s --args --suite=mytest --verbose"

De lucru director
Waf trebuie să fugă din locația sa din partea de sus a ns-3 copac. Aceasta devine lucrul
directorul în care vor fi scrise fișierele de ieșire. Dar ce se întâmplă dacă vrei să-i păstrezi
il ns-3 arborele sursă? Folosește --cwd argument:

$ ./waf --cwd=...

Poate fi mai convenabil să începeți cu directorul de lucru unde doriți să obțineți rezultat
fișiere, caz în care o mică indirectă poate ajuta:

$ function waff {
CWD="$PWD"
cd $NS3DIR >>/dev/null
./waf --cwd="$CWD" $*
cd - >/dev/null
}

Această decorare a versiunii anterioare salvează directorul de lucru curent, cdlui la
directorul Waf, apoi îi cere lui Waf să schimbe directorul de lucru înapoi celor mântuiți
directorul de lucru curent înainte de a rula programul.

CONCEPTUAL ÎNSCRIERI


Primul lucru pe care trebuie să-l facem înainte de a începe efectiv să privim sau să scriem ns-3 codul este să
explicați câteva concepte de bază și abstracții din sistem. Multe dintre acestea pot apărea
evident pentru unii, dar vă recomandăm să vă faceți timp pentru a citi acest lucru
secțiune doar pentru a vă asigura că începeți pe o bază fermă.

Cheie Abstracții
În această secțiune, vom analiza câțiva termeni care sunt utilizați în mod obișnuit în rețele, dar care au a
sens specific în ns-3.

Nod
În jargonul internetului, un dispozitiv de calcul care se conectează la o rețea se numește a gazdă or
uneori an capăt sistem. pentru că ns-3 este reţea simulator, nu în mod specific an
Internet simulator, nu folosim în mod intenționat termenul gazdă, deoarece este îndeaproape
asociat cu Internetul și protocoalele acestuia. În schimb, folosim și un termen mai generic
folosit de alte simulatoare care își au originea în teoria graficelor --- the nod.

In ns-3 abstractizarea dispozitivului de calcul de bază se numește nod. Această abstractizare este
reprezentat în C++ de către clasă Nod. Nod clasa oferă metode de gestionare a
reprezentări ale dispozitivelor de calcul în simulări.

Ar trebui să te gândești la o Nod ca un computer căruia îi vei adăuga funcționalitate. Unul adaugă
lucruri precum aplicații, stive de protocoale și carduri periferice cu asociate acestora
drivere pentru a permite computerului să facă lucrări utile. Folosim același model de bază în ns-3.

Aplicatii
De obicei, software-ul de calculator este împărțit în două clase mari. Sistem Software organizează
diverse resurse ale computerului, cum ar fi memoria, ciclurile procesorului, disc, rețea etc.,
conform unui model de calcul. De obicei, software-ul de sistem nu utilizează aceste resurse
pentru a îndeplini sarcini care beneficiază direct un utilizator. Un utilizator ar rula de obicei un cerere
care dobândește și utilizează resursele controlate de software-ul de sistem pentru a realiza unele
poartă.

Adesea, linia de separare între software-ul de sistem și aplicația se face la
modificarea nivelului de privilegii care are loc în capcanele sistemului de operare. În ns-3 nu există real
conceptul de sistem de operare și mai ales niciun concept de niveluri de privilegii sau apeluri de sistem.
Avem, totuși, ideea unei aplicații. La fel cum rulează aplicațiile software
computere pentru a îndeplini sarcini în „lumea reală”, ns-3 aplicațiile rulează pe ns-3 Nodurile la
conduce simulări în lumea simulată.

In ns-3 abstracția de bază pentru un program utilizator care generează o anumită activitate să fie
simulată este aplicația. Această abstractizare este reprezentată în C++ de clasă
Aplicatii. Aplicatii clasa oferă metode de gestionare a reprezentărilor de
versiunea noastră a aplicațiilor la nivel de utilizator în simulări. Se așteaptă ca dezvoltatorii să o facă
specializează Aplicatii clasa în sensul de programare orientată pe obiecte pentru a crea noi
aplicatii. În acest tutorial, vom folosi specializările de clasă Aplicatii denumit
UdpEchoClientApplication si UdpEchoServerApplication. După cum vă puteți aștepta, acestea
aplicațiile compun un set de aplicații client/server folosit pentru a genera și a simula simularea
pachete de rețea

Canal
În lumea reală, se poate conecta un computer la o rețea. Adesea mass-media peste care
sunt numite fluxurile de date din aceste rețele canale. Când vă conectați cablul Ethernet la
mufa din perete, vă conectați computerul la o comunicare Ethernet
canal. În lumea simulată a ns-3, se leagă a Nod la un obiect reprezentând a
canal de comunicare. Aici abstracția de bază a subrețelei de comunicații se numește
canal și este reprezentat în C++ de clasă Canal.

Canal clasa oferă metode de gestionare a obiectelor de subrețea de comunicații și
conectarea nodurilor la acestea. Canale poate fi, de asemenea, specializat de dezvoltatori în obiect
sens orientat spre programare. A Canal specializarea poate modela ceva la fel de simplu ca a
sârmă. Specialistul Canal poate modela, de asemenea, lucruri la fel de complicate ca un Ethernet mare
comutator sau spațiu tridimensional plin de obstacole în cazul rețelelor wireless.

Vom folosi versiuni specializate ale Canal denumit CsmaChannel, PointToPointChannel
si WifiChannel în acest tutorial. The CsmaChannel, de exemplu, modelează o versiune a a
subrețea de comunicații care implementează a purtător sens multiplu acces comunicare
mediu. Acest lucru ne oferă o funcționalitate asemănătoare Ethernet.

Net Dispozitiv
Cândva, dacă doreai să conectezi un computer la o rețea, trebuia
cumpărați un anumit tip de cablu de rețea și un dispozitiv hardware numit (în terminologia PC) a
periferic card care trebuia instalat pe computer. Dacă cardul periferic
au implementat o funcție de rețea, au fost numite Carduri de interfață de rețea sau NIC-uri.
Astăzi, majoritatea computerelor vin cu hardware-ul de interfață de rețea încorporat și utilizatorii nu văd
aceste blocuri de construcție.

O NIC nu va funcționa fără un driver software care să controleze hardware-ul. În Unix (sau
Linux), o componentă hardware periferică este clasificată ca a dispozitiv. Dispozitivele sunt controlate
folosind dispozitiv drivere, iar dispozitivele de rețea (NIC) sunt controlate folosind reţea dispozitiv
drivere cunoscut sub numele de net Dispozitive. În Unix și Linux vă referiți la aceste rețele
dispozitive după nume precum eth0.

In ns-3 il net dispozitiv abstractizarea acoperă atât driverul software, cât și cel simulat
hardware. Un dispozitiv net este „instalat” într-un Nod pentru a activa dispozitivul Nod la
comunica cu ceilalti Nodurile în simulare via Canale. La fel ca într-un computer adevărat,
a Nod poate fi conectat la mai multe Canal prin multiple NetDevices.

Abstracția net device este reprezentată în C++ de clasă NetDevice. NetDevice
clasa oferă metode pentru gestionarea conexiunilor la Nod si Canal obiecte; si poate
specializata de dezvoltatori in sensul programarii orientate pe obiecte. Vom folosi
mai multe versiuni specializate ale NetDevice denumit CsmaNetDevice, PointToPointNetDevice,
si Dispozitiv WifiNet în acest tutorial. Așa cum o NIC Ethernet este proiectată să funcționeze cu un
Rețeaua Ethernet, CsmaNetDevice este conceput pentru a lucra cu un CsmaChannel;
PointToPointNetDevice este conceput pentru a lucra cu un PointToPointChannel și WifiNetNevice
este conceput pentru a lucra cu un WifiChannel.

Topologie Ajutoare
Într-o rețea reală, veți găsi computere gazdă cu NIC-uri adăugate (sau încorporate). În ns-3 we
ar spune că vei găsi Nodurile cu atașat NetDevices. Într-o rețea simulată mare
va trebui să aranjați multe conexiuni între Nodurile, NetDevices si Canale.

De când s-a conectat NetDevices la Nodurile, NetDevices la Canale, atribuirea adreselor IP,
etc., sunt sarcini atât de comune în ns-3, oferim ceea ce numim topologie ajutoare pentru a face asta
cat se poate de usor. De exemplu, poate fi nevoie de multe distincte ns-3 operațiunile de bază la
creați un NetDevice, adăugați o adresă MAC, instalați acel dispozitiv net pe un Nod, configurați
stiva de protocoale a nodului, apoi conectați NetDevice la Canal. Chiar mai multe operațiuni
ar fi necesar să se conecteze mai multe dispozitive pe canale multipunct și apoi să se conecteze
rețele individuale împreună în rețele de internet. Oferim obiecte de ajutor de topologie care
combinați aceste multe operații distincte într-un model ușor de utilizat pentru confortul dvs.

A Prenumele ns-3 Scenariu
Dacă ați descărcat sistemul așa cum a fost sugerat mai sus, veți avea o versiune a ns-3 într-un
director numit odihnă sub directorul dvs. de acasă. Schimbați-vă în acel director de lansare și
ar trebui să găsiți o structură de directoare, așa cum urmează:

AUTORI exemple scratch utils waf.bat*
legături LICENSE src utils.py waf-tools
build ns3 test.py* utils.pyc wscript
CHANGES.html README testpy-output VERSION wutils.py
doc RELEASE_NOTES testpy.supp waf* wutils.pyc

Schimbați în exemple/tutorial director. Ar trebui să vedeți un fișier numit mai întâi.cc situat
Acolo. Acesta este un script care va crea o legătură simplă punct la punct între două noduri
și ecou un singur pachet între noduri. Să aruncăm o privire la acea linie de script de
linie, așa că mergeți înainte și deschideți mai întâi.cc în editorul tău preferat.

Boilerplate
Prima linie din fișier este o linie de mod emacs. Aceasta îi spune emacs-ului despre formatare
convențiile (stil de codare) pe care le folosim în codul sursă.

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

Acesta este întotdeauna un subiect oarecum controversat, așa că am putea la fel de bine să-l scoatem din drum
imediat. ns-3 proiectul, la fel ca majoritatea proiectelor mari, a adoptat un stil de codare pentru
pe care trebuie să-l respecte tot codul contribuit. Dacă doriți să contribuiți cu codul dvs. la
proiect, va trebui în cele din urmă să vă conformați ns-3 standard de codare așa cum este descris în
fișierul doc/codingstd.txt sau afișat pe pagina web a proiectului aici.

Vă recomandăm să vă obișnuiți doar cu aspectul și senzația ns-3 codificați și adoptați
acest standard ori de câte ori lucrați cu codul nostru. Toată echipa de dezvoltare și
colaboratorii au făcut-o cu diverse cantități de mormăit. Linia modului emacs de mai sus
face mai ușor să obțineți formatarea corectă dacă utilizați editorul emacs.

ns-3 simulatorul este licențiat folosind licența publică generală GNU. Vei vedea
legalizarea GNU adecvată la capul fiecărui fișier din ns-3 distributie. Adesea tu
va vedea o notificare privind drepturile de autor pentru una dintre instituțiile implicate în ns-3 proiectul de mai sus
textul GPL și un autor enumerat mai jos.

/*
* Acest program este software gratuit; îl puteți redistribui și/sau modifica
* în conformitate cu termenii GNU General Public License versiunea 2 ca
* publicat de Free Software Foundation;
*
* Acest program este distribuit în speranța că va fi util,
* dar FĂRĂ NICIO GARANȚIE; fără nici măcar garanția implicită a
* VANTABILITATE sau ADECVENȚĂ PENTRU UN ANUMIT SCOP. Vezi
* Licență publică generală GNU pentru mai multe detalii.
*
* Ar fi trebuit să primiți o copie a licenței publice generale GNU
* împreună cu acest program; dacă nu, scrieți la Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 SUA
*/

Module Include
Codul propriu-zis începe cu un număr de instrucțiuni include.

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

Pentru a ajuta utilizatorii noștri de scripturi de nivel înalt să facă față numărului mare de fișiere include prezente în
sistemul, grupăm include în funcție de module relativ mari. Oferim un singur
include fișier care va încărca recursiv toate fișierele include utilizate în fiecare modul.
În loc să trebuiască să căutați exact ce antet aveți nevoie și, eventual, trebuie să obțineți un
Numărul corect de dependențe, vă oferim posibilitatea de a încărca un grup de fișiere în mare măsură
granularitatea. Aceasta nu este cea mai eficientă abordare, dar cu siguranță face scrisul
scripturi mult mai ușor.

Fiecare din ns-3 include fișiere este plasat într-un director numit ns3 (sub construcție
director) în timpul procesului de construire pentru a evita coliziunile de nume de fișiere incluse. The
ns3/core-module.h fișierul corespunde modulului ns-3 pe care îl veți găsi în director
src/core în distribuția de lansare descărcată. Dacă enumerați acest director, o veți face
găsiți un număr mare de fișiere antet. Când faci o construcție, Waf va plasa antet public
fișiere într-un fișier ns3 director sub corespunzator construi/depanează or construi/optimizat director
în funcție de configurația dvs. Waf va genera automat un modul include
fișier pentru a încărca toate fișierele de antet publice.

Din moment ce, desigur, urmați acest tutorial religios, deja ați făcut-o
a

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

pentru a configura proiectul pentru a realiza versiuni de depanare care includ exemple și teste.
Veți fi făcut și o

$ ./waf

pentru a construi proiectul. Deci acum dacă te uiți în director ../../build/debug/ns3 tu vei
găsiți cele patru module includ fișiere prezentate mai sus. Puteți arunca o privire asupra conținutului
aceste fișiere și constată că includ toate fișierele de includere publice în fișierele lor
modulele respective.

NS3 Spațiu de nume
Următoarea linie din mai întâi.cc scriptul este o declarație de spațiu de nume.

folosind namespace ns3;

ns-3 proiectul este implementat într-un spațiu de nume C++ numit ns3. Aceasta grupează toate
ns-3-declarații legate într-un domeniu în afara spațiului de nume global, ceea ce sperăm că va ajuta
cu integrare cu alt cod. C++ folosind declarația introduce ns-3 Spațiu de nume
în regiunea declarativă (globală) actuală. Acesta este un mod elegant de a spune asta după
această declarație, nu va trebui să tastați ns3:: operator rezoluție domeniului înainte de toate
il ns-3 cod pentru a-l utiliza. Dacă nu sunteți familiarizat cu spațiile de nume, vă rugăm să consultați
aproape orice tutorial C++ și comparați ns3 spațiu de nume și utilizare aici cu instanțe ale
std spațiu de nume și folosind Spațiu de nume std; afirmații pe care le vei găsi adesea în discuții
of cout și pâraiele.

Exploatari forestiere
Următoarea linie a scriptului este următoarea,

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Vom folosi această declarație ca un loc convenabil pentru a vorbi despre documentația noastră Doxygen
sistem. Dacă te uiți pe site-ul web al proiectului, ns-3 proiect, veți găsi un link către
„Documentație” în bara de navigare. Dacă selectați acest link, veți fi direcționat către nostru
pagina de documentație. Există un link către „Ultima versiune” care vă va duce la
documentația pentru cea mai recentă versiune stabilă a ns-3. Dacă selectați „API
Documentație", veți fi direcționat la ns-3 Pagina de documentație API.

În partea stângă, veți găsi o reprezentare grafică a structurii
documentație. Un loc bun pentru a începe este NS-3 Panouri „carte” în ns-3 navigare
copac. Dacă te extinzi Panouri veți vedea o listă de ns-3 documentația modulului. The
Conceptul de modul aici se leagă direct de modulul include fișierele discutate mai sus. The
ns-3 subsistemul de logare este discutat în C ++ Constructii ECHIPAMENTE by TOATE Panouri secțiune, deci
mergeți mai departe și extindeți acel nod de documentare. Acum, extindeți Depanarea carte și apoi
selectați Exploatari forestiere .

Acum ar trebui să vă uitați la documentația Doxygen pentru modulul de înregistrare. În
lista #definiîn partea de sus a paginii veți vedea intrarea pentru
NS_LOG_COMPONENT_DEFINE. Înainte de a sări, probabil că ar fi bine să cauți
„Descrierea detaliată” a modulului de înregistrare pentru a obține o idee asupra operațiunii generale. Tu
poate derula în jos sau poate selecta linkul „Mai mult...” din diagrama de colaborare de făcut
acest.

Odată ce aveți o idee generală despre ceea ce se întâmplă, continuați și aruncați o privire asupra specificului
NS_LOG_COMPONENT_DEFINE documentație. Nu voi duplica documentația aici, ci la
rezuma, această linie declară o componentă de jurnal numită FirstScriptExample asta permite
să activați și să dezactivați înregistrarea mesajelor din consolă prin referire la nume.

Principal Funcţie
Următoarele rânduri ale scriptului pe care le veți găsi sunt:

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

Aceasta este doar declarația funcției principale a programului dumneavoastră (script). La fel ca în
orice program C++, trebuie să definiți o funcție principală care va fi prima funcție rulată.
Nu este nimic special aici. Ta ns-3 scriptul este doar un program C++.

Următoarea linie setează rezoluția de timp la o nanosecundă, care se întâmplă să fie cea implicită
valoare:

Time::SetResolution (Time::NS);

Rezoluția este cea mai mică valoare de timp care poate fi reprezentată (precum și cea mai mică
diferență reprezentabilă între două valori de timp). Puteți schimba exact rezoluția
o singura data. Mecanismul care permite această flexibilitate este oarecum amețit de memorie, deci odată ce
rezoluția a fost setată în mod explicit, eliberăm memoria, prevenind actualizările ulterioare.
(Dacă nu setați rezoluția în mod explicit, aceasta va fi implicită la o nanosecundă, iar
memoria va fi eliberată când începe simularea.)

Următoarele două rânduri ale scriptului sunt folosite pentru a activa două componente de jurnalizare care sunt construite
în aplicațiile Echo Client și Echo Server:

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

Dacă ați citit documentația componentei Logging, veți fi văzut acolo
sunt un număr de niveluri de verbozitate/detaliu de înregistrare pe care le puteți activa pentru fiecare componentă.
Aceste două linii de cod permit înregistrarea depanării la nivel INFO pentru clienții echo și
servere. Acest lucru va duce la imprimarea de către aplicație a mesajelor pe măsură ce pachetele sunt trimise
și primite în timpul simulării.

Acum vom ajunge direct la afacerea creării unei topologii și a rulării unei simulări.
Folosim obiectele helper de topologie pentru a face acest lucru cât mai ușor posibil.

Topologie Ajutoare
NodeContainer
Următoarele două linii de cod din scriptul nostru vor crea de fapt ns-3 Nod obiecte care
va reprezenta calculatoarele în simulare.

Nodurile NodeContainer;
noduri.Creează (2);

Să găsim documentația pentru NodeContainer clasa înainte de a continua. Altă cale
pentru a intra în documentația pentru o anumită clasă se face prin intermediul Clase fila din Doxygen
pagini. Dacă mai aveți Doxygen la îndemână, derulați până în partea de sus a paginii și
selectați Clase fila. Ar trebui să vedeți un nou set de file, dintre care una este Clasă
Listă. Sub acea filă veți vedea o listă cu toate ns-3 clase. Deruleaza in jos,
caut ns3::NodeContainer. Când găsiți clasa, mergeți mai departe și selectați-o pentru a merge
documentația pentru clasă.

Poate vă amintiți că una dintre abstracțiile noastre cheie este Nod. Acesta reprezintă un computer
la care vom adăuga lucruri precum stive de protocol, aplicații și periferice
carduri. The NodeContainer Asistentul pentru topologie oferă o modalitate convenabilă de a crea, gestiona și
accesa orice Nod obiecte pe care le creăm pentru a rula o simulare. Prima linie de mai sus
doar declară un NodeContainer pe care îl numim noduri. A doua linie denumește Crează
metoda pe noduri obiect și cere containerului să creeze două noduri. După cum este descris în
Doxygen, containerul cheamă în jos în ns-3 sistem propriu-zis pentru a crea două Nod
obiecte și stochează pointeri către acele obiecte în interior.

Nodurile așa cum sunt în script nu fac nimic. Următorul pas în construirea unui
topologia este de a conecta nodurile noastre împreună într-o rețea. Cea mai simplă formă de rețea am
suportul este o singură legătură punct la punct între două noduri. Vom construi unul dintre acestea
link-uri aici.

PointToPointHelper
Construim o legătură punct la punct și, într-un model care va deveni destul de bun
familiar, folosim un obiect helper de topologie pentru a face munca de nivel scăzut necesară pentru a pune
legătura împreună. Amintiți-vă că două dintre abstracțiile noastre cheie sunt NetDevice si
Canal. În lumea reală, acești termeni corespund aproximativ cardurilor periferice și
cabluri de rețea. De obicei, aceste două lucruri sunt strâns legate împreună și nu se poate
așteptați-vă să schimbați, de exemplu, dispozitive Ethernet și canale wireless. Topologia noastră
Ajutoarele urmează această cuplare intimă și, prin urmare, veți folosi un singur
PointToPointHelper pentru a configura și conecta ns-3 PointToPointNetDevice si
PointToPointChannel obiecte din acest script.

Următoarele trei rânduri din scenariu sunt:

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

Prima linie,

PointToPointHelper pointToPoint;

instanțiază a PointToPointHelper obiect pe stivă. Dintr-o perspectivă la nivel înalt
rândul următor,

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

spune PointToPointHelper obiect pentru a utiliza valoarea „5Mbps” (cinci megabiți pe secundă) ca
„DataRate” atunci când creează un PointToPointNetDevice obiect.

Dintr-o perspectivă mai detaliată, șirul „DataRate” corespunde ceea ce numim an
Atribut a PointToPointNetDevice. Dacă te uiți la Doxygen pentru clasă
ns3::PointToPointNetDevice și găsiți documentația pentru GetTypeId metoda, vei face
găsi o listă de Atribute definit pentru dispozitiv. Printre acestea se numără „DataRate”
Atribut. Cele mai vizibile de utilizator ns-3 obiectele au liste similare de Atribute. Noi folosim asta
mecanism pentru a configura cu ușurință simulările fără recompilare, așa cum veți vedea în a
următoarea secțiune.

Similar cu „DataRate” de pe PointToPointNetDevice veți găsi o „întârziere” Atribut
asociat cu PointToPointChannel. Linia finală,

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

spune PointToPointHelper pentru a utiliza valoarea „2ms” (două milisecunde) ca valoare a
întârzierea transmisiei fiecărui canal punct la punct pe care îl creează ulterior.

NetDeviceContainer
În acest moment al scenariului, avem un NodeContainer care conține două noduri. Noi avem o
PointToPointHelper care este amorsat și gata de făcut PointToPointNetDevices și sârmă
PointToPointChannel obiecte dintre ele. La fel cum am folosit NodeContainer topologie
obiect helper pentru a crea Nodurile pentru simularea noastră, vom cere PointToPointHelper
pentru a face munca implicată în crearea, configurarea și instalarea dispozitivelor noastre pentru noi. Noi
va trebui să aibă o listă cu toate obiectele NetDevice care sunt create, așa că folosim a
NetDeviceContainer pentru a le ține la fel cum am folosit un NodeContainer pentru a ține nodurile noi
creată. Următoarele două linii de cod,

Dispozitive NetDeviceContainer;
dispozitive = pointToPoint.Install (noduri);

va termina configurarea dispozitivelor și a canalului. Prima linie declară dispozitivul
containerul menționat mai sus, iar al doilea se ocupă de ridicarea greutății. The Instalare Metodă de
il PointToPointHelper ia un NodeContainer ca parametru. Pe plan intern, a
NetDeviceContainer este creat. Pentru fiecare nod din NodeContainer (trebuie să fie exact
două pentru o legătură punct la punct) a PointToPointNetDevice este creat și salvat în dispozitiv
recipient. A PointToPointChannel este creată şi cele două PointToPointNetDevices sunt
atașat. Când obiectele sunt create de către PointToPointHelper, Atribute în prealabil
setate în helper sunt folosite pentru a inițializa cele corespunzătoare Atribute în creat
obiecte.

După executarea pointToPoint.Install (noduri) apel vom avea două noduri, fiecare cu un
dispozitiv de rețea punct la punct instalat și un singur canal punct la punct între ele.
Ambele dispozitive vor fi configurate să transmită date la cinci megabiți pe secundă peste
canal care are o întârziere de transmisie de două milisecunde.

InternetStackHelper
Acum avem noduri și dispozitive configurate, dar nu avem instalate stive de protocoale
pe nodurile noastre. Următoarele două linii de cod se vor ocupa de asta.

InternetStackHelper stivă;
stack.Install (noduri);

InternetStackHelper este un ajutor de topologie care este pentru a stive pe internet ceea ce
PointToPointHelper este la dispozitive de rețea punct la punct. The Instalare metoda ia o
NodeContainer ca parametru. Când este executat, va instala o stivă Internet
(TCP, UDP, IP etc.) pe fiecare dintre nodurile din containerul de noduri.

IPv4AddressHelper
În continuare trebuie să asociem dispozitivele de pe nodurile noastre cu adrese IP. Oferim un
asistent de topologie pentru a gestiona alocarea adreselor IP. Singurul API vizibil de utilizator este să
setați adresa IP de bază și masca de rețea pe care să le utilizați atunci când efectuați adresa reală
alocare (care se face la un nivel inferior în interiorul ajutorului).

Următoarele două linii de cod din exemplul nostru de script, mai întâi.cc,

Adresă Ipv4AddressHelper;
adresa.SetBase ("10.1.1.0", "255.255.255.0");

declarați un obiect de ajutor de adresă și spuneți-i că ar trebui să înceapă alocarea adreselor IP
din rețeaua 10.1.1.0 folosind masca 255.255.255.0 pentru a defini biții alocabili. De
implicit adresele alocate vor începe de la unu și vor crește monoton, deci prima
adresa alocată din această bază va fi 10.1.1.1, urmată de 10.1.1.2 etc.
nivel ns-3 sistemul își amintește de fapt toate adresele IP alocate și va genera un
eroare fatală dacă provocați din greșeală generarea aceleiași adrese de două ori (adică a
eroare foarte greu de depanat, apropo).

Următoarea linie de cod,

Ipv4InterfaceContainer interfețe = adresa.Assign (dispozitive);

realizează atribuirea efectivă a adresei. În ns-3 facem asocierea între un IP
adresa și un dispozitiv care utilizează un Interfață IPv4 obiect. Așa cum uneori avem nevoie de o listă de
Dispozitivele net create de un ajutor pentru referințe viitoare avem nevoie uneori de o listă
Interfață IPv4 obiecte. The IPv4InterfaceContainer oferă această funcționalitate.

Acum avem o rețea punct-la-punct construită, cu stive instalate și adrese IP
atribuit. Ceea ce avem nevoie în acest moment sunt aplicații pentru a genera trafic.

Aplicatii
O altă abstracție de bază a sistemului ns-3 este Aplicatii. În acest
scriptul folosim două specializări ale nucleului ns-3 clasă Aplicatii denumit
UdpEchoServerApplication si UdpEchoClientApplication. Așa cum am făcut-o în trecutul nostru
explicații, folosim obiecte helper pentru a ajuta la configurarea și gestionarea obiectelor subiacente.
Aici, folosim UdpEchoServerHelper si UdpEchoClientHelper obiecte pentru a ne ușura viața.

UdpEchoServerHelper
Următoarele linii de cod din exemplul nostru de script, mai întâi.cc, sunt folosite pentru a configura un ecou UDP
aplicație server pe unul dintre nodurile pe care le-am creat anterior.

UdpEchoServerHelper echoServer (9);

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

Prima linie de cod din fragmentul de mai sus declară UdpEchoServerHelper. Ca de obicei,
aceasta nu este aplicația în sine, este un obiect folosit pentru a ne ajuta să creăm actualul
aplicatii. Una dintre convențiile noastre este să plasăm necesar Atribute în ajutor
constructor. În acest caz, asistentul nu poate face nimic util decât dacă este prevăzut cu acesta
un număr de port despre care știe și clientul. Mai degrabă decât să alegi unul și să speri
totul funcționează, avem nevoie de numărul portului ca parametru pentru constructor. The
constructorul, la rândul său, face pur și simplu a SetAttribute cu valoarea transmisă. Dacă vrei, tu
poate seta „Portul” Atribut la o altă valoare folosind ulterior SetAttribute.

Similar cu multe alte obiecte helper, the UdpEchoServerHelper obiectul are o Instalare
metodă. Execuția acestei metode este cea care provoacă de fapt ecoul de bază
aplicația server care urmează să fie instanțiată și atașată la un nod. Interesant este că Instalare
metoda ia o NodeContainer ca parametru la fel ca celălalt Instalare metodele pe care le avem
văzut. Acesta este de fapt ceea ce este transmis metodei, deși nu pare așa
acest caz. Există un C++ implicit convertire la lucru aici care ia rezultatul de
noduri.Get (1) (care returnează un pointer inteligent la un obiect nod --- Ptr) și folosește asta
într-un constructor pentru un nenumit NodeContainer care se trece apoi la Instalare. Daca esti
vreodată cu o pierdere pentru a găsi o anumită semnătură de metodă în codul C++ care se compila și rulează
bine, caută astfel de conversii implicite.

Acum vedem asta echoServer.Instalare urmează să instaleze un UdpEchoServerApplication pe
nodul găsit la indexul numărul unu al NodeContainer obișnuiam să ne gestionăm nodurile. Instalare
va returna un container care conține pointeri către toate aplicațiile (una în acest caz
de când am trecut pe lângă o NodeContainer conţinând un singur nod) creat de helper.

Aplicațiile necesită un timp pentru a „începe” să genereze trafic și poate dura un timp opțional
"Stop". Le oferim pe amândouă. Aceste ore sunt stabilite folosind ApplicationContainer Metode
acasă si Stop. Aceste metode iau Timp parametrii. În acest caz, folosim un explicit C ++
secvență de conversie pentru a lua C++ dublu 1.0 și a-l converti într-un ns-3 Timp obiect folosind
a secunde turnat. Rețineți că regulile de conversie pot fi controlate de autorul modelului,
iar C++ are propriile reguli, așa că nu poți întotdeauna să presupui că parametrii vor fi fericiți
convertit pentru tine. Cele două rânduri,

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

va determina aplicația server echo să acasă (se activează) la o secundă în
simulare și să Stop (se dezactivează) la zece secunde de la simulare. În virtutea
faptul că am declarat un eveniment de simulare (evenimentul de oprire a aplicației).
executat la zece secunde, simularea va dura at cel mai puțin zece secunde.

UdpEchoClientHelper
Aplicația client echo este configurată într-o metodă substanțial similară cu cea pentru
Server. Există un subiacent UdpEchoClientApplication care este gestionat de un
UdpEchoClientHelper.

UdpEchoClientHelper echoClient (interfețe.GetAddress (1), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Secunde (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

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

Pentru clientul echo, totuși, trebuie să setăm cinci diferite Atribute. Primele două
Atribute sunt stabilite în timpul construcției UdpEchoClientHelper. Trecem parametri
care sunt utilizate (intern pentru asistent) pentru a seta „RemoteAddress” și „RemotePort”
Atribute în conformitate cu convenția noastră de a face necesar Atribute parametrii din
constructori ajutatori.

Amintiți-vă că am folosit un IPv4InterfaceContainer pentru a ține evidența adreselor IP pe care le avem
atribuite dispozitivelor noastre. Cea de-a zero interfață din interfeţe containerul urmează să
corespund adresei IP a nodului zero din noduri recipient. Primul
interfață în interfeţe containerul corespunde adresei IP a primului nod din
il noduri recipient. Deci, în prima linie de cod (de sus), creăm
helper și spunându-i astfel setați adresa de la distanță a clientului să fie adresa IP
atribuit nodului pe care se află serverul. Îi spunem, de asemenea, să aranjeze trimiterea
pachete către portul nouă.

„MaxPackets” Atribut spune clientului numărul maxim de pachete pe care îi permitem
trimite în timpul simulării. „Intervalul” Atribut îi spune clientului cât să aştepte
între pachete și „PacketSize” Atribut spune clientului cât de mare are pachetul
sarcinile utile ar trebui să fie. Cu această combinație specială de Atribute, îi spunem noi
clientul să trimită un pachet de 1024 de octeți.

La fel ca în cazul serverului echo, îi spunem clientului echo să acasă si Stop, Dar
aici pornim clientul la o secundă după ce serverul este activat (la două secunde în
simulare).

Simulator
Ceea ce trebuie să facem în acest moment este să rulăm simularea. Acest lucru se face folosind
functia globala Simulator::Run.

Simulator::Run ();

Când am numit anterior metodele,

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

de fapt, am programat evenimente în simulator la 1.0 secunde, 2.0 secunde și două evenimente
la 10.0 secunde. Cand Simulator::Run este apelat, sistemul va începe să caute prin
lista evenimentelor programate și executarea acestora. Mai întâi va rula evenimentul la 1.0 secunde,
care va activa aplicația server echo (acest eveniment poate, la rândul său, să programeze multe
alte evenimente). Apoi va rula evenimentul programat pentru t=2.0 secunde care va începe
aplicația client echo. Din nou, acest eveniment poate programa mult mai multe evenimente. Începutul
implementarea evenimentului în aplicația client echo va începe faza de transfer de date a
simularea prin trimiterea unui pachet către server.

Acțiunea de a trimite pachetul către server va declanșa un lanț de evenimente care vor fi
programat automat în culise și care va efectua mecanica
ecou de pachete în funcție de diferiții parametri de sincronizare pe care i-am setat în script.

În cele din urmă, din moment ce trimitem doar un pachet (amintiți-vă de MaxPackets Atribut a fost setat la
unul), lanțul de evenimente declanșate de acea cerere de ecou unic client se va diminua și
simularea va merge inactiv. Odată ce se întâmplă acest lucru, evenimentele rămase vor fi Stop
evenimente pentru server și client. Când aceste evenimente sunt executate, nu există
evenimente ulterioare de procesat și Simulator::Run se intoarce. Apoi simularea este completă.

Rămâne doar să curățați. Acest lucru se face prin apelarea funcției globale
Simulator::Distruge. Pe măsură ce funcționează asistentul (sau nivel scăzut ns-3 cod) executate, ei
a aranjat-o astfel încât să fie introduse cârlige în simulator pentru a distruge toate obiectele
care au fost create. Nu a trebuit să țineți evidența niciunuia dintre aceste obiecte ---
tot ce trebuia să faci era să suni Simulator::Distruge si iesi. The ns-3 sistemul a avut grijă
partea grea pentru tine. Rândurile rămase din primul nostru ns-3 scenariu, mai întâi.cc, face doar
că:

Simulator::Destroy ();
0 reveni;
}

Cand il Simulator voi Stop?
ns-3 este un simulator de evenimente discrete (DE). Într-un astfel de simulator, fiecare eveniment este asociat
cu timpul său de execuție, iar simularea continuă prin executarea evenimentelor în temporal
ordinea timpului de simulare. Evenimentele pot determina programarea unor evenimente viitoare (de exemplu, a
temporizatorul se poate reprograma pentru a expira la intervalul următor).

Evenimentele inițiale sunt de obicei declanșate de fiecare obiect, de exemplu, IPv6 va programa routerul
Reclame, solicitări de vecini etc., o aplicație programează primul pachet
transmiterea evenimentului etc.

Când un eveniment este procesat, acesta poate genera zero, unul sau mai multe evenimente. Ca o simulare
se execută, evenimentele sunt consumate, dar mai multe evenimente pot fi generate (sau nu). The
simularea se va opri automat când nu mai sunt evenimente în coada de evenimente sau când
se găsește un eveniment special Stop. Evenimentul Stop este creat prin intermediul Simulator::Stop
(opreste timpul); Funcția.

Există un caz tipic în care Simulator::Stop este absolut necesar pentru a opri
simulare: atunci când are loc un eveniment autosusținut. Evenimente auto-susținute (sau recurente).
sunt evenimente care se reprogramează întotdeauna. În consecință, ei păstrează întotdeauna evenimentul
coada negoală.

Există multe protocoale și module care conțin evenimente recurente, de exemplu:

· FlowMonitor - verificare periodică a pachetelor pierdute

· RIPng - difuzare periodică a actualizării tabelelor de rutare

· etc.

În aceste cazuri, Simulator::Stop este necesar pentru a opri cu grație simularea. În
în plus, când ns-3 este în modul de emulare, the RealtimeSimulator este folosit pentru a păstra
ceasul de simulare aliniat cu ceasul mașinii și Simulator::Stop este necesar să se oprească
procesul.

Multe dintre programele de simulare din tutorial nu apelează în mod explicit Simulator::Stop,
deoarece coada de evenimente va epuiza automat evenimentele. Cu toate acestea, aceste programe vor
de asemenea, acceptați un apel către Simulator::Stop. De exemplu, următoarea declarație suplimentară în
primul exemplu de program va programa o oprire explicită la 11 secunde:

+ Simulator::Stop (Secunde (11.0));
Simulator::Run ();
Simulator::Destroy ();
0 reveni;
}

Cele de mai sus nu vor schimba de fapt comportamentul acestui program, din moment ce acest lucru particular
simularea se termină în mod natural după 10 secunde. Dar dacă ar fi să schimbi ora de oprire în
declarația de mai sus de la 11 secunde la 1 secundă, veți observa că simularea
se oprește înainte ca orice ieșire să fie imprimată pe ecran (deoarece ieșirea are loc în jurul orei 2
secunde de timp de simulare).

Este important să suni Simulator::Stop înainte apel Simulator::Run; in caz contrar,
Simulator::Run s-ar putea să nu returneze niciodată controlul programului principal pentru a executa oprirea!

Clădire Ta Scenariu
Am făcut simplu să construim scripturile tale simple. Tot ce trebuie să faci este să scapi
script în directorul scratch și va fi construit automat dacă rulați Waf.
Hai sa incercam. Copie exemple/tutorial/first.cc în zgâria director după schimbare
înapoi în directorul de nivel superior.

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

Acum construiți primul exemplu de script folosind waf:

$ ./waf

Ar trebui să vedeți mesaje care raportează că dvs prima mea exemplu a fost construit cu succes.

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
[614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o
[706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (2.357s)

Acum puteți rula exemplul (rețineți că, dacă vă construiți programul în directorul scratch
trebuie să-l executați din directorul scratch):

$ ./waf --run scratch/myfirst

Ar trebui să vedeți o ieșire:

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.418s)
A trimis 1024 de octeți la 10.1.1.2
A primit 1024 de octeți de la 10.1.1.1
A primit 1024 de octeți de la 10.1.1.2

Aici vedeți că sistemul de compilare verifică pentru a se asigura că fișierul a fost construit și
apoi îl rulează. Vedeți că componenta de logare pe clientul echo indică faptul că a trimis
un pachet de 1024 de octeți către serverul Echo pe 10.1.1.2. Veți vedea, de asemenea, componenta de logare
pe serverul echo spuneți că a primit cei 1024 de octeți de la 10.1.1.1. Serverul de eco
ecou în liniște pachetul și vedeți jurnalul clientului echo că și-a primit pachetul
înapoi de la server.

Ns-3 Sursa Cod
Acum că ați folosit o parte din ns-3 ajutoare poate doriți să aruncați o privire la unele dintre ele
codul sursă care implementează această funcționalitate. Cel mai recent cod poate fi răsfoit
serverul nostru web la următorul link: http://code.nsnam.org/ns-3-dev. Acolo, vei vedea
pagina de rezumat Mercurial pentru noastre ns-3 arborele de dezvoltare.

În partea de sus a paginii, veți vedea o serie de link-uri,

rezumat | shortlog | jurnal de modificări | grafic | etichete | fișiere

Continuați și selectați fișiere legătură. Acesta este cel mai înalt nivel al majorității noastre
arhive va arata:

drwxr-xr-x [sus]
drwxr-xr-x leagă fișierele Python
fișierele document drwxr-xr-x
fișiere exemple drwxr-xr-x
fișierele drwxr-xr-x ns3
fișiere scratch drwxr-xr-x
fișierele drwxr-xr-x src
fișierele drwxr-xr-x utils
-rw-r--r-- 2009-07-01 12:47 +0200 560 fișier .hgignore | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 1886 fișier .hgtags | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 1276 fisier AUTORI | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html fisier | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 17987 fișier LICENȚĂ | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 3742 Fișier README | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 16171 fișier RELEASE_NOTES | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 fișier 6 VERSIUNE | revizuiri | adnota
-rwxr-xr-x 2009-07-01 12:47 +0200 88110 fișier waf | revizuiri | adnota
-rwxr-xr-x 2009-07-01 12:47 +0200 28 fișier waf.bat | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 35395 fișier wscript | revizuiri | adnota
-rw-r--r-- 2009-07-01 12:47 +0200 7673 fișier wutils.py | revizuiri | adnota

Exemplele noastre de scripturi sunt în exemple director. Dacă dai clic pe exemple veți vedea
o listă de subdirectoare. Unul dintre fișierele din tutorial subdirectorul este mai întâi.cc. În cazul în care
faceţi clic pe mai întâi.cc veți găsi codul pe care tocmai l-ați parcurs.

Codul sursă este în principal în src director. Puteți vizualiza codul sursă fie prin
făcând clic pe numele directorului sau făcând clic pe fișiere link-ul din dreapta
numele directorului. Dacă faceți clic pe src director, veți fi direcționat către lista de
il src subdirectoare. Dacă apoi faceți clic pe CORE subdirectorul, veți găsi o listă de
fișiere. Primul fișier pe care îl veți găsi (în momentul scrierii acestui articol) este avorta.h. Dacă faceți clic pe
avorta.h link, veți fi trimis la fișierul sursă pentru avorta.h care conține macrocomenzi utile
pentru ieșirea din scripturi dacă sunt detectate condiții anormale.

Codul sursă pentru ajutoarele pe care i-am folosit în acest capitol poate fi găsit în
src/applications/helper director. Simțiți-vă liber să căutați în arborele de directoare pentru a obține
o senzație pentru ceea ce este acolo și stilul de ns-3 programe.

AJUSTARE


Utilizarea il Exploatari forestiere Module
Am aruncat deja o scurtă privire asupra ns-3 modul de înregistrare în timp ce treceți peste
mai întâi.cc scenariu. Acum vom arunca o privire mai atentă și vom vedea ce fel de cazuri de utilizare
subsistemul de înregistrare a fost conceput pentru a acoperi.

Exploatari forestiere Descriere
Multe sisteme mari acceptă un fel de facilitate de înregistrare a mesajelor și ns-3 nu este un
excepție. În unele cazuri, doar mesajele de eroare sunt înregistrate în „consola operatorului” (care
este de obicei stderr în sisteme bazate pe Unix). În alte sisteme, mesajele de avertizare pot fi
rezultate precum și mesaje informaționale mai detaliate. În unele cazuri, facilități de exploatare forestieră
sunt folosite pentru a afișa mesaje de depanare care pot transforma rapid rezultatul într-o neclaritate.

ns-3 consideră că toate aceste niveluri de verbozitate sunt utile și oferim a
abordare selectabilă, pe mai multe niveluri, a înregistrării mesajelor. Înregistrarea poate fi dezactivată complet,
activată componentă cu componentă sau activată global; și oferă selectabile
niveluri de verbozitate. The ns-3 Modulul de jurnal oferă un mod simplu, relativ ușor de utilizat
modalitate de a obține informații utile din simulare.

Trebuie să înțelegeți că oferim un mecanism de uz general --- urmărire --- la
obțineți date din modelele dvs. care ar trebui să fie preferate pentru ieșirea de simulare (a se vedea documentul
secțiunea tutorial Utilizarea sistemului de urmărire pentru mai multe detalii despre sistemul nostru de urmărire).
Înregistrarea ar trebui să fie preferată pentru informațiile de depanare, avertismente, mesaje de eroare sau oricare
timp în care doriți să primiți cu ușurință un mesaj rapid din scripturile sau modelele dvs.

În prezent, există șapte niveluri de mesaje de jurnal de nivel de verbozitate în creștere definite în
sistemului.

· LOG_ERROR --- Jurnalul mesajelor de eroare (macrocomandă asociată: NS_LOG_ERROR);

· LOG_WARN --- Jurnalul mesajelor de avertizare (macrocomandă asociată: NS_LOG_WARN);

· LOG_DEBUG --- Înregistrează mesaje de depanare ad-hoc relativ rare (macrocomandă asociată:
NS_LOG_DEBUG);

· LOG_INFO --- Înregistrează mesaje informaționale despre progresul programului (macrocomandă asociată:
NS_LOG_INFO);

· LOG_FUNCTION --- Înregistrează un mesaj care descrie fiecare funcție numită (două macrocomenzi asociate:
NS_LOG_FUNCTION, folosit pentru funcțiile membre și NS_LOG_FUNCTION_NOARGS, folosit pentru statice
funcții);

· LOG_LOGIC -- Mesaje de jurnal care descriu fluxul logic în cadrul unei funcții (macrocomandă asociată:
NS_LOG_LOGIC);

· LOG_ALL --- Înregistrează tot ce s-a menționat mai sus (fără macrocomandă asociată).

Pentru fiecare LOG_TYPE există, de asemenea, LOG_LEVEL_TYPE care, dacă este utilizat, permite înregistrarea tuturor
niveluri deasupra acestuia pe lângă nivelul său. (Ca o consecință a acestui fapt, LOG_ERROR și
LOG_LEVEL_ERROR și, de asemenea, LOG_ALL și LOG_LEVEL_ALL sunt echivalente din punct de vedere funcțional.) Pentru
de exemplu, activarea LOG_INFO va activa numai mesajele furnizate de macrocomanda NS_LOG_INFO, în timp ce
activarea LOG_LEVEL_INFO va activa și mesajele furnizate de NS_LOG_DEBUG, NS_LOG_WARN
și macrocomenzile NS_LOG_ERROR.

De asemenea, oferim o macrocomandă de înregistrare necondiționată care este întotdeauna afișată, indiferent de
nivelurile de înregistrare sau selecția componentelor.

· NS_LOG_UNCOND -- Înregistrați mesajul asociat necondiționat (nici un nivel de jurnal asociat).

Fiecare nivel poate fi solicitat individual sau cumulat; iar înregistrarea în jurnal poate fi configurată folosind a
variabila de mediu shell (NS_LOG) sau prin înregistrarea apelului funcției de sistem. După cum s-a văzut
mai devreme în tutorial, sistemul de înregistrare are documentație Doxygen și acum ar fi a
este momentul potrivit pentru a citi documentația Modulului de înregistrare dacă nu ați făcut acest lucru.

Acum că ați citit documentația în detaliu, să folosim o parte din aceste cunoștințe
pentru a obține câteva informații interesante din zgârietură/myfirst.cc exemplu de script pe care îl aveți
deja construit.

Activarea Exploatari forestiere
Să folosim variabila de mediu NS_LOG pentru a activa mai multe înregistrări, dar mai întâi, doar pentru a
orientați-vă, mergeți mai departe și rulați ultimul script așa cum ați făcut anterior,

$ ./waf --run scratch/myfirst

Ar trebui să vedeți rezultatul familiar al primului ns-3 exemplu de program

$ Waf: se introduce directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.413s)
A trimis 1024 de octeți la 10.1.1.2
A primit 1024 de octeți de la 10.1.1.1
A primit 1024 de octeți de la 10.1.1.2

Se pare că mesajele „Trimis” și „Primit” pe care le vedeți mai sus sunt de fapt înregistrate
mesaje de la UdpEchoClientApplication si UdpEchoServerApplication. Îl putem întreba pe
aplicația client, de exemplu, pentru a imprima mai multe informații prin setarea nivelului de înregistrare
prin variabila de mediu NS_LOG.

Voi presupune de aici încolo că utilizați un shell asemănător sh care folosește
sintaxa „VARIABLE=valoare”. Dacă utilizați un shell asemănător csh, atunci va trebui
convertiți-mi exemplele în sintaxa „setenv VARIABLE value” cerută de acele shell-uri.

În acest moment, aplicația client UDP echo răspunde la următoarea linie de cod în
zgârietură/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Această linie de cod permite LOG_LEVEL_INFO nivelul de logare. Când trecem pe lângă o tăietură
steag de nivel, de fapt activăm nivelul dat și toate nivelurile inferioare. În acest caz,
noi am activat NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN si NS_LOG_ERROR. Putem crește
nivelul de logare și obțineți mai multe informații fără a modifica scriptul și a recompila prin
setarea variabilei de mediu NS_LOG astfel:

$ export NS_LOG=UdpEchoClientApplication=level_all

Aceasta setează variabila de mediu shell NS_LOG la sfoară,

UdpEchoClientApplication=level_all

Partea stângă a sarcinii este numele componentei de înregistrare pe care dorim să o setăm,
iar partea dreaptă este steagul pe care vrem să-l folosim. În acest caz, vom porni
toate nivelurile de depanare pentru aplicație. Dacă rulați scriptul cu NS_LOG setat
în acest fel, ns-3 sistemul de înregistrare va prelua modificarea și ar trebui să vedeți următoarele
ieșire:

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
A trimis 1024 de octeți la 10.1.1.2
A primit 1024 de octeți de la 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
A primit 1024 de octeți de la 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Informațiile suplimentare de depanare furnizate de aplicație provin din NS_LOG_FUNCTION
nivel. Aceasta arată de fiecare dată când o funcție din aplicație este apelată în timpul scriptului
execuţie. În general, utilizarea (cel puțin) NS_LOG_FUNCTION(this) în funcțiile membre este
preferat. Utilizați NS_LOG_FUNCTION_NOARGS() numai în funcțiile statice. Rețineți, totuși, că
nu există cerințe în ns-3 sistem pe care modelele trebuie să-l suporte orice
funcționalitate de înregistrare. Decizia cu privire la câte informații sunt înregistrate este lăsată pe seama
dezvoltatorul de model individual. În cazul aplicațiilor echo, o mulțime de jurnal
ieșirea este disponibilă.

Acum puteți vedea un jurnal al apelurilor de funcții care au fost efectuate către aplicație. daca tu
Priviți cu atenție veți observa un singur două puncte între șir UdpEchoClientApplication
și numele metodei unde v-ați fi așteptat la un operator de domeniu C++ (::). Aceasta este
intenționat.

Numele nu este de fapt un nume de clasă, este un nume de componentă de jurnal. Când există o
corespondența unu-la-unu între un fișier sursă și o clasă, aceasta va fi în general
nume de clasă, dar ar trebui să înțelegeți că nu este de fapt un nume de clasă și există un
un singur colon acolo în loc de un dublu dublu pentru a vă aminti într-un mod relativ subtil
separa conceptual numele componentei de jurnal de numele clasei.

Se dovedește că, în unele cazuri, poate fi greu de determinat care metodă de fapt
generează un mesaj de jurnal. Dacă te uiți în textul de mai sus, s-ar putea să te întrebi unde este șirul
"Primit 1024 bytes din 10.1.1.2" vine de la. Puteți rezolva acest lucru prin SAU
prefix_func nivel în NS_LOG variabilă de mediu. Încercați să faceți următoarele,

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Rețineți că ghilimelele sunt necesare deoarece bara verticală pe care o folosim pentru a indica un SAU
funcționarea este, de asemenea, un conector de conductă Unix.

Acum, dacă rulați scriptul, veți vedea că sistemul de înregistrare se asigură că fiecare
mesajul de la componenta de jurnal dată este prefixat cu numele componentei.

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): a trimis 1024 de octeți la 10.1.1.2
A primit 1024 de octeți de la 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): a primit 1024 de octeți de la 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()

Acum puteți vedea toate mesajele care provin din aplicația client Echo UDP
identificate ca atare. Mesajul „Received 1024 bytes from 10.1.1.2” este acum clar
identificate ca provenind din aplicația client echo. Mesajul rămas trebuie să fie
provenind de la aplicația UDP echo server. Putem activa acea componentă introducând a
lista de componente separate prin două puncte din variabila de mediu NS_LOG.

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

Avertisment: va trebui să eliminați linia nouă după : în textul exemplu de mai sus
este acolo doar în scopul formatării documentelor.

Acum, dacă rulați scriptul, veți vedea toate mesajele de jurnal de la atât clientul echo
și aplicații server. Puteți vedea că acest lucru poate fi foarte util în problemele de depanare.

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): a trimis 1024 de octeți la 10.1.1.2
UdpEchoServerApplication:HandleRead(): a primit 1024 de octeți de la 10.1.1.1
UdpEchoServerApplication:HandleRead(): Ecou pachet
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): a primit 1024 de octeți de la 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

De asemenea, uneori este util să poți vedea ora de simulare la care un mesaj de jurnal
Este generat. Puteți face acest lucru prin OR în bitul prefix_time.

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

Din nou, va trebui să eliminați linia nouă de mai sus. Dacă rulați scriptul acum, ar trebui
vezi urmatoarea iesire:

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.418s)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): a trimis 1024 de octeți la 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): a primit 1024 de octeți de la 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Ecou pachet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): S-au primit 1024 de octeți de la 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()

Puteți vedea că constructorul pentru UdpEchoServer a fost apelat la un moment de simulare de
0 secunde. Acest lucru se întâmplă de fapt înainte de a începe simularea, dar timpul este
afișat ca zero secunde. Același lucru este valabil și pentru mesajul constructorului UdpEchoClient.

Reamintim că zgârietură/primul.cc scriptul a pornit aplicația server echo la o secundă
în simulare. Acum puteți vedea că StartApplication metoda serverului este,
de fapt, sunat la o secundă. De asemenea, puteți vedea că aplicația client echo este
a început la un timp de simulare de două secunde așa cum am cerut în script.

Acum puteți urmări progresul simulării din ScheduleTransmit apel în
clientul care sună Trimiteți la Găsește Citiți apel invers în aplicația server echo. Notă
că timpul scurs pentru ca pachetul să fie trimis prin legătura punct la punct este 3.69
milisecunde. Vedeți serverul de ecou înregistrând un mesaj care vă spune că a avut ecou
pachetul și apoi, după o altă întârziere a canalului, vedeți clientul echo primind
ecou pachet în el Găsește Citiți metodă.

Sunt multe care se întâmplă sub acoperirea acestei simulari și nu sunteți
văzând de asemenea. Puteți urmări foarte ușor întregul proces pornind toate
de înregistrare a componentelor din sistem. Încercați să setați NS_LOG variabilă la următoarele,

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

Asteriscul de mai sus este caracterul metalic al componentei de înregistrare. Acest lucru va activa toate
înregistrarea tuturor componentelor utilizate în simulare. Nu voi reproduce rezultatul
aici (în momentul în care scriem aceasta produce 1265 de linii de ieșire pentru ecou un singur pachet) dar
puteți redirecționa aceste informații într-un fișier și puteți căuta prin el cu preferatul dvs
editor dacă vrei,

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

Eu personal folosesc această versiune extrem de cuprinzătoare de logare când mi se prezintă un
problema și nu am idee unde merg lucrurile prost. Pot urmări progresul
codați destul de ușor, fără a fi nevoie să setați puncte de întrerupere și să parcurgeți codul într-un depanator.
Pot doar să editez rezultatul în editorul meu preferat și să caut lucruri pe care le aștept,
și să văd lucruri care se întâmplă la care nu mă aștept. Când am o idee generală despre ce este
mergând prost, trec într-un depanator pentru o examinare fină a problemei.
Acest tip de ieșire poate fi util în special atunci când scriptul face ceva complet
neașteptat. Dacă utilizați un depanator, este posibil să pierdeți o excursie neașteptată
complet. Înregistrarea excursiei o face rapid vizibilă.

Adăugare Exploatari forestiere la ta Cod
Puteți adăuga înregistrări noi la simulările dvs. făcând apeluri la componenta jurnal prin
mai multe macro-uri. Să facem asta în myfirst.cc scenariul pe care îl avem în zgâria director.

Amintiți-vă că am definit o componentă de logare în acel script:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Acum știți că puteți activa toată înregistrarea pentru această componentă prin setarea
NS_LOG variabilă de mediu la diferite niveluri. Să mergem mai departe și să adăugăm ceva logare la
scenariul. Macrocomanda utilizată pentru a adăuga un mesaj de jurnal la nivel informațional este NS_LOG_INFO. Merge
înainte și adăugați unul (chiar înainte de a începe să creăm nodurile) care vă spune că scriptul
este „Crearea topologiei”. Acest lucru se face ca în acest fragment de cod,

Operatii Deschise zgârietură/myfirst.cc în editorul tău preferat și adaugă linia,

NS_LOG_INFO ("Crearea topologiei");

chiar înaintea liniilor,

Nodurile NodeContainer;
noduri.Creează (2);

Acum construiți scriptul folosind waf și ștergeți NS_LOG variabilă pentru a opri torrentul
înregistrarea pe care am activat-o anterior:

$ ./waf
$ export NS_LOG=

Acum, dacă rulați scriptul,

$ ./waf --run scratch/myfirst

tu vei nu vedeți noul mesaj de la componenta de înregistrare asociată
(FirstScriptExample) nu a fost activat. Pentru a vedea mesajul dvs. va trebui
activați FirstScriptExample componentă de logare cu un nivel mai mare sau egal cu
NS_LOG_INFO. Dacă doriți doar să vedeți acest nivel special de înregistrare, îl puteți activa
de,

$ export NS_LOG=FirstScriptExample=informații

Dacă rulați acum scriptul, veți vedea noul mesaj de jurnal „Crearea topologiei”,

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.404s)
Crearea topologiei
A trimis 1024 de octeți la 10.1.1.2
A primit 1024 de octeți de la 10.1.1.1
A primit 1024 de octeți de la 10.1.1.2

Utilizarea Comandă Linie Argumente
Supracomandarea Mod implicit Atribute
Un alt mod în care poți schimba cum ns-3 scripturile se comportă fără editare și construirea se face prin
comandă linie argumente. Oferim un mecanism pentru a analiza argumentele liniei de comandă și
setați automat variabilele locale și globale pe baza acestor argumente.

Primul pas în utilizarea sistemului de argumente în linia de comandă este declararea liniei de comandă
analizator. Acest lucru se face destul de simplu (în programul dvs. principal), ca în următorul cod,

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

CommandLine cmd;
cmd.Parse (argc, argv);

...
}

Acest simplu fragment de două rânduri este de fapt foarte util în sine. Se deschide ușa către
ns-3 variabilă globală şi Atribut sisteme. Continuați și adăugați acele două linii de cod la
il zgârietură/myfirst.cc script la începutul lui principal. Continuați și construiți scriptul și rulați
aceasta, dar cereți ajutor scriptului în felul următor,

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

Acest lucru va cere lui Waf să ruleze zgârietură/primul meu script și transmiteți argumentul liniei de comandă
--PrintHelp la scenariu. Ghilimele sunt necesare pentru a sorta ce program primește care
argument. Analizorul liniei de comandă va vedea acum --PrintHelp argumentați și răspundeți cu,

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: imprimați acest mesaj de ajutor.
--PrintGroups: Tipăriți lista de grupuri.
--PrintTypeIds: Tipăriți toate TypeId-urile.
--PrintGroup=[grup]: Tipăriți toate TypeId-urile grupului.
--PrintAttributes=[typeid]: Imprimă toate atributele typeid.
--PrintGlobals: Tipăriți lista de globaluri.

Să ne concentrăm pe --PrintAttributes opțiune. Am făcut deja aluzie la ns-3 Atribut
sistem în timp ce mergeți prin mai întâi.cc scenariu. Ne-am uitat la următoarele rânduri ale
cod,

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

și am menționat că Rata de date a fost de fapt o Atribut a PointToPointNetDevice. hai sa
utilizați analizatorul de argumente din linia de comandă pentru a arunca o privire la Atribute a
PointToPointNetDevice. Lista de ajutor spune că ar trebui să oferim a TypeId. Acest
corespunde numelui de clasă al clasei la care Atribute aparține. În acest caz
va fi ns3::PointToPointNetDevice. Să mergem mai departe și să introducem,

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

Sistemul va imprima toate Atribute a acestui tip de dispozitiv net. Printre
Atribute veți vedea listat este,

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
Rata de date implicită pentru legăturile punct la punct

Aceasta este valoarea implicită care va fi utilizată atunci când a PointToPointNetDevice este creat în
sistem. Am înlocuit această implicită cu Atribut stabilirea în PointToPointHelper
de mai sus. Să folosim valorile implicite pentru dispozitivele și canalele punct la punct
ștergerea SetDeviceAttribute apel și SetChannelAttribute apel de la myfirst.cc
avem în directorul scratch.

Scriptul dvs. ar trebui să declare acum PointToPointHelper si sa nu faci nimic set operațiuni
ca în exemplul următor,

...

Nodurile NodeContainer;
noduri.Creează (2);

PointToPointHelper pointToPoint;

Dispozitive NetDeviceContainer;
dispozitive = pointToPoint.Install (noduri);

...

Continuați și construiți noul script cu Waf (./waff) și să revenim și să activăm unele
logare din aplicația de server Echo UDP și activați prefixul de timp.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Dacă rulați scriptul, acum ar trebui să vedeți următoarea ieșire,

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
A trimis 1024 de octeți la 10.1.1.2
2.25732s A primit 1024 de octeți de la 10.1.1.1
2.25732s Ecou pachet
A primit 1024 de octeți de la 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Amintiți-vă că ultima dată ne-am uitat la timpul de simulare la care se afla pachetul
primit de serverul echo, a fost la 2.00369 secunde.

2.00369s UdpEchoServerApplication:HandleRead(): a primit 1024 de octeți de la 10.1.1.1

Acum primește pachetul la 2.25732 secunde. Acest lucru se datorează faptului că tocmai am renunțat la
rata de date a PointToPointNetDevice până la valoarea implicită de 32768 biți pe secundă de la
cinci megabiți pe secundă.

Dacă ar fi să oferim un nou Rata de date folosind linia de comandă, ne-am putea accelera simularea
sus din nou. Facem acest lucru în felul următor, conform formulei implicate de ajutor
articol:

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

Aceasta va seta valoarea implicită a Rata de date Atribut înapoi la cinci megabiți pe
al doilea. Esti surprins de rezultat? Se pare că pentru a obține originalul
comportamentul scriptului înapoi, va trebui să setăm întârzierea vitezei luminii a canalului
de asemenea. Putem cere sistemului de linie de comandă să imprime Atribute a canalului
la fel cum am făcut pentru dispozitivul net:

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

Descoperim pe Întârziere Atribut al canalului este setat în felul următor:

--ns3::PointToPointChannel::Delay=[0ns]:
Întârziere de transmisie prin canal

Putem apoi seta ambele aceste valori implicite prin sistemul de linie de comandă,

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

caz în care recuperăm timpul pe care l-am avut când am setat în mod explicit Rata de date si Întârziere
în scenariu:

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
A trimis 1024 de octeți la 10.1.1.2
2.00369s A primit 1024 de octeți de la 10.1.1.1
2.00369s Ecou pachet
A primit 1024 de octeți de la 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Rețineți că pachetul este primit din nou de către server la 2.00369 secunde. Am putea
setați de fapt oricare dintre Atribute folosit în scenariu în acest fel. În special am putea
setați UdpEchoClient Atribut MaxPackets la o altă valoare decât una.

Cum ai proceda la asta? Incearca. Amintiți-vă că trebuie să comentați locul
suprascriem implicit Atribut și setat în mod explicit MaxPackets în scenariu. Atunci tu
trebuie să reconstruiască scriptul. De asemenea, va trebui să găsiți sintaxa pentru setarea efectivă
noua valoare implicită a atributului utilizând facilitatea de ajutor din linia de comandă. Odată ce ai asta
mi-am dat seama că ar trebui să poți controla numărul de pachete care au ecou de la comandă
linia. Întrucât suntem oameni drăguți, vă vom spune că linia dvs. de comandă ar trebui să caute
ceva asemănător cu,

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

Cârlig Ta Propriu Valori
De asemenea, puteți adăuga propriile cârlige la sistemul de linie de comandă. Acest lucru se face pur și simplu de
folosind Adaugă valoare metoda la analizatorul liniei de comandă.

Să folosim această facilitate pentru a specifica numărul de pachete de care vor ecou într-un mod complet diferit
cale. Să adăugăm o variabilă locală numită nPachete la principal funcţie. Vom inițializa
la unul pentru a se potrivi cu comportamentul nostru implicit anterior. Pentru a permite analizatorului liniei de comandă să
schimbați această valoare, trebuie să conectam valoarea în parser. Facem acest lucru adăugând un apel
la Adaugă valoare. Continuă și schimbă zgârietură/myfirst.cc scriptul pentru a începe cu
următorul cod,

int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;

CommandLine cmd;
cmd.AddValue("nPackets", "Număr de pachete pentru a ecou", nPackets);
cmd.Parse (argc, argv);

...

Derulați în jos până la punctul din script unde am setat MaxPackets Atribut si schimba-l
astfel încât să fie setată la variabilă nPachete în loc de constantă 1 după cum se arată mai jos.

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

Acum, dacă rulați scriptul și furnizați --PrintHelp argument, ar trebui să vezi noul tău
Utilizator Argument listate în afișajul de ajutor.

Încerca,

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

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.403s)
--PrintHelp: imprimați acest mesaj de ajutor.
--PrintGroups: Tipăriți lista de grupuri.
--PrintTypeIds: Tipăriți toate TypeId-urile.
--PrintGroup=[grup]: Tipăriți toate TypeId-urile grupului.
--PrintAttributes=[typeid]: Imprimă toate atributele typeid.
--PrintGlobals: Tipăriți lista de globaluri.
Argumente ale utilizatorului:
--nPackets: Numărul de pachete la care se ecou

Dacă doriți să specificați numărul de pachete pentru care să economisiți, acum puteți face acest lucru setând
--nPachete argument în linia de comandă,

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

Ar trebui să vezi acum

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
A trimis 1024 de octeți la 10.1.1.2
2.25732s A primit 1024 de octeți de la 10.1.1.1
2.25732s Ecou pachet
A primit 1024 de octeți de la 10.1.1.2
A trimis 1024 de octeți la 10.1.1.2
3.25732s A primit 1024 de octeți de la 10.1.1.1
3.25732s Ecou pachet
A primit 1024 de octeți de la 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()

Acum ați ecou două pachete. Destul de ușor, nu-i așa?

Puteți vedea că dacă sunteți un ns-3 utilizator, puteți utiliza sistemul de argumente din linia de comandă pentru
controlează valorile globale și Atribute. Dacă sunteți un autor de model, puteți adăuga noi
Atribute de dvs. Obiecte iar acestea vor fi automat disponibile pentru setare de către dvs
utilizatorii prin sistemul de linie de comandă. Dacă sunteți un autor de scenarii, puteți adăuga noi
variabile la scripturile dvs. și conectați-le în sistemul de linie de comandă destul de fără durere.

Utilizarea il calc Sistem
Scopul simulării este de a genera rezultate pentru studii ulterioare, iar ns-3
sistemul de urmărire este un mecanism principal pentru aceasta. De cand ns-3 este un program C++, standard
Ar putea fi utilizate facilități pentru generarea rezultatelor din programele C++:

#include
...
intmain()
{
...
std::cout << "Valoarea lui x este " << x << std::endl;
...
}

Puteți chiar să utilizați modulul de înregistrare pentru a adăuga o mică structură soluției dvs. Acolo
sunt multe probleme bine-cunoscute generate de astfel de abordări și astfel am oferit a
subsistem generic de urmărire a evenimentelor pentru a aborda problemele pe care le-am considerat importante.

Obiectivele de bază ale ns-3 sistemele de urmărire sunt:

· Pentru sarcinile de bază, sistemul de urmărire ar trebui să permită utilizatorului să genereze urmărire standard
pentru sursele populare de urmărire și pentru a personaliza ce obiecte generează trasarea;

· Utilizatorii intermediari trebuie să poată extinde sistemul de urmărire pentru a modifica formatul de ieșire
generate sau pentru a insera noi surse de urmărire, fără a modifica nucleul
simulator;

· Utilizatorii avansați pot modifica nucleul simulatorului pentru a adăuga noi surse de urmărire și chiuvete.

ns-3 sistemul de urmărire este construit pe conceptele de surse independente de urmărire și
trasarea chiuvetelor și un mecanism uniform pentru conectarea surselor la chiuvete. Sursele de urme sunt
entități care pot semnala evenimente care au loc într-o simulare și oferă acces la
date interesante de bază. De exemplu, o sursă de urmărire ar putea indica când este un pachet
primit de un dispozitiv net și oferă acces la conținutul pachetului pentru urmărirea interesată
chiuvete.

Sursele de urmărire nu sunt utile de la sine, ele trebuie să fie „conectate” la alte bucăți de
cod care chiar face ceva util cu informațiile furnizate de chiuvetă. Urmă
chiuvetele sunt consumatori ai evenimentelor și datelor furnizate de sursele de urmărire. De exemplu,
s-ar putea crea o chiuvetă de urmărire care ar (atunci când este conectată la sursa de urmărire a
exemplul anterior) tipăriți părți interesante ale pachetului primit.

Motivul pentru această împărțire explicită este de a permite utilizatorilor să atașeze noi tipuri de chiuvete
sursele de urmărire existente, fără a necesita editarea și recompilarea nucleului fișierului
simulator. Astfel, în exemplul de mai sus, un utilizator ar putea defini o nouă chiuvetă de urmărire în ea
script-ul și atașați-l la o sursă de urmărire existentă definită în nucleul de simulare de
editarea numai a scriptului utilizatorului.

În acest tutorial, vom parcurge câteva surse și chiuvete predefinite și vom arăta cum
pot fi personalizate cu un efort redus al utilizatorului. Consultați manualul ns-3 sau secțiunile de instrucțiuni
pentru informații despre configurația avansată de urmărire, inclusiv extinderea urmăririi
namespace și crearea de noi surse de urmărire.

ASCII calc
ns-3 oferă funcționalitate de ajutor care înglobează sistemul de urmărire de nivel scăzut pentru a vă ajuta
cu detaliile implicate în configurarea unor urme de pachete ușor de înțeles. daca tu
activați această funcționalitate, veți vedea rezultate într-un fișier ASCII --- deci numele. Pentru
cei familiarizati cu ns-2 de ieșire, acest tip de urmă este analog cu afară.tr generată
prin multe scripturi.

Să intrăm direct și să adăugăm o ieșire de urmărire ASCII la nostru zgârietură/myfirst.cc
scenariu. Chiar înainte de a apela la Simulator::Run (), adăugați următoarele rânduri de cod:

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

Ca în multe altele ns-3 idioms, acest cod folosește un obiect helper pentru a ajuta la crearea ASCII
urme. A doua linie conține două apeluri de metodă imbricate. Metoda „în interior”,
CreateFileStream() folosește un limbaj de obiect fără nume pentru a crea un obiect de flux de fișiere pe
stiva (fără nume de obiect) și transmiteți-l la metoda apelată. Vom intra în asta
mai multe în viitor, dar tot ce trebuie să știți în acest moment este că creați un
obiect reprezentând un fișier numit „myfirst.tr” și care îl trece în ns-3. tu spui
ns-3 să se ocupe de problemele de viață ale obiectului creat și, de asemenea, să se ocupe de probleme
cauzat de o limitare puțin cunoscută (intenționată) a obiectelor C++ din flux legate de copiere
constructorii.

Apelul exterior, către EnableAsciiAll(), îi spune asistentului că doriți să activați ASCII
urmărirea pe toate dispozitivele punct la punct din simularea dvs.; și vrei (furnizat)
trace se adaugă pentru a scrie informații despre mișcarea pachetelor în format ASCII.

Pentru cei familiarizați cu ns-2, evenimentele urmărite sunt echivalente cu punctele de urmărire populare
care înregistrează evenimentele „+”, „-”, „d” și „r”.

Acum puteți construi scriptul și îl puteți rula din linia de comandă:

$ ./waf --run scratch/myfirst

Așa cum ați văzut de multe ori înainte, veți vedea câteva mesaje de la Waf și apoi
„„build” s-a terminat cu succes” cu un anumit număr de mesaje din programul care rulează.

Când a rulat, programul va fi creat un fișier numit myfirst.tr. Din cauza modului
că Waf funcționează, fișierul nu este creat în directorul local, este creat la
directorul de nivel superior al depozitului în mod implicit. Dacă vrei să controlezi unde sunt urmele
sunt salvate, puteți utiliza --cwd opțiunea Waf pentru a specifica acest lucru. Nu am făcut asta, așadar
trebuie să ne schimbăm în directorul de nivel superior al depozitului nostru și să aruncăm o privire la ASCII
fișier de urmărire myfirst.tr în editorul tău preferat.

Analizare ascii urme
Există o mulțime de informații acolo într-o formă destul de densă, dar primul lucru de observat
este că există un număr de linii distincte în acest fișier. Poate fi greu de văzut
acest lucru clar dacă nu vă lărgiți fereastra considerabil.

Fiecare linie din fișier îi corespunde a urmări eveniment. În acest caz, urmărim evenimentele
il transmite coadă prezent în fiecare dispozitiv net punct la punct din simulare. The
coada de transmitere este o coadă prin care fiecare pachet este destinat unui canal punct la punct
trebuie trecut. Rețineți că fiecare linie din fișierul de urmărire începe cu un caracter singur (are un
spațiu după el). Acest caracter va avea următorul sens:

· +: A avut loc o operație de coadă în coada dispozitivului;

· -: A avut loc o operație de scoatere din coadă în coada dispozitivului;

· d: Un pachet a fost abandonat, de obicei pentru că coada era plină;

· r: Un pachet a fost primit de dispozitivul de rețea.

Să luăm o vedere mai detaliată a primei linii din fișierul de urmărire. O voi sparge
în secțiuni (indentate pentru claritate) cu un număr de referință în partea stângă:

+
2
/NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
ns3::PppHeader (
Protocol punct la punct: IP (0x0021))
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 protocol 17 offset 0 steaguri [niciunul]
lungime: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
lungime: 1032 49153 > 9)
Sarcină utilă (dimensiune=1024)

Prima secțiune a acestui eveniment de urmărire extins (numărul de referință 0) este operația. Noi
ia o + caracter, deci acesta corespunde unui Puneți în coadă operațiune pe coada de transmisie.
A doua secțiune (referința 1) este timpul de simulare exprimat în secunde. Poți
Amintiți-vă că am întrebat UdpEchoClientApplication pentru a începe trimiterea pachetelor la două secunde.
Aici vedem confirmarea că acest lucru se întâmplă într-adevăr.

Următoarea secțiune a exemplului de urmărire (referința 2) ne spune care sursă de urmărire a provenit
acest eveniment (exprimat în spațiul de nume de urmărire). Vă puteți gândi la spațiul de nume de urmărire
oarecum așa cum ai face cu un spațiu de nume de sistem de fișiere. Rădăcina spațiului de nume este
NodeList. Aceasta corespunde unui container gestionat în ns-3 cod de bază care conține toate
a nodurilor care sunt create într-un script. La fel cum un sistem de fișiere poate avea directoare
sub rădăcină, este posibil să avem numere de noduri în NodeList. Șirul /NodeList/0
prin urmare se referă la nodul zero din NodeList pe care îl considerăm de obicei „nod
0". În fiecare nod există o listă de dispozitive care au fost instalate. Apare această listă
următorul în spațiul de nume. Puteți vedea că acest eveniment de urmărire provine DeviceList/0 care este
dispozitivul zero instalat în nod.

Următorul șir, $ns3::PointToPointNetDevice vă spune ce fel de dispozitiv este în
poziţia zero a listei de dispozitive pentru nodul zero. Amintiți-vă că operația + găsit la
referința 00 a însemnat că a avut loc o operațiune de coadă în coada de transmisie a dispozitivului.
Acest lucru se reflectă în segmentele finale ale „calei de urmărire” care sunt TxQueue/Enqueue.

Secțiunile rămase din urmă ar trebui să fie destul de intuitive. Referințele 3-4 indică
că pachetul este încapsulat în protocolul punct la punct. Referințele 5-7 arată că
pachetul are un antet IP versiunea patru și provine de la adresa IP 10.1.1.1 și
este destinat pentru 10.1.1.2. Referințele 8-9 arată că acest pachet are un antet UDP și,
în cele din urmă, referința 10 arată că sarcina utilă este de 1024 de octeți așteptați.

Următoarea linie din fișierul de urmărire arată că același pachet este scos din coda de transmisie
coadă pe același nod.

A treia linie din fișierul de urmărire arată pachetul primit de dispozitivul net pe
nod cu serverul echo. Am reprodus mai jos acel eveniment.

r
2.25732
/NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 protocol 17 offset 0 steaguri [niciunul]
lungime: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
lungime: 1032 49153 > 9)
Sarcină utilă (dimensiune=1024)

Observați că operația de urmărire este acum r iar timpul de simulare a crescut la 2.25732
secunde. Dacă ai urmat îndeaproape pașii tutorialului, înseamnă că ai făcut-o
a parasit Rata de date a dispozitivelor de rețea și a canalului Întârziere setați la valorile implicite.
Acest timp ar trebui să fie familiar, așa cum ați văzut-o înainte într-o secțiune anterioară.

Intrarea spațiului de nume sursă de urmărire (referința 02) s-a schimbat pentru a reflecta faptul că acest eveniment este
provenind de la nodul 1 (/NodeList/1) și sursa de urmărire a recepției pachetului (/MacRx). Aceasta
ar trebui să vă fie destul de ușor să urmăriți progresul pachetului prin topologie
uitându-se la restul urmelor din dosar.

PCAP calc
ns-3 Ajutoarele dispozitivului pot fi, de asemenea, utilizați pentru a crea fișiere de urmărire în fișierul .pcap format. The
acronimul pcap (scris de obicei cu litere mici) înseamnă captura de pachete și este de fapt un
API care include definiția a .pcap tipul fisierului. Cel mai popular program care
poate citi și afișa acest format este Wireshark (numit anterior Ethereal). Totuși, acolo
Există multe analizoare de urmărire a traficului care utilizează acest format de pachet. Încurajăm utilizatorii să facă acest lucru
exploatează numeroasele instrumente disponibile pentru analiza urmelor pcap. În acest tutorial, noi
concentrați-vă pe vizualizarea urmelor pcap cu tcpdump.

Codul folosit pentru a activa urmărirea pcap este o singură linie.

pointToPoint.EnablePcapAll ("myfirst");

Continuați și introduceți această linie de cod după codul de urmărire ASCII pe care tocmai l-am adăugat
zgârietură/myfirst.cc. Observați că am trecut doar șirul „myfirst”, și nu
„myfirst.pcap” sau ceva similar. Acest lucru se datorează faptului că parametrul este un prefix, nu un
numele complet al fișierului. Asistentul va crea de fapt un fișier de urmărire pentru fiecare punct la punct
dispozitiv în simulare. Numele fișierelor vor fi construite folosind prefixul, numărul nodului,
numărul dispozitivului și un sufix „.pcap”.

În exemplul nostru de script, vom vedea în cele din urmă fișiere numite „myfirst-0-0.pcap” și
„myfirst-1-0.pcap” care sunt urmele pcap pentru nodul 0-dispozitiv 0 și nodul 1-dispozitiv 0,
respectiv.

După ce ați adăugat linia de cod pentru a activa urmărirea pcap, puteți rula scriptul în fișierul
mod obișnuit:

$ ./waf --run scratch/myfirst

Dacă vă uitați la directorul de nivel superior al distribuției dvs., acum ar trebui să vedeți trei jurnal
fișiere: myfirst.tr este fișierul de urmărire ASCII pe care l-am examinat anterior. myfirst-0-0.pcap
si myfirst-1-0.pcap sunt noile fișiere pcap pe care tocmai le-am generat.

Citind producție cu tcpdump
Cel mai ușor lucru de făcut în acest moment va fi să utilizați tcpdump a se uita la pcap fișiere.

$ tcpdump -nn -tt -r myfirst-0-0.pcap
citire din fișierul myfirst-0-0.pcap, tip link PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, lungime 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, lungime 1024

tcpdump -nn -tt -r myfirst-1-0.pcap
citire din fișierul myfirst-1-0.pcap, tip link PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, lungime 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, lungime 1024

Puteți vedea în groapa de myfirst-0-0.pcap (dispozitivul client) care este pachetul ecou
trimis la 2 secunde de la simulare. Dacă te uiți la a doua groapă (myfirst-1-0.pcap)
puteți vedea că pachetul este primit la 2.257324 secunde. Vezi că pachetul este
ecou înapoi la 2.257324 secunde în al doilea dump și, în cele din urmă, vedeți că pachetul este
primit înapoi la client în primul dump la 2.514648 secunde.

Citind producție cu Wireshark
Dacă nu sunteți familiarizat cu Wireshark, există un site web disponibil de pe care puteți
descărcați programe și documentație: http://www.wireshark.org/.

Wireshark este o interfață grafică de utilizator care poate fi utilizată pentru afișarea acestor urme
fișiere. Dacă aveți Wireshark disponibil, puteți deschide fiecare dintre fișierele de urmărire și puteți afișa
conținutul ca și cum ați fi capturat pachetele folosind a pachet sniffer.

BUILDING TOPOLOGII


Clădire a Autobuz Reţea Topologie
În această secțiune ne vom extinde stăpânirea ns-3 dispozitive de rețea și canale către
acoperă un exemplu de rețea de autobuze. ns-3 oferă un dispozitiv net și un canal pe care îl numim CSMA
(Acces multiplu Carrier Sense).

ns-3 Dispozitivul CSMA modelează o rețea simplă în spiritul Ethernet. Un adevărat Ethernet
folosește schema CSMA/CD (Acces multiplu cu sens de transportator cu detectare a coliziunilor) cu
creșterea exponențială a retragerii pentru a lupta pentru mediul de transmisie partajat. The ns-3
Dispozitivele CSMA și modelele de canale sunt doar un subset din acesta.

Așa cum am văzut obiecte de ajutor de topologie punct la punct la construcție
topologii punct la punct, vom vedea ajutoare de topologie CSMA echivalente în această secțiune.
Aspectul și funcționarea acestor ajutoare ar trebui să vă pară destul de familiare.

Oferim un exemplu de script în directorul nostru exemple/tutorial}. Acest script se bazează pe
il mai întâi.cc script și adaugă o rețea CSMA la simularea punct la punct pe care o avem deja
considerată. Du-te înainte și deschide exemple/tutorial/second.cc în editorul tău preferat. Tu
va fi văzut deja destul ns-3 cod pentru a înțelege majoritatea a ceea ce se întâmplă în asta
exemplu, dar vom trece peste întregul script și vom examina o parte din rezultat.

La fel ca în mai întâi.cc exemplu (și în toate exemplele ns-3) fișierul începe cu un emacs
linie de mod și niște boilerplate GPL.

Codul propriu-zis începe prin încărcarea fișierelor include module exact așa cum sa făcut în mai întâi.cc
exemplu.

#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”

Un lucru care poate fi surprinzător de util este un pic de artă ASCII care arată un desen animat
a topologiei de rețea construită în exemplu. Veți găsi un „desen” similar în
majoritatea exemplelor noastre.

În acest caz, puteți vedea că vom extinde exemplul nostru punct la punct (linkul
între nodurile n0 și n1 de mai jos) prin agățarea unei rețele de autobuz pe partea dreaptă. Înștiințare
că aceasta este topologia implicită de rețea, deoarece puteți varia efectiv numărul de noduri
creat pe LAN. Dacă setați nCsma la unul, vor exista în total două noduri pe
LAN (canal CSMA) --- un nod necesar și un nod „extra”. Implicit sunt trei
noduri „extra”, așa cum se vede mai jos:

// Topologie de rețea implicită
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// punct la punct | | | |
// ================
// LAN 10.1.2.0

Atunci spațiul de nume ns-3 este utilizat și este definită o componentă de înregistrare. Toate acestea sunt la fel ca
a fost în mai întâi.cc, deci nu este nimic nou încă.

folosind namespace ns3;

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

Programul principal începe cu o întorsătură ușor diferită. Folosim un steag verboz pentru
determina dacă sau nu UdpEchoClientApplication si UdpEchoServerApplication logare
componentele sunt activate. Acest indicator este implicit adevărat (componentele de înregistrare sunt activate)
dar ne permite să dezactivăm înregistrarea în timpul testării de regresie a acestui exemplu.

Veți vedea un cod familiar care vă va permite să schimbați numărul de dispozitive de pe
Rețeaua CSMA prin argumentul liniei de comandă. Am făcut ceva similar când am permis
numărul de pachete trimise pentru a fi schimbat în secțiunea privind argumentele liniei de comandă. Ultimul
linia se asigură că aveți cel puțin un nod „extra”.

Codul constă din variații ale API-ului acoperit anterior, așa că ar trebui să fiți în întregime
confortabil cu următorul cod în acest moment al tutorialului.

bool verbose = adevărat;
uint32_t nCsma = 3;

CommandLine cmd;
cmd.AddValue ("nCsma", "Numărul de noduri/dispozitive CSMA \"extra\", nCsma);
cmd.AddValue ("verbos", "Spune aplicațiilor echo să se înregistreze dacă este adevărat", verbose);

cmd.Parse (argc, argv);

dacă (verbos)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

nCsma = nCsma == 0 ? 1 : nCsma;

Următorul pas este să creăm două noduri pe care le vom conecta prin legătura punct la punct.
NodeContainer este folosit pentru a face acest lucru așa cum sa făcut în mai întâi.cc.

NodeContainer p2pNodes;
p2pNodes.Create (2);

În continuare, declarăm altul NodeContainer pentru a ține nodurile care vor face parte din autobuz
(CSMA). În primul rând, instanțiem obiectul container în sine.

NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

Următoarea linie de cod Devine primul nod (ca avand un indice de unu) din
container de noduri punct la punct și îl adaugă la containerul de noduri care va primi CSMA
dispozitive. Nodul în cauză va ajunge cu un dispozitiv punct la punct si un CSMA
dispozitiv. Apoi creăm un număr de noduri „extra” care compun restul CSMA
reţea. Deoarece avem deja un nod în rețeaua CSMA -- cel care va avea
atât un dispozitiv punct la punct, cât și un dispozitiv net CSMA, numărul de noduri „extra” înseamnă numărul
nodurile pe care le doriți în secțiunea CSMA minus unu.

Următorul fragment de cod ar trebui să fie destul de familiar până acum. Instanțiem a PointToPointHelper
și setați valoarea implicită asociată Atribute astfel încât să creăm un număr de cinci megabiți pe secundă
transmițător pe dispozitivele create folosind ajutorul și o întârziere de două milisecunde pe canale
creat de ajutor.

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

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

Apoi instanțiem a NetDeviceContainer pentru a ține evidența dispozitivelor de rețea punct la punct
și noi Instalare dispozitive pe nodurile punct la punct.

Am menționat mai sus că urma să vedeți un ajutor pentru dispozitivele și canalele CSMA și
rândurile următoare le prezintă. The CsmaHelper funcționează la fel ca un PointToPointHelper, Dar
creează și conectează dispozitive și canale CSMA. În cazul unui dispozitiv CSMA și
pereche de canale, observați că rata de date este specificată de a canal Atribut în loc de a
dispozitiv Atribut. Acest lucru se datorează faptului că o rețea CSMA reală nu permite să se amestece, pt
exemplu, dispozitive 10Base-T și 100Base-T pe un canal dat. Mai întâi setăm rata de date la
100 megabiți pe secundă, apoi setați întârzierea vitezei luminii a canalului la 6560
nanosecunde (alese în mod arbitrar ca 1 nanosecundă pe picior pe un segment de 100 de metri).
Observați că puteți seta un Atribut folosind tipul său nativ de date.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Întârziere", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

La fel cum am creat un NetDeviceContainer pentru a ține dispozitivele create de
PointToPointHelper creăm un NetDeviceContainer pentru a ține dispozitivele create de noi
CsmaHelper. Noi numim Instalare metodă a CsmaHelper pentru a instala dispozitivele în
noduri ale csmaNodes NodeContainer.

Acum avem nodurile, dispozitivele și canalele create, dar nu avem stive de protocoale
prezent. La fel ca în mai întâi.cc scriptul, vom folosi InternetStackHelper a instala
aceste stive.

InternetStackHelper stivă;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);

Amintiți-vă că am luat unul dintre nodurile din p2pNodes recipient și l-a adăugat la
csmaNodes recipient. Astfel, trebuie doar să instalăm stivele pe restul p2pNodes
nod și toate nodurile din csmaNodes container pentru a acoperi toate nodurile din
simulare.

La fel ca în mai întâi.cc exemplu de script, vom folosi IPv4AddressHelper la
atribuiți adrese IP interfețelor dispozitivelor noastre. Mai întâi folosim rețeaua 10.1.1.0 pentru a crea
cele două adrese necesare pentru cele două dispozitive punct-la-punct.

Adresă Ipv4AddressHelper;
adresa.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfețe;
p2pInterfaces = adresa.Assign (p2pDevices);

Amintiți-vă că salvăm interfețele create într-un container pentru a fi ușor de scos
adresarea informațiilor ulterioare pentru utilizare la configurarea aplicațiilor.

Acum trebuie să atribuim adrese IP interfețelor dispozitivelor noastre CSMA. Operația funcționează
la fel cum a făcut pentru cazul punct la punct, cu excepția faptului că acum efectuăm operația
un container care are un număr variabil de dispozitive CSMA --- amintiți-vă că am făcut numărul de
Dispozitivele CSMA pot fi schimbate prin argumentul liniei de comandă. Dispozitivele CSMA vor fi asociate
cu adrese IP de la numărul de rețea 10.1.2.0 în acest caz, așa cum se vede mai jos.

adresa.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = adresa.Assign (csmaDevices);

Acum avem o topologie construită, dar avem nevoie de aplicații. Această secțiune va fi
fundamental similar cu secțiunea de aplicații a mai întâi.cc dar vom merge
instanțiați serverul pe unul dintre nodurile care are un dispozitiv CSMA și clientul pe
nod având doar un dispozitiv punct la punct.

Mai întâi, am configurat serverul echo. Creăm un UdpEchoServerHelper și furnizați o solicitare
Atribut valoare pentru constructor, care este numărul portului serverului. Amintiți-vă că acest port
poate fi schimbat ulterior folosind SetAttribute metoda dacă se dorește, dar cerem să fie
furnizate constructorului.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Secunde (1.0));
serverApps.Stop (Secunde (10.0));

Reamintim că csmaNodes NodeContainer conține unul dintre nodurile create pentru
reţea punct la punct şi nCsma noduri „extra”. La ce vrem să ajungem este ultimul dintre
noduri „extra”. Cea de-a zero intrare a csmaNodes containerul va fi punct la punct
nodul. Prin urmare, modul ușor de a gândi la asta este dacă creăm un nod CSMA „în plus”, atunci acesta
va fi la indexul unul dintre csmaNodes recipient. Prin inducție, dacă creăm nCsma "suplimentar"
noduri ultimul va fi la index nCsma. Vedeți acest lucru expus în Obține din prima
linie de cod.

Aplicația client este configurată exact așa cum am făcut-o în mai întâi.cc exemplu de script. Din nou,
oferim necesar Atribute la UdpEchoClientHelper în constructor (în acest caz
adresa și portul de la distanță). Îi spunem clientului să trimită pachete către serverul pe care tocmai l-am făcut
instalat pe ultimul dintre nodurile CSMA „extra”. Instalăm clientul în partea stângă
nod punct la punct văzut în ilustrația topologiei.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Secunde (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0));
clientApps.Start (Secunde (2.0));
clientApps.Stop (Secunde (10.0));

Deoarece am construit de fapt un internetwork aici, avem nevoie de o formă de internetwork
rutare. ns-3 oferă ceea ce numim rutare globală pentru a vă ajuta. Rutarea globală ia
avantajul faptului că întreaga interconectare este accesibilă în simulare și
trece prin toate nodurile create pentru simulare --- face munca grea
configurați rutarea pentru dvs. fără a fi nevoie să configurați routerele.

Practic, ceea ce se întâmplă este că fiecare nod se comportă ca și cum ar fi un router OSPF care
comunică instantaneu și magic cu toate celelalte routere din culise. Fiecare nod
generează reclame de link și le comunică direct unui manager global de rute
care utilizează aceste informații globale pentru a construi tabelele de rutare pentru fiecare nod. Setare
această formă de rutare este o singură linie:

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Apoi, activăm urmărirea pcap. Prima linie de cod pentru a activa urmărirea pcap în fișierul
asistentul punct la punct ar trebui să vă fie familiar până acum. A doua linie activează pcap
urmărirea în ajutorul CSMA și există un parametru suplimentar pe care nu l-ați întâlnit încă.

pointToPoint.EnablePcapAll ("al doilea");
csma.EnablePcap ("al doilea", csmaDevices.Get (1), true);

Rețeaua CSMA este o rețea multi-punct-la-punct. Aceasta înseamnă că pot (și sunt în
în acest caz) puncte finale multiple pe un mediu partajat. Fiecare dintre aceste puncte finale are o rețea
dispozitiv asociat cu acesta. Există două alternative de bază la colectarea urmelor
informații dintr-o astfel de rețea. O modalitate este de a crea un fișier de urmărire pentru fiecare dispozitiv net
și stocați numai pachetele care sunt emise sau consumate de acel dispozitiv net. Altă cale
este să alegeți unul dintre dispozitive și să-l plasați în modul promiscuu. Atunci acel singur dispozitiv
„adulmecă” rețeaua pentru toate pachetele și le stochează într-un singur fișier pcap. Acesta este cum
tcpdump, de exemplu, funcționează. Acest parametru final îi spune asistentului CSMA dacă să facă sau nu
aranjați să capturați pachetele în modul promiscuu.

În acest exemplu, vom selecta unul dintre dispozitivele din rețeaua CSMA și îl vom întreba
pentru a efectua un miros promiscuu al rețelei, emulând astfel ce tcpdump ar face.
Dacă ați fi pe o mașină Linux, ați putea face ceva de genul tcpdump -i eth0 Pentru a obține
urmă. În acest caz, specificăm dispozitivul care utilizează csmaDevices.Get(1), care selectează
primul dispozitiv din container. Setarea parametrului final la true permite promiscuitatea
captează.

Ultima secțiune de cod pur și simplu rulează și curăță simularea la fel ca și mai întâi.cc
exemplu.

Simulator::Run ();
Simulator::Destroy ();
0 reveni;
}

Pentru a rula acest exemplu, copiați fișierul al doilea.cc exemplu de script în directorul scratch
și folosește waf pentru a construi așa cum ai făcut cu mai întâi.cc exemplu. Dacă sunteți în
directorul de nivel superior al depozitului pe care tocmai îl tastați,

$ cp exemple/tutorial/second.cc scratch/mysecond.cc
$ ./waf

Atenție: folosim fișierul al doilea.cc ca unul dintre testele noastre de regresie pentru a verifica dacă funcționează
exact așa cum credem că ar trebui, pentru a face din experiența dvs. tutorială una pozitivă.
Aceasta înseamnă că un executabil numit al doilea există deja în proiect. Pentru a evita orice
confuzie cu privire la ceea ce executați, vă rugăm să faceți redenumirea a doua mea.cc sugerat
de mai sus.

Dacă urmați tutorialul în mod religios (ești, nu-i așa) vei avea totuși
setul de variabile NS_LOG, așa că mergeți mai departe și ștergeți acea variabilă și rulați programul.

$ export NS_LOG=
$ ./waf --run scratch/mysecond

Deoarece am configurat aplicațiile UDP Echo pentru a se conecta exact așa cum am făcut-o mai întâi.cc, tu vei
vedeți rezultate similare când rulați scriptul.

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.415s)
A trimis 1024 de octeți la 10.1.2.4
A primit 1024 de octeți de la 10.1.1.1
A primit 1024 de octeți de la 10.1.2.4

Amintiți-vă că primul mesaj, "Trimisa 1024 bytes la 10.1.2.4," este clientul de eco UDP
trimiterea unui pachet către server. În acest caz, serverul se află pe o altă rețea
(10.1.2.0). Al doilea mesaj, "Primit 1024 bytes din 10.1.1.1," este din ecoul UDP
server, generat când primește pachetul ecou. Mesajul final, "Primit 1024
bytes din 10.1.2.4," este de la clientul echo, indicând că a primit ecoul
înapoi de la server.

Dacă acum mergeți și căutați în directorul de nivel superior, veți găsi trei fișiere de urmărire:

second-0-0.pcap second-1-0.pcap second-2-0.pcap

Să ne uităm puțin la denumirea acestor fișiere. Toate au aceeași formă,
- - .pcap. De exemplu, primul fișier din listă este
secunda-0-0.pcap care este urma pcap de la nodul zero, dispozitivul zero. Acesta este
dispozitiv net punct la punct pe nodul zero. Fișierul secunda-1-0.pcap este urma pcap pentru
dispozitiv zero pe nodul unu, de asemenea un dispozitiv net punct la punct; si dosarul secunda-2-0.pcap is
urma pcap pentru dispozitivul zero pe nodul doi.

Dacă vă referiți înapoi la ilustrația topologiei de la începutul secțiunii, veți vedea
acel nod zero este nodul cel mai din stânga al legăturii punct la punct, iar nodul unu este nodul
care are atât un dispozitiv punct la punct, cât și un dispozitiv CSMA. Veți vedea că nodul doi este
primul nod „extra” din rețeaua CSMA și dispozitivul său zero a fost selectat ca dispozitiv
pentru a capta urma în mod promiscuu.

Acum, să urmărim pachetul de ecou prin internetwork. Mai întâi, faceți un tcpdump al
fișier de urmărire pentru nodul cel mai din stânga punct la punct --- nodul zero.

$ tcpdump -nn -tt -r secund-0-0.pcap

Ar trebui să vedeți afișat conținutul fișierului pcap:

citire din fișierul secund-0-0.pcap, tip link PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

Prima linie a dump-ului indică faptul că tipul de legătură este PPP (point-to-point), ceea ce noi
aştepta. Apoi vedeți pachetul de eco care părăsește nodul zero prin intermediul dispozitivului asociat cu IP
adresa 10.1.1.1 îndreptată către adresa IP 10.1.2.4 (nodul CSMA din dreapta). Acest pachet
se va deplasa peste legătura punct la punct și va fi primit de dispozitivul de rețea punct la punct
nodul unu. Hai să aruncăm o privire:

$ tcpdump -nn -tt -r secund-1-0.pcap

Ar trebui să vedeți acum ieșirea urmăririi pcap de cealaltă parte a link-ului punct la punct:

citire din fișierul secund-1-0.pcap, tip link PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

Aici vedem că tipul de link este și PPP așa cum ne-am aștepta. Vedeți pachetul de la IP
adresa 10.1.1.1 (care a fost trimisă la 2.000000 de secunde) se îndrepta către adresa IP 10.1.2.4
apar pe această interfață. Acum, intern la acest nod, pachetul va fi redirecționat către
interfața CSMA și ar trebui să o vedem iese pe acel dispozitiv îndreptându-se spre finalul său
destinaţie.

Amintiți-vă că am selectat nodul 2 ca nod sniffer promiscuu pentru rețeaua CSMA, deci
Să ne uităm apoi la second-2-0.pcap și să vedem dacă este acolo.

$ tcpdump -nn -tt -r secund-2-0.pcap

Ar trebui să vedeți acum descărcarea promiscuă a nodului doi, dispozitivul zero:

citire din fișierul second-2-0.pcap, tip link EN10MB (Ethernet)
2.007698 ARP, Solicitați cine-are 10.1.2.4 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.1, lungime 50
2.007710 ARP, Răspuns 10.1.2.4 este la 00:00:00:00:00:06, lungime 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024
2.013815 ARP, Solicitați cine-are 10.1.2.1 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.4, lungime 50
2.013828 ARP, Răspuns 10.1.2.1 este la 00:00:00:00:00:03, lungime 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

După cum puteți vedea, tipul de link este acum „Ethernet”. A apărut însă ceva nou. The
nevoile rețelei de autobuze ARP, Protocolul de rezoluție a adreselor. Nodul unu știe că trebuie trimis
pachetul la adresa IP 10.1.2.4, dar nu știe adresa MAC a
nodul corespunzător. Emite pe rețeaua CSMA (ff:ff:ff:ff:ff:ff) solicitând
dispozitiv care are adresa IP 10.1.2.4. În acest caz, nodul din dreapta răspunde spunând acest lucru
este la adresa MAC 00:00:00:00:00:06. Rețineți că nodul doi nu este direct implicat în acest lucru
schimb, dar adulmecă rețeaua și raportează tot traficul pe care îl vede.

Acest schimb este văzut în rândurile următoare,

2.007698 ARP, Solicitați cine-are 10.1.2.4 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.1, lungime 50
2.007710 ARP, Răspuns 10.1.2.4 este la 00:00:00:00:00:06, lungime 50

Apoi nodul unu, dispozitivul unu merge înainte și trimite pachetul de eco la serverul de eco UDP la
Adresa IP 10.1.2.4.

2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024

Serverul primește cererea de eco și întoarce pachetul încercând să-l trimită înapoi
sursa. Serverul știe că această adresă se află pe o altă rețea prin care ajunge
Adresa IP 10.1.2.1. Acest lucru se datorează faptului că am inițializat rutarea globală și a înțeles totul
de asta pentru noi. Dar, nodul serverului echo nu știe adresa MAC a primului
Nod CSMA, așa că trebuie să ARP pentru el, așa cum a trebuit să facă primul nod CSMA.

2.013815 ARP, Solicitați cine-are 10.1.2.1 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.4, lungime 50
2.013828 ARP, Răspuns 10.1.2.1 este la 00:00:00:00:00:03, lungime 50

Serverul trimite apoi ecoul înapoi la nodul de redirecționare.

2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

Privind înapoi la nodul din dreapta al legăturii punct la punct,

$ tcpdump -nn -tt -r secund-1-0.pcap

Acum puteți vedea pachetul cu ecou revenind pe legătura punct la punct ca ultimul
linia depozitului de urme.

citire din fișierul secund-1-0.pcap, tip link PPP (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

În cele din urmă, puteți privi înapoi la nodul care a generat ecoul

$ tcpdump -nn -tt -r secund-0-0.pcap

și vezi că pachetul cu ecou ajunge înapoi la sursă la 2.007602 secunde,

citire din fișierul secund-0-0.pcap, tip link PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lungime 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lungime 1024

În cele din urmă, amintiți-vă că am adăugat capacitatea de a controla numărul de dispozitive CSMA în
simulare prin argument de linie de comandă. Puteți schimba acest argument în același mod ca atunci când
ne-am uitat la schimbarea numărului de pachete cu ecou în mai întâi.cc exemplu. Încearcă să alergi
programul cu numărul de dispozitive „extra” setat la patru:

$ ./waf --run "scratch/mysecond --nCsma=4"

Ar trebui să vezi acum,

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.405s)
La momentul respectiv, clientul 2s a trimis 1024 de octeți către portul 10.1.2.5 9
La momentul respectiv, serverul 2.0118s a primit 1024 de octeți de la portul 10.1.1.1 49153
La momentul respectiv, serverul 2.0118s a trimis 1024 de octeți la portul 10.1.1.1 49153
La momentul respectiv, clientul 2.02461s a primit 1024 de octeți de la portul 10.1.2.5 9

Observați că serverul echo a fost acum mutat la ultimul dintre nodurile CSMA, adică
10.1.2.5 în loc de cazul implicit, 10.1.2.4.

Este posibil să nu fiți mulțumit de un fișier de urmărire generat de un spectator în
rețeaua CSMA. Este posibil să doriți cu adevărat să obțineți o urmă de pe un singur dispozitiv și este posibil să nu
fii interesat de orice alt trafic din rețea. Puteți face acest lucru destul de ușor.

Să aruncăm o privire zgârietură/secunda mea.cc și adăugați acel cod, permițându-ne să fim mai mulți
specific ns-3 ajutoarele oferă metode care iau un număr de nod și un număr de dispozitiv ca
parametrii. Continuați și înlocuiți EnablePcap apeluri cu apelurile de mai jos.

pointToPoint.EnablePcap ("al doilea", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("al doilea", csmaNodes.Get (nCsma)->GetId (), 0, false);
csma.EnablePcap ("al doilea", csmaNodes.Get (nCsma-1)->GetId (), 0, false);

Știm că vrem să creăm un fișier pcap cu numele de bază „second” și mai știm
că dispozitivul de interes în ambele cazuri va fi zero, deci acei parametri nu sunt
foarte interesant.

Pentru a obține numărul nodului, aveți două opțiuni: mai întâi, nodurile sunt numerotate cu a
modă crescândă monoton începând de la zero în ordinea în care ai creat
lor. O modalitate de a obține un număr de nod este să descoperiți acest număr „manual” prin
contemplând ordinea creării nodurilor. Dacă aruncați o privire la topologia rețelei
ilustrație de la începutul fișierului, am făcut asta pentru dvs. și puteți vedea că
ultimul nod CSMA va fi numărul nodului nCsma + 1. Această abordare poate deveni enervantă
dificil în simulări mai mari.

O modalitate alternativă, pe care o folosim aici, este să ne dăm seama că NodeContainers conţine
indicii către ns-3 Nod Obiecte. The Nod Obiectul are o metodă numită GetId care va
returnează ID-ul nodului respectiv, care este numărul nodului pe care îl căutăm. Să mergem să aruncăm o privire la
Doxygen pentru Nod și localizați acea metodă, care este mai jos în ns-3 cod de bază
decât am văzut până acum; dar uneori trebuie să cauți cu sârguință lucruri utile.

Accesați documentația Doxygen pentru lansarea dvs. (rețineți că o puteți găsi pe
site-ul web al proiectului). Puteți ajunge la Nod documentație uitându-se prin intermediul
fila „Clasuri” și derulând în jos „Lista de clase” până când găsiți ns3::Node. Selecta
ns3::Node și veți fi dus la documentația pentru Nod clasă. Dacă tu acum
derulați în jos la GetId metoda și selectați-o, veți fi dus la detaliile
documentația pentru metodă. Folosind GetId metoda poate determina numerele de noduri
mult mai ușor în topologiile complexe.

Să ștergem fișierele de urmărire vechi din directorul de nivel superior pentru a evita confuzia
Ce se întâmplă,

$ rm *.pcap
$ rm *.tr

Dacă construiți noul script și rulați setarea de simulare nCsma la 100,

$ ./waf --run "scratch/mysecond --nCsma=100"

veți vedea următoarea ieșire:

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.407s)
La momentul respectiv, clientul 2s a trimis 1024 de octeți către portul 10.1.2.101 9
La momentul respectiv, serverul 2.0068s a primit 1024 de octeți de la portul 10.1.1.1 49153
La momentul respectiv, serverul 2.0068s a trimis 1024 de octeți la portul 10.1.1.1 49153
La momentul respectiv, clientul 2.01761s a primit 1024 de octeți de la portul 10.1.2.101 9

Rețineți că serverul echo este acum situat la 10.1.2.101, ceea ce corespunde cu 100
noduri CSMA „extra” cu serverul echo pe ultimul. Dacă enumerați fișierele pcap în
directorul de nivel superior pe care îl veți vedea,

second-0-0.pcap second-100-0.pcap second-101-0.pcap

Fișierul de urmărire secunda-0-0.pcap este dispozitivul punct la punct „cel mai din stânga” care este ecoul
sursa pachetului. Fișierul secunda-101-0.pcap corespunde dispozitivului CSMA din dreapta care
este locul unde se află serverul echo. Poate ați observat că parametrul final de pe
apelul pentru a activa urmărirea pcap pe nodul serverului echo a fost fals. Aceasta înseamnă că urma
adunate pe acel nod era în modul non-promiscuu.

Pentru a ilustra diferența dintre urmele promiscue și non-promiscue, noi de asemenea
a solicitat o urmă nepromiscuă pentru penultimul nod. Haideți și aruncați o privire la
il tcpdump pentru secunda-100-0.pcap.

$ tcpdump -nn -tt -r secund-100-0.pcap

Acum puteți vedea că nodul 100 este într-adevăr un spectator în schimbul de ecou. Singura
pachetele pe care le primește sunt cererile ARP care sunt transmise întregului CSMA
rețea.

citire din fișierul second-100-0.pcap, tip link EN10MB (Ethernet)
2.006698 ARP, Solicitați cine-are 10.1.2.101 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.1, lungime 50
2.013815 ARP, Solicitați cine-are 10.1.2.1 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.101, lungime 50

Acum aruncați o privire la tcpdump pentru secunda-101-0.pcap.

$ tcpdump -nn -tt -r secund-101-0.pcap

Acum puteți vedea că nodul 101 este într-adevăr participant la schimbul de ecou.

citire din fișierul second-101-0.pcap, tip link EN10MB (Ethernet)
2.006698 ARP, Solicitați cine-are 10.1.2.101 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.1, lungime 50
2.006698 ARP, Răspuns 10.1.2.101 este la 00:00:00:00:00:67, lungime 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, lungime 1024
2.013803 ARP, Solicitați cine-are 10.1.2.1 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.101, lungime 50
2.013828 ARP, Răspuns 10.1.2.1 este la 00:00:00:00:00:03, lungime 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, lungime 1024

modele, Atribute si Realitate
Acesta este un loc convenabil pentru a face o mică excursie și pentru a face un punct important. Aceasta poate
sau poate să nu fie evident pentru dvs., dar ori de câte ori se utilizează o simulare, este important
înțelegeți exact ce este modelat și ce nu. Este tentant, de exemplu, să
gândiți-vă la dispozitivele și canalele CSMA utilizate în secțiunea anterioară ca și cum ar fi reale
Dispozitive Ethernet; și să ne așteptăm ca rezultatul simulării să reflecte direct ceea ce se va întâmpla
într-un Ethernet real. Nu este cazul.

Un model este, prin definiție, o abstractizare a realității. În cele din urmă este responsabilitatea
al autorului scriptului de simulare pentru a determina așa-numita „gamă de precizie” și „domeniu
de aplicabilitate" a simulării în ansamblu și, prin urmare, a părților sale constitutive.

În unele cazuri, cum ar fi Csma, poate fi destul de ușor să determinați ce este nu modelat. De
citind descrierea modelului (csma.h) puteți constata că nu există nicio detectare a coliziunilor
în modelul CSMA și decideți cât de aplicabilă va fi utilizarea sa în simularea dvs. sau ce
avertismente pe care poate doriți să le includeți în rezultatele dvs. În alte cazuri, poate fi destul de ușor
pentru a configura comportamente care s-ar putea să nu fie de acord cu nicio realitate pe care le puteți cumpăra. Aceasta
se va dovedi că merită să petreci ceva timp investigând câteva astfel de cazuri și cum
cu ușurință poți să devii în afara limitelor realității în simulările tale.

După cum ați văzut, ns-3 furnizează Atribute pe care un utilizator îl poate seta cu ușurință pentru a schimba modelul
comportament. Luați în considerare două dintre Atribute a CsmaNetDevice: MTU si
Modul de încapsulare. MTU Atributul indică unitatea de transmisie maximă către
dispozitiv. Aceasta este dimensiunea celei mai mari unități de date de protocol (PDU) pe care o poate face dispozitivul
trimite.

MTU este implicit la 1500 de octeți în CsmaNetDevice. Această implicită corespunde unui număr
găsit în RFC 894, „Un standard pentru transmiterea de datagrame IP prin Ethernet
Rețele." Numărul este de fapt derivat din dimensiunea maximă a pachetului pentru 10Base5
rețele (Ethernet cu specificații complete) -- 1518 octeți. Dacă scădeți încapsularea DIX
overhead pentru pachetele Ethernet (18 octeți) veți ajunge cu o dimensiune maximă de date posibilă
(MTU) de 1500 de octeți. Se poate constata, de asemenea, că MTU pentru rețelele IEEE 802.3 este 1492
octeți. Acest lucru se datorează faptului că încapsularea LLC/SNAP adaugă încă opt octeți de supraîncărcare
pachetul. În ambele cazuri, hardware-ul de bază poate trimite doar 1518 octeți, dar datele
dimensiunea este diferită.

Pentru a seta modul de încapsulare, CsmaNetDevice oferă un Atribut denumit
Modul de încapsulare care poate prelua valorile Dix or LLC. Acestea corespund Ethernet
și, respectiv, încadrarea LLC/SNAP.

Dacă unul părăsește MTU la 1500 de octeți și schimbă modul de încapsulare în LLC, rezultatul
va fi o rețea care încapsulează PDU-uri de 1500 de octeți cu încadrare LLC/SNAP, rezultând
pachete de 1526 de octeți, ceea ce ar fi ilegal în multe rețele, deoarece pot transmite a
maxim 1518 octeți per pachet. Acest lucru ar duce cel mai probabil la o simulare care
destul de subtil nu reflectă realitatea la care te-ai putea aștepta.

Doar pentru a complica imaginea, există cadre jumbo (1500 < MTU <= 9000 de octeți) și
cadre super-jumbo (MTU > 9000 de octeți) care nu sunt sancționate oficial de IEEE, dar sunt
disponibil în unele rețele și NIC-uri de mare viteză (Gigabit). S-ar putea părăsi
modul de încapsulare setat la Dix, și setați MTU Atribut pe o CsmaNetDevice la 64000 de octeți
-- chiar dacă un asociat CsmaChannel Rata de date a fost setat la 10 megabiți pe secundă. Acest
ar modela, în esență, un comutator Ethernet realizat din 1980Base10, în stilul anilor 5, conectat la vampir.
rețele care acceptă datagrame super-jumbo. Acest lucru cu siguranță nu este ceva care a fost
făcut vreodată și nici nu va fi făcut vreodată, dar este destul de ușor de configurat pentru dvs.

În exemplul anterior, ați folosit linia de comandă pentru a crea o simulare care avea 100
Csma noduri. Ai fi putut crea la fel de ușor o simulare cu 500 de noduri. daca tu
de fapt modelau acea rețea 10Base5 vampire-tap, lungimea maximă a unui full-spec
Cablul Ethernet este de 500 de metri, cu o distanță minimă de 2.5 metri. Asta înseamnă acolo
ar putea fi doar 200 de accesări pe o rețea reală. Ai fi putut destul de ușor să construiești un ilegal
rețeaua și în acest fel. Acest lucru poate duce sau nu la o simulare semnificativă
in functie de ceea ce incerci sa modelezi.

Situații similare pot apărea în multe locuri în ns-3 și în orice simulator. De exemplu,
este posibil să puteți poziționa nodurile în așa fel încât să ocupe același spațiu la
în același timp, sau puteți configura amplificatoare sau niveluri de zgomot care încalcă
legile fundamentale ale fizicii.

ns-3 în general favorizează flexibilitatea, iar multe modele vor permite setarea liberă Atribute
fără a încerca să impună o consecvență arbitrară sau o anumită specificație subiacentă.

Lucrul de luat acasă din asta este că ns-3 va oferi o bază super-flexibilă
pentru ca tu să experimentezi. Depinde de dvs. să înțelegeți ce cereți sistemului
pentru a face și pentru a vă asigura că simulările pe care le creați au o anumită semnificație și altele
legătura cu o realitate definită de tine.

Clădire a Fără fir Reţea Topologie
În această secțiune ne vom extinde în continuare cunoștințele despre ns-3 dispozitive de rețea și
canale pentru a acoperi un exemplu de rețea fără fir. ns-3 oferă un set de modele 802.11
care încearcă să ofere o implementare precisă la nivel MAC a specificației 802.11
și un model „nu atât de lent” la nivel PHY al specificației 802.11a.

Așa cum am văzut atât obiecte de ajutor pentru topologie punct-la-punct, cât și CSMA când
construind topologii punct la punct, vom vedea echivalent Wifi ajutoare de topologie în
aceasta sectiune. Aspectul și funcționarea acestor ajutoare ar trebui să pară destul de familiare
te.

Oferim un exemplu de script în documentul nostru exemple/tutorial director. Acest script se bazează pe
il al doilea.cc script și adaugă o rețea Wifi. Du-te înainte și deschide
exemple/tutorial/a treia.cc în editorul tău preferat. Veți fi văzut deja destule
ns-3 cod pentru a înțelege majoritatea a ceea ce se întâmplă în acest exemplu, dar există câteva noi
lucruri, așa că vom trece peste întregul script și vom examina o parte din rezultat.

La fel ca în al doilea.cc exemplu (și în toate ns-3 exemple) fișierul începe cu un emacs
linie de mod și niște boilerplate GPL.

Aruncă o privire la arta ASCII (reprodusă mai jos) care arată topologia implicită a rețelei
construit în exemplu. Puteți vedea că vom extinde și mai mult exemplul nostru
prin agățarea unei rețele fără fir din partea stângă. Observați că aceasta este o rețea implicită
topologie, deoarece puteți varia efectiv numărul de noduri create pe cablu și fără fir
retelelor. La fel ca în al doilea.cc caz de script, dacă schimbați nCsma, vă va oferi un
numărul de noduri CSMA „extra”. În mod similar, puteți seta nWifi pentru a controla câte STA
nodurile (stație) sunt create în simulare. Întotdeauna va fi unul AP (punct de acces)
nod din rețeaua fără fir. În mod implicit, există trei noduri CSMA „în plus” și trei
fără fir STA noduri.

Codul începe prin a încărca fișierele include module exact așa cum sa făcut în al doilea.cc exemplu.
Există câteva includeri noi corespunzătoare modulului Wifi și mobilității
modul pe care îl vom discuta mai jos.

#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”

Ilustrația topologiei rețelei este următoarea:

// Topologie de rețea implicită
//
// Wifi 10.1.3.0
// AP
// * * * *
// | | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// punct la punct | | | |
// ================
// LAN 10.1.2.0

Puteți vedea că adăugăm un nou dispozitiv de rețea la nodul din partea stângă a
legătura punct la punct care devine punctul de acces pentru rețeaua fără fir. Un numar de
Nodurile wireless STA sunt create pentru a completa noua rețea 10.1.3.0, așa cum se arată în stânga
partea ilustrației.

După ilustrare, ns-3 spatiul de nume este utilizat și este definită o componentă de înregistrare.
Toate acestea ar trebui să fie destul de familiare până acum.

folosind namespace ns3;

NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample");

Programul principal începe la fel al doilea.cc prin adăugarea unor parametri de linie de comandă pentru
activarea sau dezactivarea componentelor de jurnal și pentru modificarea numărului de dispozitive create.

bool verbose = adevărat;
uint32_t nCsma = 3;
uint32_t nWifi = 3;

CommandLine cmd;
cmd.AddValue ("nCsma", "Numărul de noduri/dispozitive CSMA \"extra\", nCsma);
cmd.AddValue ("nWifi", "Număr de dispozitive STA wifi", nWifi);
cmd.AddValue ("verbos", "Spune aplicațiilor echo să se înregistreze dacă este adevărat", verbose);

cmd.Parse (argc,argv);

dacă (verbos)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

La fel ca în toate exemplele anterioare, următorul pas este să creăm două noduri pe care le vom face
conectați-vă prin legătura punct la punct.

NodeContainer p2pNodes;
p2pNodes.Create (2);

Apoi, vedem un vechi prieten. Instanțiem a PointToPointHelper și setați asociatul
lipsă Atribute astfel încât să creăm un transmițător de cinci megabiți pe secundă pe dispozitive
creat folosind ajutorul și o întârziere de două milisecunde pe canalele create de ajutor.
Apoi, Intal dispozitivele de pe noduri și canalul dintre ele.

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

NetDeviceContainer p2pDevices;
p2pDevices = pointToPoint.Install (p2pNodes);

În continuare, declarăm altul NodeContainer pentru a ține nodurile care vor face parte din autobuz
(CSMA).

NodeContainer csmaNodes;
csmaNodes.Add (p2pNodes.Get (1));
csmaNodes.Create (nCsma);

Următoarea linie de cod Devine primul nod (ca avand un indice de unu) din
container de noduri punct la punct și îl adaugă la containerul de noduri care va primi CSMA
dispozitive. Nodul în cauză va ajunge cu un dispozitiv punct la punct și un CSMA
dispozitiv. Apoi creăm un număr de noduri „extra” care compun restul CSMA
rețea.

Apoi instanțiem a CsmaHelper și stabiliți-l Atribute așa cum am făcut în exemplul anterior.
Creăm un NetDeviceContainer pentru a ține evidența dispozitivelor de net CSMA create și apoi noi
Instalare Dispozitivele CSMA pe nodurile selectate.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Întârziere", TimeValue (NanoSeconds (6560)));

NetDeviceContainer csmaDevices;
csmaDevices = csma.Install (csmaNodes);

În continuare, vom crea nodurile care vor face parte din rețeaua Wifi. Noi suntem
va crea un număr de noduri „stație” așa cum este specificat de argumentul liniei de comandă și
vom folosi nodul „cel mai din stânga” al legăturii punct la punct ca nod pentru
punct de acces.

NodeContainer wifiStaNodes;
wifiStaNodes.Create (nWifi);
NodeContainer wifiApNode = p2pNodes.Get (0);

Următorul bit de cod construiește dispozitivele wifi și canalul de interconectare între
aceste noduri wifi. Mai întâi, configuram PHY și ajutoarele de canal:

YansWifiChannelHelper canal = YansWifiChannelHelper::Implicit ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Implicit ();

Pentru simplitate, acest cod folosește configurația implicită a stratului PHY și modelele de canal
care sunt documentate în documentația API doxygen pentru
YansWifiChannelHelper::Implicit si YansWifiPhyHelper::Implicit metode. Odată ce aceste obiecte
sunt create, creăm un obiect canal și îl asociam managerului nostru de obiecte layer PHY
pentru a vă asigura că toate obiectele stratului PHY create de YansWifiPhyHelper împărtășiți
același canal de bază, adică împărtășesc același mediu wireless și pot
comunicare și interferență:

phy.SetChannel (canal.Creare ());

Odată configurat ajutorul PHY, ne putem concentra pe stratul MAC. Aici alegem să lucrăm
cu MAC-uri non-Qos, așa că folosim un obiect NqosWifiMacHelper pentru a seta parametrii MAC.

WifiHelper wifi = WifiHelper::Implicit ();
wifi.SetRemoteStationManager ("ns3::AarfWifiManager");

NqosWifiMacHelper mac = NqosWifiMacHelper::Implicit ();

SetRemoteStationManager metoda îi spune asistentului tipul de algoritm de control al ratei la care trebuie
utilizare. Aici, îi cere ajutorului să folosească algoritmul AARF --- detaliile sunt, desigur,
disponibil în Doxygen.

În continuare, configurăm tipul de MAC, SSID-ul rețelei de infrastructură pe care dorim să o facem
configurați și asigurați-vă că stațiile noastre nu efectuează sondare activă:

Ssid ssid = Ssid ("ns-3-ssid");
mac.SetType ("ns3::StaWifiMac",
„Ssid”, SsidValue (ssid),
„ActiveProbing”, BooleanValue (fals));

Acest cod creează mai întâi un obiect 802.11 service set identifier (SSID) care va fi utilizat
pentru a seta valoarea „Ssid” Atribut implementării stratului MAC. Particularul
tipul de strat MAC care va fi creat de ajutor este specificat de Atribut ca fiind de
tipul „ns3::StaWifiMac”. Utilizarea NqosWifiMacHelper se va asigura că
„QosSupported” Atribut pentru obiectele MAC create este setat fals. Combinația dintre acestea
două configurații înseamnă că instanța MAC creată în continuare va fi un non-QoS non-AP
(STA) într-o infrastructură BSS (adică un BSS cu un AP). În cele din urmă, cel
„ActiveProbing” Atribut este setat la fals. Aceasta înseamnă că cererile de sondă nu vor fi
trimis de MAC-urile create de acest ajutor.

Odată ce toți parametrii specifici stației sunt complet configurați, atât la MAC, cât și la PHY
straturi, putem invoca familiarul nostru acum Instalare metodă de a crea dispozitivele wifi ale acestora
statii:

NetDeviceContainer staDevices;
staDevices = wifi.Install (phy, mac, wifiStaNodes);

Am configurat Wifi pentru toate nodurile noastre STA, iar acum trebuie să configuram AP-ul
(punct de acces) nod. Începem acest proces prin modificarea valorii implicite Atribute a
NqosWifiMacHelper pentru a reflecta cerințele AP.

mac.SetType ("ns3::ApWifiMac",
„Ssid”, SsidValue (ssid));

În acest caz, NqosWifiMacHelper va crea straturi MAC ale „ns3::ApWifiMac”,
acesta din urmă specificând că trebuie creată o instanță MAC configurată ca AP, cu
tip de ajutor care implică faptul că „QosSupported” Atribut ar trebui setat la false - dezactivare
Suport QoS în stil 802.11e/WMM la AP-urile create.

Următoarele linii creează un singur AP care împarte același set de nivel PHY Atribute (Și
canal) ca posturile:

NetDeviceContainer apDevices;
apDevices = wifi.Install (phy, mac, wifiApNode);

Acum, vom adăuga modele de mobilitate. Vrem ca nodurile STA să fie mobile, rătăcitoare
în interiorul unei casete de delimitare și vrem să facem nodul AP staționar. Noi folosim
MobilityHelper pentru a ne face acest lucru ușor. În primul rând, instanțiem a MobilityHelper obiect
și setați câteva Atribute controlând funcționalitatea „alocator de poziție”.

Mobilitate MobilityHelper;

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”));

Acest cod îi spune asistentului de mobilitate să folosească o grilă bidimensională pentru a plasa inițial
noduri STA. Simțiți-vă liber să explorați Doxygen pentru cursuri ns3::GridPositionAllocator pentru a vedea
exact ce se face.

Ne-am aranjat nodurile pe o grilă inițială, dar acum trebuie să le spunem cum să se miște.
Alegem RandomWalk2dMobilityModel care are nodurile să se miște într-o direcție aleatorie la
o viteză aleatorie în jurul unei casete de delimitare.

mobilitate.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
„Margini”, RectangleValue (Dreptunghi (-50, 50, -50, 50)));

Îi spunem acum MobilityHelper pentru a instala modelele de mobilitate pe nodurile STA.

mobilitate.Instalare (wifiStaNodes);

Dorim ca punctul de acces să rămână într-o poziție fixă ​​în timpul simulării. Noi
realizați acest lucru setând modelul de mobilitate pentru acest nod să fie
ns3::ConstantPositionMobilityModel:

mobilitate.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobilitate.Instalare (wifiApNode);

Acum avem nodurile, dispozitivele și canalele noastre create și modelele de mobilitate alese pentru
Noduri Wifi, dar nu avem stive de protocol prezente. Așa cum am făcut anterior multe
ori, vom folosi InternetStackHelper pentru a instala aceste stive.

InternetStackHelper stivă;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);

La fel ca în al doilea.cc exemplu de script, vom folosi IPv4AddressHelper la
atribuiți adrese IP interfețelor dispozitivelor noastre. Mai întâi folosim rețeaua 10.1.1.0 pentru a crea
cele două adrese necesare pentru cele două dispozitive punct-la-punct. Apoi folosim rețeaua 10.1.2.0
pentru a atribui adrese rețelei CSMA și apoi atribuim adrese din rețeaua 10.1.3.0
atât la dispozitivele STA, cât și la AP-ul din rețeaua wireless.

Adresă Ipv4AddressHelper;

adresa.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer p2pInterfețe;
p2pInterfaces = adresa.Assign (p2pDevices);

adresa.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer csmaInterfaces;
csmaInterfaces = adresa.Assign (csmaDevices);

adresa.SetBase ("10.1.3.0", "255.255.255.0");
adresa.Atribuire (staDevices);
adresa.Atribuire (apDevices);

Am plasat serverul echo pe nodul „cel mai din dreapta” din ilustrația de la începutul
fişier. Am mai făcut asta.

UdpEchoServerHelper echoServer (9);

ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma));
serverApps.Start (Secunde (1.0));
serverApps.Stop (Secunde (10.0));

Și am plasat clientul echo pe ultimul nod STA pe care l-am creat, îndreptându-l către serverul pe care îl avem
rețeaua CSMA. Am mai văzut și operațiuni similare.

UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9);
echoClient.SetAttribute ("MaxPackets", UintegerValue (1));
echoClient.SetAttribute ("Interval", TimeValue (Secunde (1.0)));
echoClient.SetAttribute ("PacketSize", UintegerValue (1024));

ApplicationContainer clientApps =
echoClient.Install (wifiStaNodes.Get (nWifi - 1));
clientApps.Start (Secunde (2.0));
clientApps.Stop (Secunde (10.0));

Deoarece am construit aici o rețea de internet, trebuie să activăm rutarea rețelei la fel
am făcut în al doilea.cc exemplu de script.

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Un lucru care îi poate surprinde pe unii utilizatori este faptul că simularea pe care tocmai am creat-o
nu se va opri niciodată „în mod natural”. Acest lucru se datorează faptului că am cerut punctului de acces wireless
genera balize. Va genera balize pentru totdeauna, iar acest lucru va avea ca rezultat un simulator
evenimentele fiind programate în viitor pe termen nelimitat, așa că trebuie să spunem simulatorului să se oprească
chiar dacă poate avea programate evenimente de generare a farurilor. Următoarea linie de cod
spune simulatorului să se oprească, astfel încât să nu simulăm balize pentru totdeauna și să intrăm în ceea ce este
în esență o buclă nesfârșită.

Simulator::Stop (Secunde (10.0));

Creăm suficientă urmărire pentru a acoperi toate cele trei rețele:

pointToPoint.EnablePcapAll ("al treilea");
phy.EnablePcap ("al treilea", apDevices.Get (0));
csma.EnablePcap ("al treilea", csmaDevices.Get (0), true);

Aceste trei linii de cod vor începe urmărirea pcap pe ambele noduri punct la punct care
servește drept coloană vertebrală, va începe o urmărire a modului promiscuu (monitor) în rețeaua Wifi,
și va începe o urmă promiscuă pe rețeaua CSMA. Acest lucru ne va permite să vedem toate
trafic cu un număr minim de fișiere de urmărire.

În cele din urmă, rulăm simularea, curățăm și apoi ieșim din program.

Simulator::Run ();
Simulator::Destroy ();
0 reveni;
}

Pentru a rula acest exemplu, trebuie să copiați fișierul a treia.cc exemplu de script în
directorul scratch și folosește Waf pentru a construi așa cum ai făcut cu al doilea.cc exemplu. daca tu
sunt în directorul de nivel superior al depozitului pe care l-ați tasta,

$ cp exemple/tutorial/third.cc scratch/mythird.cc
$ ./waf
$ ./waf --run scratch/mythird

Din nou, din moment ce am configurat aplicațiile UDP Echo exact așa cum am făcut în al doilea.cc
script, veți vedea rezultate similare.

Waf: se introduce în directorul „/home/craigdo/repos/ns-3-allinone/ns-3-dev/build”
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
„build” finalizat cu succes (0.407s)
La momentul respectiv, clientul 2s a trimis 1024 de octeți către portul 10.1.2.4 9
La momentul respectiv, serverul 2.01796s a primit 1024 de octeți de la portul 10.1.3.3 49153
La momentul respectiv, serverul 2.01796s a trimis 1024 de octeți la portul 10.1.3.3 49153
La momentul respectiv, clientul 2.03364s a primit 1024 de octeți de la portul 10.1.2.4 9

Amintiți-vă că primul mesaj, Trimisa 1024 bytes la 10.1.2.4," este clientul de eco UDP
trimiterea unui pachet către server. În acest caz, clientul se află în rețeaua wireless
(10.1.3.0). Al doilea mesaj, "Primit 1024 bytes din 10.1.3.3," este din ecoul UDP
server, generat când primește pachetul ecou. Mesajul final, "Primit 1024
bytes din 10.1.2.4," este de la clientul echo, indicând că a primit ecoul
înapoi de la server.

Dacă acum mergeți și căutați în directorul de nivel superior, veți găsi patru fișiere de urmărire din
această simulare, două de la nodul zero și două de la nodul unu:

third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap

Fișierul „third-0-0.pcap” corespunde dispozitivului punct la punct de pe nodul zero --
partea stângă a „coloanei vertebrale”. Fișierul „third-1-0.pcap” corespunde punct-la-punct
dispozitiv pe nodul unu -- partea dreaptă a „coloanei vertebrale”. Fișierul „third-0-1.pcap” va fi
urma promiscuă (mod monitor) din rețeaua Wifi și fișierul „third-1-1.pcap”
va fi urma promiscua din reteaua CSMA. Puteți verifica acest lucru prin inspectare
Codul?

Deoarece clientul echo se află în rețeaua Wifi, să începem de acolo. Să aruncăm o privire la
Urmă promiscuă (mod monitor) pe care am capturat-o în acea rețea.

$ tcpdump -nn -tt -r al treilea-0-1.pcap

Ar trebui să vedeți niște conținuturi cu aspect Wi-Fi pe care nu le-ați văzut până acum aici:

citire din fișierul third-0-1.pcap, tip link 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 Solicitare asociat (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 Răspuns conf AJUTORUL(0) :: Reușit
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Solicitare asociat (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 Răspuns conf AJUTORUL(0) :: Reușit
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Solicitare asociat (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 Răspuns conf AJUTORUL(0) :: Reușit
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

Puteți vedea că tipul de link este acum 802.11 așa cum v-ați aștepta. Probabil că poți
înțelegeți ce se întâmplă și găsiți cererile de ecou IP și pachetele de răspuns în aceasta
urmă. Îl lăsăm ca un exercițiu pentru a analiza complet depozitul de urme.

Acum, uitați-vă la fișierul pcap din partea dreaptă a legăturii punct la punct,

$ tcpdump -nn -tt -r al treilea-0-0.pcap

Din nou, ar trebui să vedeți niște conținuturi familiare:

citire din fișierul third-0-0.pcap, tip link PPP (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lungime 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lungime 1024

Acesta este pachetul de eco care merge de la stânga la dreapta (de la Wifi la CSMA) și înapoi din nou
legătura punct la punct.

Acum, uitați-vă la fișierul pcap din partea dreaptă a legăturii punct la punct,

$ tcpdump -nn -tt -r al treilea-1-0.pcap

Din nou, ar trebui să vedeți niște conținuturi familiare:

citire din fișierul third-1-0.pcap, tip link PPP (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lungime 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lungime 1024

Acesta este, de asemenea, pachetul de eco care merge de la stânga la dreapta (de la Wifi la CSMA) și înapoi
de-a lungul legăturii punct la punct, cu timpi ușor diferite, așa cum v-ați aștepta.

Serverul echo este în rețeaua CSMA, să ne uităm la urma promiscuă de acolo:

$ tcpdump -nn -tt -r al treilea-1-1.pcap

Ar trebui să vedeți niște conținuturi cu aspect familiar:

citire din fișierul third-1-1.pcap, tip link EN10MB (Ethernet)
2.017837 ARP, Solicitați cine-are 10.1.2.4 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.1, lungime 50
2.017861 ARP, Răspuns 10.1.2.4 este la 00:00:00:00:00:06, lungime 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lungime 1024
2.022966 ARP, Solicitați cine-are 10.1.2.1 (ff:ff:ff:ff:ff:ff) spuneți 10.1.2.4, lungime 50
2.022966 ARP, Răspuns 10.1.2.1 este la 00:00:00:00:00:03, lungime 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lungime 1024

Acest lucru ar trebui să fie ușor de înțeles. Dacă ați uitat, întoarceți-vă și uitați-vă la discuție
in al doilea.cc. Aceasta este aceeași secvență.

Acum, am petrecut mult timp creând modele de mobilitate pentru rețeaua wireless și așa
ar fi păcat să termin fără a arăta măcar că nodurile STA se mișcă de fapt
în jur în timpul simulării. Să facem asta prin conectarea la Modelul de mobilitate înscrie-te la cursul
modificarea sursei de urmărire. Aceasta este doar o scurtă privire în secțiunea de urmărire detaliată care este
urmează, dar acesta pare un loc foarte frumos pentru a obține un exemplu.

După cum sa menționat în secțiunea „Tweaking ns-3”, sistemul ns-3 sistemul de urmărire este împărțit în urmă
surse și canale de urmărire, iar noi oferim funcții pentru conectarea celor două. Vom folosi
sursa de urmărire a schimbării cursului predefinit de model de mobilitate pentru a genera evenimentele de urmărire. Noi
va trebui să scrie o chiuvetă de urmărire pentru a se conecta la acea sursă care va afișa unele frumoase
informatii pentru noi. În ciuda reputației sale ca fiind dificil, este într-adevăr destul de simplu.
Chiar înainte de programul principal al zgârietură/mythird.cc script (adică imediat după
NS_LOG_COMPONENT_DEFINE declarație), adăugați următoarea funcție:

anula
CourseChange (std::string context, Ptr model)
{
Poziția vectorului = model->GetPosition ();
NS_LOG_UNCOND (context <
" x = " << poziție.x << ", y = " << poziție.y);
}

Acest cod doar extrage informațiile despre poziție din modelul de mobilitate și necondiționat
înregistrează poziția x și y a nodului. Vom aranja ca această funcție să fie
apelat de fiecare dată când nodul wireless cu clientul echo își schimbă poziția. Facem asta
folosind Config::Conectează funcţie. Adăugați următoarele linii de cod la script
inainte de Simulator::Run apel.

std::ostringstream oss;
oss <
„/NodeList/” << wifiStaNodes.Get (nWifi - 1)->GetId () <
„/$ns3::MobilityModel/CourseChange”;

Config::Connect (oss.str (), MakeCallback (&CourseChange));

Ceea ce facem aici este să creăm un șir care să conțină calea de urmărire a spațiului de nume a evenimentului
la care vrem să ne conectăm. În primul rând, trebuie să ne dăm seama ce nod vrem să-l folosim
il GetId metoda descrisă mai devreme. În cazul numărului implicit al CSMA și
noduri wireless, acesta se dovedește a fi nodul șapte și calea de urmărire a spațiului de nume către
modelul de mobilitate ar arăta ca,

/NodeList/7/$ns3::MobilityModel/CourseChange

Pe baza discuției din secțiunea de urmărire, puteți deduce că această cale de urmărire
face referire la cel de-al șaptelea nod din lista globală NodeList. Specifică ceea ce se numește an
obiect agregat de tip ns3::Model de mobilitate. Prefixul semnului dolar implică faptul că
MobilityModel este agregat la nodul șapte. Ultima componentă a căii înseamnă că noi
se conectează la evenimentul „CourseChange” al modelului respectiv.

Facem o conexiune între sursa de urmărire din nodul șapte cu receptorul nostru de urmărire prin apelare
Config::Conectează și trecând această cale de spațiu de nume. Odată făcut acest lucru, fiecare curs se schimbă
evenimentul de pe nodul șapte va fi conectat la chiuveta de urmărire, care, la rândul său, va tipări
Pozitie noua.

Dacă rulați acum simularea, veți vedea modificările cursului afișate pe măsură ce se întâmplă.

„build” finalizat cu succes (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
La momentul respectiv, clientul 2s a trimis 1024 de octeți către portul 10.1.2.4 9
La momentul respectiv, serverul 2.01796s a primit 1024 de octeți de la portul 10.1.3.3 49153
La momentul respectiv, serverul 2.01796s a trimis 1024 de octeți la portul 10.1.3.3 49153
La momentul respectiv, clientul 2.03364s a primit 1024 de octeți de la portul 10.1.2.4 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

URMĂRIREA


Context
După cum s-a menționat în UsingTracingSystem, scopul rulării unui ns-3 simularea este de a
generează rezultate pentru studiu. Aveți două strategii de bază pentru a obține rezultate ns-3:
folosind mecanisme generice de ieșire în bloc predefinite și analizarea conținutului acestora pentru a le extrage
informații interesante; sau cumva dezvoltarea unui mecanism de ieșire care transmite exact
(și poate doar) informațiile dorite.

Utilizarea mecanismelor de ieșire în bloc predefinite are avantajul de a nu necesita nicio modificare
ns-3, dar poate necesita scrierea de scripturi pentru a analiza și a filtra datele de interes. De multe ori,
PCAP sau NS_LOG mesajele de ieșire sunt colectate în timpul rulărilor de simulare și rulate separat
prin scripturi care folosesc grep, sete or Wow pentru a analiza mesajele și a reduce și transforma
datele într-o formă gestionabilă. Programele trebuie scrise pentru a face transformarea, deci asta
nu vine gratis. NS_LOG ieșirea nu este considerată parte a ns-3 API și poate
schimbați fără avertisment între versiuni. În plus, NS_LOG ieșirea este disponibilă numai în
build-uri de depanare, așa că bazarea pe aceasta impune o penalizare de performanță. Desigur, dacă
informația de interes nu există în niciunul dintre mecanismele de ieșire predefinite, aceasta
abordarea eșuează.

Dacă trebuie să adăugați câteva informații la mecanismele predefinite în bloc, acest lucru poate
cu siguranță să se facă; iar dacă utilizați unul dintre ns-3 mecanisme, este posibil să vă adăugați codul
ca contributie.

ns-3 oferă un alt mecanism, numit Urmărire, care evită unele dintre problemele inerente
în mecanismele de ieșire în vrac. Are mai multe avantaje importante. În primul rând, poți
reduceți cantitatea de date pe care trebuie să le gestionați doar urmărind evenimentele care vă interesează
(pentru simulări mari, descărcarea totul pe disc pentru post-procesare poate crea I/O
blocajele). În al doilea rând, dacă utilizați această metodă, puteți controla formatul de ieșire
direct astfel încât să evitați etapa de postprocesare cu sete, Wow, perl or piton scenarii. Dacă
doriți, rezultatul dvs. poate fi formatat direct într-o formă acceptabilă de gnuplot, pentru
exemplu (vezi și GnuplotHelper). Puteți adăuga cârlige în miez care pot fi apoi
accesat de alți utilizatori, dar care nu va produce nicio informație decât dacă este solicitat în mod explicit
face acest lucru. Din aceste motive, credem că ns-3 sistemul de urmărire este cea mai bună modalitate de a obține
informația dintr-o simulare și este, prin urmare, unul dintre cele mai importante mecanisme
a intelege in ns-3.

bont Instrumente
Există multe modalități de a obține informații dintr-un program. Cea mai simplă cale este
pentru a imprima informațiile direct la ieșirea standard, ca în:

#include
...
anula
SomeFunction (nulă)
{
uint32_t x = VALOARE_INTERESTANTĂ;
...
std::cout << "Valoarea lui x este " << x << std::endl;
...
}

Nimeni nu te va împiedica să mergi adânc în miezul ns-3 și adăugarea de imprimare
declarații. Acest lucru este nebun de ușor de făcut și, la urma urmei, aveți control complet asupra dvs
propriu ns-3 ramură. Probabil că acest lucru nu se va dovedi a fi foarte satisfăcător pe termen lung
termen, însă.

Pe măsură ce numărul de instrucțiuni de imprimare crește în programele dvs., sarcina de a se ocupa de
un număr mare de ieșiri va deveni din ce în ce mai complicat. În cele din urmă, s-ar putea să simți
necesitatea de a controla ce informații sunt tipărite într-un fel, poate prin pornire
și dezactivarea anumitor categorii de printuri, sau creșterea sau scăderea cantității de
informatiile dorite. Dacă continui pe această cale, s-ar putea să descoperi că ai
re-implementat NS_LOG mecanism (vezi Utilizarea jurnalelor). Pentru a evita asta, unul dintre
primul lucru pe care l-ați putea lua în considerare este utilizarea NS_LOG însăși.

Am menționat mai sus acea modalitate de a obține informații din ns-3 este de a analiza existente NS_LOG
ieșire pentru informații interesante. Dacă descoperiți că un pic de informații vă
nevoia nu este prezentă în ieșirea jurnalului existent, puteți edita nucleul ns-3 și pur și simplu adăugați
informațiile dvs. interesante pentru fluxul de ieșire. Acum, acest lucru este cu siguranță mai bun decât
adăugând propriile declarații de tipărire, deoarece urmează ns-3 convenţiile de codificare şi ar putea
poate fi util altor persoane ca un patch pentru nucleul existent.

Să alegem un exemplu la întâmplare. Dacă doriți să adăugați mai mult logare la ns-3 socket TCP
(tcp-socket-base.cc) puteți adăuga un mesaj nou în implementare. Înștiințare
că în TcpSocketBase::ReceivedAck() nu există niciun mesaj de jurnal pentru cazul fără ACK. Tu
ar putea pur și simplu să adauge unul, schimbând codul. Iată originalul:

/** Procesează ACK-ul nou primit */
anula
TcpSocketBase::ReceivedAck (Ptr pachet, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (acest << tcpHeader);

// A primit ACK. Comparați numărul ACK cu cel mai mare număr de secvențe neaccesate
dacă (0 == (tcpHeader.GetFlags () și TcpHeader::ACK))
{ // Ignorați dacă nu există semnal ACK
}
...

Pentru a înregistra cazul fără ACK, puteți adăuga un nou NS_LOG_LOGIC în if corpul declarației:

/** Procesează ACK-ul nou primit */
anula
TcpSocketBase::ReceivedAck (Ptr pachet, const TcpHeader& tcpHeader)
{
NS_LOG_FUNCTION (acest << tcpHeader);

// A primit ACK. Comparați numărul ACK cu cel mai mare număr de secvențe neaccesate
dacă (0 == (tcpHeader.GetFlags () și TcpHeader::ACK))
{ // Ignorați dacă nu există semnal ACK
NS_LOG_LOGIC ("TcpSocketBase " << acest << " fără semnalizare ACK");
}
...

Acest lucru poate părea destul de simplu și satisfăcător la prima vedere, dar este ceva de luat în considerare
că veți scrie cod de adăugat NS_LOG afirmatii si va trebui sa scrii si tu
cod (ca în grep, sete or Wow scripturi) pentru a analiza rezultatul jurnalului pentru a izola
informație. Acest lucru se datorează faptului că, deși aveți un anumit control asupra a ceea ce este produs de
sistem de înregistrare, aveți control doar până la nivelul componentei de jurnal, care este de obicei
un întreg fișier de cod sursă.

Dacă adăugați cod la un modul existent, va trebui, de asemenea, să trăiți cu rezultatul
pe care toți ceilalți dezvoltatori l-au găsit interesant. Puteți găsi asta pentru a obține
cantitate mică de informații de care aveți nevoie, este posibil să fiți nevoit să treceți prin cantități uriașe de
mesaje străine care nu vă interesează. Este posibil să fiți forțat să salvați un jurnal uriaș
fișierele pe disc și procesați-le până la câteva linii oricând doriți să faceți ceva.

Deoarece nu există garanții în ns-3 despre stabilitatea NS_LOG ieșire, puteți, de asemenea
descoperiți că bucățile de ieșire a jurnalului de care depindeți dispar sau schimbați între ele
eliberează. Dacă depindeți de structura rezultatului, este posibil să găsiți alte mesaje
adăugat sau șters, ceea ce vă poate afecta codul de analiză.

În cele din urmă, NS_LOG ieșirea este disponibilă numai în versiunile de depanare, nu puteți obține rezultate din jurnal
versiuni optimizate, care rulează de aproximativ două ori mai repede. Bazându-se pe NS_LOG impune o performanță
penalizare.

Din aceste motive, considerăm că printuri std::out si NS_LOG mesajele să fie rapid şi
modalități murdare de a obține mai multe informații din ns-3, dar nu este potrivit pentru muncă serioasă.

Este de dorit să existe o instalație stabilă, folosind API-uri stabile care să permită accesul în
sistemul de bază și obțineți doar informațiile necesare. Este de dorit să poți face
acest lucru fără a fi nevoie să schimbați și să recompilați sistemul de bază. Chiar mai bine ar fi a
sistem care a notificat codul utilizatorului atunci când un articol de interes a fost modificat sau un eveniment interesant
sa întâmplat, astfel încât utilizatorul să nu fie nevoit să caute în mod activ sistemul pe care îl caută
lucruri.

ns-3 sistemul de urmărire este proiectat să funcționeze de-a lungul acestor linii și este bine integrat cu
Atributul și config subsisteme care permit scenarii de utilizare relativ simple.

Descriere
ns-3 sistemul de urmărire este construit pe conceptele de surse independente de urmărire și
trasarea chiuvetelor, împreună cu un mecanism uniform pentru conectarea surselor la chiuvete.

Sursele de urmărire sunt entități care pot semnala evenimente care au loc într-o simulare și pot furniza
acces la date interesante de bază. De exemplu, o sursă de urmărire ar putea indica când a
pachetul este primit de un dispozitiv de rețea și oferă acces la conținutul pachetului pentru
cufundă urme interesate. O sursă de urmărire ar putea indica, de asemenea, când o stare interesantă
schimbarea are loc într-un model. De exemplu, fereastra de congestie a unui model TCP este un prim
candidat pentru o sursă de urmărire. De fiecare dată când fereastra de congestie schimbă traseul conectat
chiuvetele sunt notificate cu valoarea veche și nouă.

Sursele de urmărire nu sunt utile în sine; acestea trebuie să fie conectate la alte bucăți de cod
care fac de fapt ceva util cu informațiile furnizate de sursă. The
entitățile care consumă informații despre urme sunt numite canale de urmărire. Sursele de urme sunt
generatorii de date și de urmărire sunt consumatori. Această împărțire explicită permite mari
un număr de surse de urme care urmează să fie împrăștiate în jurul sistemului în locurile care modelează autorii
cred că ar putea fi util. Inserarea surselor de urmărire introduce o execuție foarte mică
deasupra capului.

Pot exista zero sau mai mulți consumatori de evenimente de urmărire generate de o sursă de urmărire. Se poate
Gândiți-vă la o sursă de urmărire ca la un fel de legătură de informații punct-la-multipunct. Codul tau
căutarea evenimentelor de urmărire dintr-o anumită bucată de cod de bază ar putea coexista fericit cu
alt cod care face ceva complet diferit de aceeași informație.

Cu excepția cazului în care un utilizator conectează un canal de urmărire la una dintre aceste surse, nimic nu este scos. Prin utilizarea
sistemul de urmărire primiți atât dvs., cât și alte persoane conectate la aceeași sursă de urmărire
exact ce vor ei și doar ceea ce vor de la sistem. Nici unul dintre voi nu sunteți
influențând orice alt utilizator prin modificarea informațiilor care sunt transmise de sistem. daca tu
se întâmplă să adăugați o sursă de urmărire, munca dvs. de bun cetățean open-source poate permite altele
utilizatorilor să ofere noi utilități care sunt poate foarte utile în general, fără a face niciuna
modificări la ns-3 nucleu.

simplu Exemplu
Să luăm câteva minute și să parcurgem un exemplu simplu de urmărire. Vom avea nevoie
un mic context despre apeluri inverse pentru a înțelege ce se întâmplă în exemplu, așa că noi
trebuie să faceți imediat un mic ocol.

Rambursări
Scopul sistemului de apel invers în ns-3 este de a permite unei bucăți de cod să apeleze o funcție
(sau metoda în C++) fără nicio dependență specifică între module. Aceasta înseamnă în cele din urmă
aveți nevoie de un fel de indirect -- tratați adresa funcției apelate ca a
variabil. Această variabilă se numește variabilă pointer-to-function. Relația
între funcție și pointer-la-funcție nu este cu adevărat diferită de cea a obiectului și
pointer-la-obiect.

În C exemplul canonic al unui pointer-la-funcție este a
indicator-la-funcție-întoarcere-întreg (PFI). Pentru un PFI care ia unul int parametru, acesta
ar putea fi declarat ca,

int (*pfi)(int arg) = 0;

(Dar citiți C++-Întrebări frecvente Secțiune 33 înainte de a scrie cod ca acesta!) Ce obțineți din asta
este o variabilă numită simplu pfi care este inițializată la valoarea 0. Dacă doriți
inițializați acest indicator la ceva semnificativ, trebuie să aveți o funcție cu a
semnătura potrivită. În acest caz, puteți furniza o funcție care arată astfel:

int Funcția mea (int arg) {}

Dacă aveți această țintă, puteți inițializa variabila pentru a indica funcția dvs.:

pfi = MyFunction;

Apoi puteți apela MyFunction indirect folosind forma mai sugestivă a apelului:

int rezultat = (*pfi) (1234);

Acest lucru este sugestiv, deoarece se pare că dereferențiați doar indicatorul funcției
ca și cum ai dereferi orice indicator. De obicei, totuși, oamenii profită de
faptul că compilatorul știe ce se întâmplă și va folosi doar o formă mai scurtă:

int rezultat = pfi (1234);

Se pare că apelați o funcție numită pfi, dar compilatorul este suficient de inteligent pentru a
știi să apelezi prin variabilă pfi indirect la funcţie Funcția mea.

Din punct de vedere conceptual, acesta este aproape exact modul în care funcționează sistemul de urmărire. Practic, o urmă
chiuvetă is un apel invers. Atunci când un receptor de urme își exprimă interesul pentru a primi evenimente de urmărire, acesta
se adaugă ca un Callback la o listă de Callback-uri deținute intern de sursa de urmărire.
Când are loc un eveniment interesant, sursa de urmărire îl invocă operator(...) furnizarea
zero sau mai multe argumente. The operator(...) în cele din urmă rătăceşte în sistem şi
face ceva remarcabil ca apelul indirect pe care tocmai l-ați văzut, oferind zero sau mai mult
parametri, la fel ca apelul la pfi de mai sus a transmis un parametru funcției țintă
Funcția mea.

Diferența importantă pe care o adaugă sistemul de urmărire este că pentru fiecare sursă de urmărire de acolo
este o listă internă de apeluri inverse. În loc să faci doar un apel indirect, o urmă
sursa poate invoca mai multe apeluri inverse. Când o chiuvetă de urme își exprimă interesul pentru
notificări de la o sursă de urmărire, practic aranjează doar să adauge propria funcție la
lista de apel invers.

Dacă sunteți interesat de mai multe detalii despre cum este de fapt aranjat acest lucru în ns-3, simți
liber să parcurgeți secțiunea de apel invers din ns-3 Manual.

Walkthrough: a patra.cc
Am furnizat un cod pentru a implementa ceea ce este cu adevărat cel mai simplu exemplu de urmărire
care poate fi asamblat. Puteți găsi acest cod în directorul tutorial ca a patra.cc.
Să trecem prin el:

/* -*- Mod: C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Acest program este software gratuit; îl puteți redistribui și/sau modifica
* în conformitate cu termenii GNU General Public License versiunea 2 ca
* publicat de Free Software Foundation;
*
* Acest program este distribuit în speranța că va fi util,
* dar FĂRĂ NICIO GARANȚIE; fără nici măcar garanția implicită a
* VANTABILITATE sau ADECVENȚĂ PENTRU UN ANUMIT SCOP. Vezi
* Licență publică generală GNU pentru mai multe detalii.
*
* Ar fi trebuit să primiți o copie a licenței publice generale GNU
* împreună cu acest program; dacă nu, scrieți la Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 SUA
*/

#include „ns3/object.h”
#include „ns3/uinteger.h”
#include „ns3/traced-value.h”
#include „ns3/trace-source-accessor.h”

#include

folosind namespace ns3;

Majoritatea acestui cod ar trebui să vă fie destul de familiar. După cum am menționat mai sus, sistemul de urmărire
face uz intens de sistemele Object și Atribute, așa că va trebui să le includeți.
Primele două includ mai sus aduc declarațiile pentru acele sisteme în mod explicit. Tu
am putea folosi antetul modulului de bază pentru a obține totul dintr-o dată, dar facem includerile
aici în mod explicit pentru a ilustra cât de simplu este totul.

Fișierul, valoare urmărită.h aduce declarațiile necesare pentru urmărirea datelor care
se supune semanticii valorilor. În general, semantica valorii înseamnă doar că poți trece
obiectul însuși în jur, mai degrabă decât să treacă adresa obiectului. Ce toate astea cu adevărat
înseamnă că veți putea urmări toate modificările aduse unui TracedValue într-un mod real
calea usoara.

Deoarece sistemul de urmărire este integrat cu Atribute, iar Atributele funcționează cu Obiecte,
trebuie să existe o ns-3 Obiect pentru ca sursa de urmărire să locuiască. Următorul fragment de cod
declară și definește un obiect simplu cu care putem lucra.

clasa MyObject : obiect public
{
public:
static TypeId GetTypeId (void)
{
static TypeId tid = TypeId ("MyObject")
.SetParent (Object::GetTypeId ())
.AddConstructor ()
.AddTraceSource ("MyInteger",
„O valoare întreagă de urmărit.”
MakeTraceSourceAccessor (&MyObject::m_myInt),
„ns3::Traced::Value::Int32Callback”)
;
return tid;
}

MyObject () {}
TracedValue m_myInt;
};

Cele două linii importante de cod, de mai sus, cu privire la urmărire sunt .AddTraceSource
si TracedValue declaraţie de m_myInt.

.AddTraceSource furnizează „cârligele” utilizate pentru conectarea sursei de urmărire la
lumea exterioară prin sistemul Config. Primul argument este un nume pentru această urmă
sursă, ceea ce îl face vizibil în sistemul Config. Al doilea argument este un șir de ajutor.
Acum uită-te la al treilea argument, concentrează-te de fapt pe argument al treilea argument:
&MyObject::m_myInt. Aceasta este TracedValue care este adăugată la clasă; este
întotdeauna un membru al datelor de clasă. (Argumentul final este numele lui a typedef pentru
Tipul TracedValue, ca șir. Acesta este folosit pentru a genera documentație pentru corect
Semnătura funcției de apel invers, care este utilă în special pentru tipuri mai generale de
Reapeluri.)

TracedValue<> declarația furnizează infrastructura care conduce apelul invers
proces. De fiecare dată când valoarea de bază este modificată, mecanismul TracedValue va furniza
atât valoarea veche cât și cea nouă a acelei variabile, în acest caz an int32_t valoare. Urma
Funcția de colectare pentru această TracedValue va avea nevoie de semnătură

void (* TracedValueCallback)(const int32_t oldValue, const int32_t newValue);

Toate canalele de urmărire care conectează această sursă de urmărire trebuie să aibă această semnătură. Vom discuta mai jos
cum puteți determina semnătura de apel invers necesară în alte cazuri.

Destul de sigur, continuând a patra.cc v-om vedea:

anula
IntTrace (int32_t oldValue, int32_t newValue)
{
std::cout << "Traced" << oldValue << " la " << newValue << std::endl;
}

Aceasta este definiția unei chiuvete de urmărire potrivite. Corespunde direct apelului invers
semnătura funcției. Odată conectată, această funcție va fi apelată ori de câte ori
TracedValue schimbări.

Am văzut acum sursa de urme și chiuveta de urme. Ceea ce rămâne este codul pentru conectarea
sursă la chiuvetă, ceea ce se întâmplă în principal:

int
main (int argc, char *argv[])
{
Ptr myObject = CreateObject ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));

myObject->m_myInt = 1234;
}

Aici creăm mai întâi instanța MyObject în care trăiește sursa de urmărire.

Următorul pas, cel TraceConnectWithoutContext, formează legătura între urmă
sursă și chiuvetă de urme. Primul argument este doar numele sursei de urmărire „MyInteger”
am vazut mai sus. Observați MakeCallback funcția șablon. Această funcție face magia
necesare pentru a crea suportul ns-3 obiect de apel invers și asociați-l cu funcția
IntTrace. TraceConnect face asocierea între funcția furnizată de dvs. și
supraîncărcat operator() în variabila urmărită la care se referă atributul „MyInteger”.
După ce se face această asociere, sursa de urmărire va „declanșa” apelul returnat
Funcția.

Codul pentru a face toate acestea să se întâmple este, desigur, non-trivial, dar esența este aceea
aranjați pentru ceva care arată exact ca pfi() exemplu de mai sus pentru a fi numit
de sursa urmelor. Declarația lui TracedValue m_myInt; în Obiect
însuși realizează magia necesară pentru a oferi operatorilor de atribuire supraîncărcați care vor
utilizați operator() pentru a invoca efectiv Callback-ul cu parametrii doriti. The
.AddTraceSource efectuează magia pentru a conecta Callback-ul la sistemul Config și
TraceConnectWithoutContext efectuează magia pentru a vă conecta funcția la urmă
sursă, care este specificată de numele atributului.

Să ignorăm puțin despre context pentru moment.

În cele din urmă, linia care atribuie o valoare lui m_myInt:

myObject->m_myInt = 1234;

ar trebui interpretat ca o invocare a operator= pe variabila membru m_myInt cu
numărul întreg 1234 trecut ca parametru.

Întrucât m_myInt este TracedValue, acest operator este definit pentru a executa un apel invers care
returnează void și ia două valori întregi ca parametri --- o valoare veche și o valoare nouă
pentru întregul în cauză. Aceasta este exact semnătura funcției pentru apel invers
funcția oferită de noi --- IntTrace.

Pentru a rezuma, o sursă de urmărire este, în esență, o variabilă care conține o listă de apeluri inverse. A
trace sink este o funcție folosită ca țintă a unui apel invers. Atributul și tipul de obiect
sistemele informaționale sunt folosite pentru a oferi o modalitate de a conecta sursele de urmărire la chiuvete de urmărire.
Actul de a „lovi” o sursă de urmărire este executarea unui operator pe sursa de urmărire care
declanșează apeluri inverse. Acest lucru are ca rezultat apelurile de urmărire care înregistrează interes pentru
sursa fiind apelată cu parametrii furnizați de sursă.

Dacă acum construiți și rulați acest exemplu,

$ ./waf --al patrulea

veți vedea rezultatul de la IntTrace funcția se execută imediat ce sursa de urmărire este
lovit:

Urmărit de la 0 la 1234

Când am executat codul, myObject->m_myInt = 1234;, sursa de urmărire a tras și
a furnizat automat valorile înainte și după chiuvetei de urmărire. Functia
IntTrace apoi a imprimat acest lucru la ieșirea standard.

Connect cu config
TraceConnectWithoutContext apelul prezentat mai sus în exemplul simplu este de fapt foarte
rar folosit în sistem. Mai tipic, cel config subsistemul este utilizat pentru a selecta o urmă
sursă în sistem folosind ceea ce se numește a config cale. Am văzut un exemplu în acest sens în
secțiunea anterioară în care am conectat evenimentul „CourseChange” când am experimentat
a treia.cc.

Amintiți-vă că am definit un canal de urmărire pentru a imprima informații despre schimbarea cursului din mobilitate
modele ale simulării noastre. Acum ar trebui să vă fie mult mai clar care este această funcție
face:

anula
CourseChange (std::string context, Ptr model)
{
Poziția vectorului = model->GetPosition ();
NS_LOG_UNCOND (context <
" x = " << poziție.x << ", y = " << poziție.y);
}

Când am conectat sursa de urmărire „CourseChange” la chiuveta de urmărire de mai sus, am folosit a
Calea de configurare pentru a specifica sursa atunci când am aranjat o conexiune între cele predefinite
sursă de urmărire și noul receptor de urmărire:

std::ostringstream oss;
oss << "/NodeList/"
<< wifiStaNodes.Get (nWifi - 1)->GetId ()
<< „/$ns3::MobilityModel/CourseChange”;

Config::Connect (oss.str (), MakeCallback (&CourseChange));

Să încercăm să înțelegem ceea ce este uneori considerat un cod relativ misterios.
În scopul discuției, presupunem că numărul Nodului returnat de GetId() is
„7”. În acest caz, calea de mai sus se dovedește a fi

„/NodeList/7/$ns3::MobilityModel/CourseChange”

Ultimul segment al unei căi de configurare trebuie să fie un Atribut unui Obiect. De fapt, dacă ai avea
un indicator spre Obiect care are „CourseChange” Atribut la îndemână, ai putea scrie asta
exact cum am făcut în exemplul anterior. Știți până acum că de obicei depozităm
indicii către nostru Nodurile într-un NodeContainer. În a treia.cc exemplu, Nodurile de interes
sunt stocate în wifiStaNodes NodeContainer. De fapt, în timp ce punem drumul împreună,
am folosit acest container pentru a obține un Ptr pe care obișnuiam să-l numim GetId(). Am putea avea
folosit asta Ptr pentru a apela direct o metodă Connect:

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnectWithoutContext („CourseChange”, MakeCallback (&CourseChange));

În a treia.cc De exemplu, am vrut de fapt să fie livrat un „context” suplimentar
cu parametrii Callback (care vor fi explicați mai jos), astfel încât să putem folosi efectiv
următorul cod echivalent:

Ptr theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnect („CourseChange”, MakeCallback (&CourseChange));

Se pare că codul intern pentru Config::ConnectWithoutContext si Config::Conectează
găsi de fapt o Ptr și sunați pe cel corespunzător TraceConnect metoda la cel mai mic
nivel.

config funcțiile iau o cale care reprezintă un lanț de Obiect indicatoare. Fiecare segment
a unei căi corespunde unui atribut de obiect. Ultimul segment este Atributul de
interes, iar segmentele anterioare trebuie tastate pentru a conține sau a găsi obiecte. The config cod
parsează și „plimbă” această cale până când ajunge la segmentul final al căii. Atunci
interpretează ultimul segment ca un Atribut pe ultimul obiect pe care l-a găsit în timp ce mergea pe
cale. The config funcții apoi apelați corespunzător TraceConnect or
TraceConnectWithoutContext metoda pe Obiectul final. Să vedem ce se întâmplă peste puțin
mai multe detalii când se parcurge calea de mai sus.

Caracterul principal „/” din cale se referă la un așa-numit spațiu de nume. Unul dintre
spațiile de nume predefinite în sistemul de configurare este „NodeList”, care este o listă a tuturor
noduri în simulare. Elementele din listă sunt menționate prin indici în listă, deci
„/NodeList/7” se referă la al optulea Nod din lista de noduri create în timpul simulării
(indicii de reamintire încep la 0’). Acest referință is de fapt a ``Ptr ` si la fel si a
subclasa a unui ns3::Obiect.

După cum este descris în secțiunea Model de obiect a ns-3 Manual, folosim pe scară largă
agregarea obiectelor. Acest lucru ne permite să formăm o asociere între diferite Obiecte
fără a construi un arbore de moștenire complicat sau a decide dinainte ce obiecte vor face parte
a unui Nod. Fiecare obiect dintr-o agregare poate fi accesat de la celelalte Obiecte.

În exemplul nostru, următorul segment de cale parcurs începe cu caracterul „$”. Acest
indică sistemului de configurare că segmentul este numele unui tip de obiect, deci a
GetObject apelul ar trebui făcut în căutarea acestui tip. Se pare că MobilityHelper
utilizate în a treia.cc aranjează să asocieze, sau să asocieze, un model de mobilitate la fiecare dintre
fără fir Nodurile. Când adăugați „$” cereți un alt obiect care are
probabil a fost agregat anterior. Poți să te gândești la asta ca la trecerea de indicatori de la
originalul Ptr așa cum este specificat de „/NodeList/7” la modelul său de mobilitate asociat ---
care este de tip ns3::Model de mobilitate. Dacă sunteți familiarizat cu GetObject, am întrebat noi
sistemul să facă următoarele:

Ptr mobilityModel = nod->GetObject ()

Suntem acum la ultimul Obiect din cale, așa că ne îndreptăm atenția către Atributele lui
acel Obiect. The Modelul de mobilitate clasa definește un Atribut numit „CourseChange”. Puteți
vezi asta uitându-te la codul sursă în src/mobility/model/mobility-model.cc si
căutând „CourseChange” în editorul tău preferat. Ar trebui să găsești

.AddTraceSource ("Modificare curs",
„S-a schimbat valoarea vectorului de poziție și/sau viteză”,
MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace),
„ns3::MobilityModel::CourseChangeCallback”)

care ar trebui să pară foarte familiar în acest moment.

Dacă căutați declarația corespunzătoare a variabilei urmărite subiacente în
mobilitate-model.h veţi găsi

TracedCallback > m_courseChangeTrace;

Declarația de tip TracedCallback identifică m_courseChangeTrace ca o listă specială a
Reapeluri care pot fi conectate folosind funcțiile de configurare descrise mai sus. The typedef pentru
semnătura funcției de apel invers este definită și în fișierul antet:

typedef void (* CourseChangeCallback)(Ptr * model);

Modelul de mobilitate clasa este concepută pentru a fi o clasă de bază care oferă o interfață comună pentru
toate subclasele specifice. Dacă căutați până la sfârșitul fișierului, veți vedea a
metoda definită numită NotifyCourseChange():

anula
MobilityModel::NotifyCourseChange (void) const
{
m_courseChangeTrace(this);
}

Clasele derivate vor apela la această metodă ori de câte ori vor schimba cursul pentru a sprijini
trasarea. Această metodă invocă operator() pe subiacent m_courseChangeTrace, Care
va invoca, la rândul său, toate apelurile inverse înregistrate, apelând toate canalele de urmărire care
au înregistrat interes pentru sursa de urmărire apelând o funcție Config.

Deci, în a treia.cc exemplu la care ne-am uitat, ori de câte ori se face o schimbare de curs într-unul dintre
RandomWalk2dMobilityModel instanțe instalate, va exista un NotifyCourseChange() apel
care cheamă în Modelul de mobilitate clasa de bază. După cum sa văzut mai sus, aceasta invocă operator()
on m_courseChangeTrace, care, la rândul său, numește orice chiuvete de urmărire înregistrate. În exemplu,
singurul cod care a înregistrat un interes a fost codul care a furnizat calea de configurare.
De aceea Schimbarea cursului funcția care a fost conectată de la Nodul numărul șapte va fi
doar apelat înapoi.

Ultima piesă a puzzle-ului este „contextul”. Amintiți-vă că am văzut o ieșire în căutarea
ceva de genul următor de la a treia.cc:

/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y =
2.22677

Prima parte a rezultatului este contextul. Este pur și simplu calea prin care
codul de configurare a localizat sursa de urmărire. În cazul pe care ne-am uitat, poate exista
orice număr de surse de urmărire din sistem corespunzător oricărui număr de noduri cu
modele de mobilitate. Trebuie să existe o modalitate de a identifica care sursă de urmărire este de fapt
cel care a tras Callback-ul. Modul simplu este să te conectezi cu Config::Conectează, in schimb
of Config::ConnectWithoutContext.

Găsire Surse
Prima întrebare care apare inevitabil pentru noii utilizatori ai sistemului de urmărire este: "Bine,
I ști acea acolo trebuie sa be urmări surse in il simulare nucleu, dar cum do I găsi afară ceea ce
urmări surse sunt disponibil la pe mine?"

A doua întrebare este, "Bine, I găsit a urmări sursă, cum do I figura afară il config cale
la utilizare cand I conectaţi la aceasta?"

A treia întrebare este, "Bine, I găsit a urmări sursă si il config cale, cum do I figura
afară ceea ce il reveni tip si formal argumente of my suna inapoi funcţie nevoie la fi?"

A patra întrebare este, "Bine, I dactilografiat acea toate in si am acest incredibil bizar eroare
mesaj, ceea ce in il lume face it Rău?"

Vom aborda fiecare dintre acestea pe rând.

Disponibil Surse
Bine, I ști acea acolo trebuie sa be urmări surse in il simulare nucleu, dar cum do I găsi
afară ceea ce urmări surse sunt disponibil la pe mine?

Răspunsul la prima întrebare se găsește în ns-3 Documentația API. Dacă mergi la
site-ul web al proiectului, ns-3 proiect, veți găsi un link către „Documentare” în navigare
bar. Dacă selectați acest link, veți fi direcționat către pagina noastră de documentație. Este un
link la „Ultima versiune” care vă va duce la documentația pentru cel mai recent stabil
lansarea ns-3. Dacă selectați linkul „Documentație API”, veți fi direcționat la
ns-3 Pagina de documentație API.

În bara laterală ar trebui să vedeți o ierarhie care începe

· ns-3

· Documentație ns-3

· Toate TraceSources

· Toate atributele

· Toate GlobalValues

Lista de interes pentru noi aici este „All TraceSources”. Continuați și selectați acel link.
Veți vedea, poate nu prea surprinzător, o listă a tuturor surselor de urme disponibile
in ns-3.

De exemplu, derulați în jos la ns3::Model de mobilitate. Veți găsi o intrare pentru

CourseChange: valoarea vectorului de poziție și/sau viteză a fost schimbată

Ar trebui să recunoașteți aceasta ca fiind sursa de urmărire pe care am folosit-o în a treia.cc exemplu. Studiind
această listă va fi de ajutor.

config Căi
Bine, I găsit a urmări sursă, cum do I figura afară il config cale la utilizare cand I conectaţi la
aceasta?

Dacă știți ce obiect vă interesează, secțiunea „Descriere detaliată” pentru
clasa va lista toate sursele de urmărire disponibile. De exemplu, pornind de la lista „Toate
TraceSources", faceți clic pe ns3::Model de mobilitate link, care vă va duce la
documentatie pentru Modelul de mobilitate clasă. Aproape în partea de sus a paginii este o singură linie
scurtă descriere a clasei, care se termină cu un link „Mai mult...”. Faceți clic pe acest link pentru a omite
rezumatul API și accesați „Descrierea detaliată” a clasei. La sfârșitul
descrierea va fi (până la) trei liste:

· config Căi: o listă de căi tipice de configurare pentru această clasă.

· Atribute: o listă a tuturor atributelor furnizate de această clasă.

· TraceSources: o listă cu toate TraceSources disponibile din această clasă.

Mai întâi vom discuta căile de configurare.

Să presupunem că tocmai ați găsit sursa de urmărire „CourseChange” în „Toate
TraceSources" și doriți să vă dați seama cum să vă conectați la ea. Știți că sunteți
folosind (din nou, din a treia.cc exemplu) an ns3::RandomWalk2dMobilityModel. Deci fie
faceți clic pe numele clasei din lista „Toate sursele de urmărire” sau găsiți
ns3::RandomWalk2dMobilityModel în „Lista de clase”. Oricum ar trebui să cauți acum
la pagina „ns3::RandomWalk2dMobilityModel Class Reference”.

Dacă acum derulați în jos la secțiunea „Descriere detaliată”, după lista rezumată a
metodele și atributele clasei (sau doar faceți clic pe linkul „Mai multe...” de la sfârșitul clasei
scurtă descriere în partea de sus a paginii) veți vedea documentația generală pentru
clasă. Continuând să derulați în jos, găsiți lista „Config Paths”:
config Căi

ns3::RandomWalk2dMobilityModel este accesibilă prin următoarele căi cu
Config::Set si Config::Conectează:

· „/NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel”

Documentația vă spune cum să ajungeți la RandomWalk2dMobilityModel Obiect. Comparaţie
șirul de mai sus cu șirul pe care l-am folosit de fapt în exemplul de cod:

„/NodeList/7/$ns3::MobilityModel”

Diferența se datorează faptului că doi GetObject apelurile sunt implicate în șirul găsit
în documentație. Primul, pentru $ns3::Model de mobilitate va interoga agregarea pentru
clasa de bază. Al doilea implica GetObject suna pentru $ns3::RandomWalk2dMobilityModel,
este folosit pentru a turna clasa de bază în clasa de implementare concretă. Documentația
vă arată ambele operațiuni. Se pare că ești sursa reală de urmărire
cautat se gaseste in clasa de baza.

Căutați mai jos în secțiunea „Descriere detaliată” pentru lista surselor de urmărire.
Tu vei gasi
Nu sunt definite TraceSources pentru acest tip.

TraceSources definit in mamă clasă ``ns3::MobilityModel``

· Schimbarea cursului: Valoarea vectorului poziție și/sau viteză s-a schimbat.

Semnătură de apel invers: ns3::MobilityModel::CourseChangeCallback

Acesta este exact ceea ce trebuie să știți. Urmele sursei de interes se găsesc în
ns3::Model de mobilitate (pe care oricum știai). Lucrul interesant acest pic de API
Documentația vă spune că nu aveți nevoie de acel cast suplimentar în calea de configurare de mai sus
ajunge la clasa concretă, deoarece sursa de urmărire este de fapt în clasa de bază.
Prin urmare, suplimentar GetObject nu este necesar și pur și simplu utilizați calea:

„/NodeList/[i]/$ns3::MobilityModel”

care se potrivește perfect cu calea exemplu:

„/NodeList/7/$ns3::MobilityModel”

Deoparte, o altă modalitate de a găsi calea de configurare este să grep în jurul în ns-3 codebase
pentru cineva care și-a dat seama deja. Ar trebui să încercați întotdeauna să copiați pe al altcuiva
cod de lucru înainte de a începe să-l scrieți pe al dvs. Încearcă ceva de genul:

$ găsi . -nume '*.cc' | xargs grep CourseChange | grep Connect

și puteți găsi răspunsul împreună cu codul de lucru. De exemplu, în acest caz,
src/mobility/examples/main-random-topology.cc are ceva ce așteaptă să folosești:

Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange));

Vom reveni la acest exemplu într-un moment.

Callback Semnături
Bine, I găsit a urmări sursă si il config cale, cum do I figura afară ceea ce il reveni tip
si formal argumente of my suna inapoi funcţie nevoie la fi?

Cel mai simplu mod este să examinezi semnătura de apel invers typedef, care este dat în
„Semnătura de apel invers” a sursei de urmărire în „Descrierea detaliată” pentru clasă, ca
prezentat mai sus.

Repetarea intrării sursei de urmărire „CourseChange” de la ns3::RandomWalk2dMobilityModel we
avea:

· Schimbarea cursului: Valoarea vectorului poziție și/sau viteză s-a schimbat.

Semnătură de apel invers: ns3::MobilityModel::CourseChangeCallback

Semnătura de apel invers este dată ca un link către cel relevant typedef, unde găsim
typedef anula (* CourseChangeCallback)(const std::string context Ptr
MobilityModel> * model);

TracedCallback semnătură pentru notificările privind schimbarea cursului.

Dacă apelul invers este conectat folosind ConnectWithoutContext omite context argument de la
semnatura.

parametrii:
[în] context Șirul de context furnizat de sursa Trace.
[în] modelul MobilityModel care își schimbă cursul.

Ca mai sus, pentru a vedea acest lucru în uz grep în jurul în ns-3 baza de cod de exemplu. Exemplul
mai sus, din src/mobility/examples/main-random-topology.cc, conectează „CourseChange”
sursa de urma la Schimbarea cursului funcția în același fișier:

gol static
CourseChange (std::string context, Ptr model)
{
...
}

Observați că această funcție:

· Preia un argument șir „context”, pe care îl vom descrie într-un minut. (Dacă apelul înapoi
este conectat folosind ConnectWithoutContext funcționează context argumentul va fi
omis.)

· Are Modelul de mobilitate furnizat ca ultimul argument (sau numai argument dacă
ConnectWithoutContext este folosit).

· Se intoarce anula.

Dacă, întâmplător, semnătura de apel invers nu a fost documentată și nu există exemple
de la lucru, determinarea semnăturii corecte a funcției de apel invers poate fi, ei bine, o provocare
de fapt, afli din codul sursă.

Înainte de a începe o prezentare a codului, voi fi amabil și vă voi spune doar un mod simplu
pentru a-ți da seama: valoarea returnată a apelului înapoi va fi întotdeauna anula. Formalul
lista de parametri pentru a TracedCallback poate fi găsit din lista de parametri șablon din
declaraţie. Amintiți-vă că, pentru exemplul nostru actual, acesta este în mobilitate-model.h, unde noi
au gasit anterior:

TracedCallback > m_courseChangeTrace;

Există o corespondență unu-la-unu între lista de parametri șablon din
declarația și argumentele formale ale funcției de apel invers. Aici, există unul
parametru șablon, care este a Ptr MobilityModel>. Acest lucru vă spune că aveți nevoie de un
funcție care returnează void și ia a Ptr MobilityModel>. De exemplu:

anula
Schimbarea cursului (Ptr model)
{
...
}

Asta e tot ce ai nevoie dacă vrei Config::ConnectWithoutContext. Daca vrei un context,
aveți nevoie pentru a Config::Conectează și folosiți o funcție de apel invers care preia un context șir, atunci
argumentele șablonului:

anula
CourseChange (const std::string context, Ptr model)
{
...
}

Dacă doriți să vă asigurați că CursChangeCallback funcția este vizibilă numai în dvs
fișier local, puteți adăuga cuvântul cheie static si vin cu:

gol static
CourseChange (const std::string path, Ptr model)
{
...
}

care este exact ceea ce am folosit în a treia.cc exemplu.

Punerea în aplicare
Această secțiune este complet opțională. Va fi o călătorie accidentată, mai ales pentru aceștia
nefamiliarizat cu detaliile șabloanelor. Cu toate acestea, dacă treci prin asta, vei avea
un mâner foarte bun pe o mulțime de ns-3 idiomuri de nivel scăzut.

Deci, din nou, să ne dăm seama ce semnătură a funcției de apel invers este necesară pentru
Sursa de urmărire „CourseChange”. Va fi dureros, dar trebuie doar să faci asta
o singura data. După ce vei trece peste asta, vei putea doar să te uiți la a TracedCallback si
intelege-o.

Primul lucru la care trebuie să ne uităm este declararea sursei de urmărire. Amintește-ți asta
aceasta este in mobilitate-model.h, unde am găsit anterior:

TracedCallback > m_courseChangeTrace;

Această declarație este pentru un șablon. Parametrul șablonului este în interiorul parantezelor unghiulare,
așa că suntem cu adevărat interesați să aflăm ce anume TracedCallback<> este. Daca ai
absolut nicio idee unde ar putea fi găsit asta, grep este prietenul tau.

Probabil că vom fi interesați de un fel de declarație în ns-3 sursa, deci
prima schimbare în src director. Apoi, știm că această declarație va trebui
fi într-un fel de fișier antet, deci doar grep pentru aceasta folosind:

$ găsi . -nume '*.h' | xargs grep TracedCallback

Veți vedea 303 linii zburând (am transmis asta wc sa vezi cat de rau a fost). Cu toate că
asta poate părea mult, nu este chiar mult. Doar conductați ieșirea prin mai mult si
începe să scanezi prin el. Pe prima pagină, veți vedea unele foarte suspecte
chestii cu aspect de șablon.

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 ...

Se pare că toate acestea provin din fișierul antet trasat-callback.h care sună
foarte promitator. Apoi puteți arunca o privire la mobilitate-model.h și vezi că există o linie
care confirmă această bănuială:

#include „ns3/traced-callback.h”

Desigur, ai fi putut să mergi la asta din cealaltă direcție și să începi prin a te uita la
include în mobilitate-model.h și observând includerea de trasat-callback.h si
deducând că acesta trebuie să fie fișierul dorit.

În ambele cazuri, următorul pas este să aruncați o privire la src/core/model/traced-callback.h in
editorul tău preferat pentru a vedea ce se întâmplă.

Veți vedea un comentariu în partea de sus a fișierului care ar trebui să fie reconfortant:
Un ns3::TracedCallback are aproape exact același API ca un ns3::Callback normal, dar
în loc să redirecționați apelurile către o singură funcție (cum face în mod normal un ns3::Callback),
redirecționează apelurile către un lanț de ns3::Callback.

Acest lucru ar trebui să sune foarte familiar și să vă spună că sunteți pe drumul cel bun.

Imediat după acest comentariu, vei găsi

șablon
nume de tip T3 = gol, nume de tip T4 = gol,
nume de tip T5 = gol, nume de tip T6 = gol,
typename T7 = gol, typename T8 = gol>
clasa TracedCallback
{
...

Aceasta vă spune că TracedCallback este o clasă cu șablon. Are opt tipuri posibile
parametrii cu valori implicite. Întoarce-te și compară asta cu declarația în care ești
incercand sa inteleg:

TracedCallback > m_courseChangeTrace;

nume de tip T1 în declarația șablonului de clasă corespunde Ptr
MobilityModel> în declarația de mai sus. Toți ceilalți parametri de tip sunt lăsați ca
implicite. Privind la constructor, chiar nu vă spune mare lucru. Singurul loc unde
ați văzut o conexiune între funcția dvs. de apel invers și sistemul de urmărire
în Connect si ConnectWithoutContext funcții. Dacă derulați în jos, veți vedea a
ConnectWithoutContext metoda aici:

șablon
nume de tip T3, nume de tip T4,
nume de tip T5, nume de tip T6,
nume de tip T7, nume de tip T8>
anula
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assign (callback);
m_callbackList.push_back (cb);
}

Acum ești în burta fiarei. Când șablonul este instanțiat pentru
declarația de mai sus, compilatorul va înlocui T1 cu Ptr MobilityModel>.

anula
TracedCallback ::ConnectWithoutContext ... cb
{
Suna inapoi > cb;
cb.Assign (callback);
m_callbackList.push_back (cb);
}

Acum puteți vedea implementarea a tot ceea ce am vorbit. Codul
creează un Callback de tipul potrivit și îi atribuie funcția. Acesta este
echivalent al pfi = Funcția mea am discutat la începutul acestei secțiuni. Codul
apoi adaugă apelul înapoi la lista de apeluri inverse pentru această sursă. Singurul lucru rămas este
pentru a vedea definiția Callback-ului. Folosind la fel grep truc așa cum obișnuiam să găsim
TracedCallback, veți putea găsi că fișierul ./core/callback.h este cel noi
trebuie să te uiți la.

Dacă te uiți în jos prin fișier, vei vedea o mulțime de probabil aproape de neînțeles
cod șablon. În cele din urmă, veți ajunge la o documentație API pentru apel invers
clasa șablon, totuși. Din fericire, există ceva engleză:
Callback clasă șablon.

Acest șablon de clasă implementează Modelul de design Functor. Este folosit pentru a declara
tip de a Callback:

· primul argument șablon non-opțional reprezintă tipul de returnare al apelului invers.

· argumentele șablonului remining (opțional) reprezintă tipul următorului
argumente la apel invers.

· sunt acceptate până la nouă argumente.

Încercăm să ne dăm seama ce

Suna inapoi > cb;

declarație înseamnă. Acum suntem în măsură să înțelegem că primul (neopțional)
argument șablon, anula, reprezintă tipul de returnare al apelului invers. Al doilea
(opțional) argument șablon, Ptr MobilityModel> reprezintă tipul primului
argument la apel invers.

Callback-ul în cauză este funcția dvs. de a primi evenimentele de urmărire. Din asta poți
deduceți că aveți nevoie de o funcție care revine anula și ia o Ptr MobilityModel>.
De exemplu,

anula
CursChangeCallback (Ptr model)
{
...
}

Asta e tot ce ai nevoie dacă vrei Config::ConnectWithoutContext. Daca vrei un context,
aveți nevoie pentru a Config::Conectează și utilizați o funcție de apel invers care preia un context șir. Acest
se datorează faptului că Connect funcția vă va oferi contextul. O să ai nevoie:

anula
CourseChangeCallback (std::string context, Ptr model)
{
...
}

Dacă doriți să vă asigurați că CursChangeCallback este vizibil numai în fișierul dvs. local,
puteți adăuga cuvântul cheie static si vin cu:

gol static
CourseChangeCallback (std::cale string, Ptr model)
{
...
}

care este exact ceea ce am folosit în a treia.cc exemplu. Poate ar trebui să te întorci acum și
recitiți secțiunea anterioară (Take My Word for It).

Dacă sunteți interesat de mai multe detalii privind implementarea Callback-urilor, nu ezitați
să aruncăm o privire la ns-3 manual. Ele sunt una dintre cele mai frecvent utilizate constructe în
părţile de nivel inferior ale ns-3. Este, după părerea mea, un lucru destul de elegant.

Valori urmărite
Mai devreme în această secțiune, am prezentat o bucată simplă de cod care folosea a
TracedValue pentru a demonstra elementele de bază ale codului de urmărire. Tocmai am trecut cu vederea
ce este de fapt o valoare TracedValue și cum să găsiți tipul de returnare și argumentele formale pentru
apelul înapoi.

După cum am menționat, fișierul, valoare urmărită.h aduce declarațiile necesare pentru urmărire
de date care se supune semanticii valorii. În general, semantica valorii înseamnă doar că poți
transmiteți obiectul în sine, mai degrabă decât să transmiteți adresa obiectului. Noi extindem
acea cerință de a include setul complet de operatori în stil de atribuire care sunt
predefinit pentru tipuri de date simple-vechi (POD):

┌────────────────────────────────────────────────
operator= (sarcina) │ │
├───────────────────────────────────────────────────────
operator*=operator/=
├───────────────────────────────────────────────────────
operator+=operator-=
├───────────────────────────────────────────────────────
operator++ (atât prefixul, cât și │ │
│postfix) │ │
├───────────────────────────────────────────────────────
operator-- (atât prefixul, cât și │ │
│postfix) │ │
├───────────────────────────────────────────────────────
operator<<=operator>>=
├───────────────────────────────────────────────────────
operator&=operator|=
├───────────────────────────────────────────────────────
operator%=operator^=
└──────────────────────────────────────────────────────

Ce înseamnă cu adevărat toate acestea este că veți putea urmări toate modificările făcute folosind acestea
operatori la un obiect C++ care are semantica valorii.

TracedValue<> Declarația pe care am văzut-o mai sus oferă infrastructura care supraîncărcă
operatorii menționați mai sus și conduce procesul de apel invers. La utilizarea oricăruia dintre operatori
mai sus cu a TracedValue va furniza atât valoarea veche, cât și cea nouă a acelei variabile,
în acest caz an int32_t valoare. Prin inspectarea TracedValue declarație, știm
funcția trace sink va avea argumente (const int32_t valoare veche, CONST int32_t valoare nouă).
Tipul de returnare pentru a TracedValue funcția de apel invers este întotdeauna anula, deci de așteptat
semnătura de apel invers va fi:

void (* TracedValueCallback)(const int32_t oldValue, const int32_t newValue);

.AddTraceSource în GetTypeId Metoda furnizează „cârligele” utilizate pentru conectarea
urmăriți sursa către lumea exterioară prin sistemul Config. Am discutat deja despre
primele trei agruments la AddTraceSource: numele atributului pentru sistemul Config, un ajutor
șir de caractere și adresa membrului de date al clasei TracedValue.

Argumentul șir final, „ns3::Traced::Value::Int32” din exemplu, este numele unui
typedef pentru semnătura funcției de apel invers. Solicităm ca aceste semnături să fie definite,
și dați numele de tip complet calificat la AddTraceSource, astfel încât documentația API poate
legați o sursă de urmărire la semnătura funcției. Pentru TracedValue semnătura este
simplu; pentru TracedCallbacks, am văzut deja că documentele API ajută cu adevărat.

real Exemplu
Să facem un exemplu luat dintr-una dintre cele mai cunoscute cărți despre TCP din jur. „TCP/IP
Ilustrat, volumul 1: Protocoalele", de W. Richard Stevens este un clasic. Tocmai am răsturnat
cartea s-a deschis și a trecut printr-un complot frumos atât al ferestrei de aglomerație, cât și al secvenței
numere în funcție de timp la pagina 366. Stevens numește asta „Figura 21.10. Valoarea cwnd și
trimiteți numărul de secvență în timp ce datele sunt transmise." Să recreăm doar partea cwnd
a acelui complot în ns-3 folosind sistemul de urmărire și gnuplot.

Disponibil Surse
Primul lucru la care trebuie să ne gândim este cum vrem să scoatem datele. Ce este ceea ce noi
trebuie să urmărim? Deci, să consultăm lista „Toate sursele de urmărire” pentru a vedea ce trebuie să lucrăm
cu. Amintiți-vă că acest lucru se găsește în ns-3 Documentația API. Dacă parcurgeți
listă, veți găsi în cele din urmă:
ns3::TcpNewReno

· CongestionWindow: fereastra de congestie a conexiunii TCP

· SlowStart Threshold: pragul de pornire lentă TCP (octeți)

Se pare că ns-3 Implementarea TCP trăiește (în mare parte) în fișier
src/internet/model/tcp-socket-base.cc în timp ce variantele de control al congestionării se află în fișiere precum
as src/internet/model/tcp-newreno.cc. Dacă nu știi asta a apriori, puteți utiliza funcția
recursiv grep truc:

$ găsi . -nume '*.cc' | xargs grep -i tcp

Veți găsi pagină după pagină cu cazuri de tcp care vă indică acel fișier.

Aducerea documentației de clasă pentru TcpNewReno și săriți la lista de
TraceSources veți găsi
TraceSources

· CongestionWindow: fereastra de congestie a conexiunii TCP

Semnătură de apel invers: ns3::Traced::Value::Uint322Callback

Făcând clic pe apel invers typedef link vedem semnătura la care știți acum să vă așteptați:

typedef void(* ns3::Traced::Value::Int32Callback)(const int32_t oldValue, const int32_t newValue)

Acum ar trebui să înțelegeți complet acest cod. Dacă avem un indicator către TcpNewReno,
noi putem TraceConnect la sursa de urmărire „CongestionWindow”, dacă oferim o sursă adecvată
țintă de apel invers. Acesta este același tip de sursă de urmărire pe care l-am văzut în exemplul simplu
la începutul acestei secțiuni, cu excepția faptului că vorbim uint32_t în loc de
int32_t. Și știm că trebuie să oferim o funcție de apel invers cu acea semnătură.

Găsire Exemple
Cel mai bine este întotdeauna să încerci să găsești un cod de lucru pe care îl poți modifica, mai degrabă
decât pornind de la zero. Deci, prima ordine de lucru acum este să găsim un cod care să fie
agăță deja sursa de urmărire „CongestionWindow” și vedem dacă o putem modifica. Ca de obicei,
grep este prietenul tau:

$ găsi . -nume '*.cc' | xargs grep CongestionWindow

Acest lucru va evidenția câțiva candidați promițători: exemple/tcp/tcp-large-transfer.cc
si src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc.

Nu am vizitat încă niciun cod de testare, așa că hai să aruncăm o privire acolo. Tu vei
de obicei, găsiți că codul de testare este destul de minim, așa că acesta este probabil un pariu foarte bun.
Operatii Deschise src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc în editorul tău preferat și caută
„CongestionWindow”. Vei găsi,

ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this));

Acest lucru ar trebui să vă pară foarte familiar. Am menționat mai sus că dacă am avea un indicator către
TcpNewReno, am putea TraceConnect la sursa de urmărire „CongestionWindow”. Exact asta
ce avem aici; așa că se dovedește că această linie de cod face exact ceea ce ne dorim.
Să mergem mai departe și să extragem codul de care avem nevoie din această funcție (Ns3TcpCwndTestCase1::DoRun
(Nu apare)). Dacă te uiți la această funcție, vei descoperi că arată exact ca un ns-3
scenariu. Se pare că este exact ceea ce este. Este un script rulat de test
cadru, așa că îl putem scoate și înfășura principal în loc de în DoRun. Mai degraba
decât să treci prin asta, pas cu pas, am furnizat fișierul care rezultă din portare
acest test înapoi la un nativ ns-3 scenariu -- exemple/tutorial/al cincilea.cc.

Dinamic Urmă Surse
a cincea.cc exemplu demonstrează o regulă extrem de importantă pe care trebuie să o înțelegi
înainte de a utiliza orice fel de sursă de urmărire: trebuie să vă asigurați că ținta a
Config::Conectează comanda există înainte de a încerca să o folosească. Acest lucru nu este diferit de a spune
un obiect trebuie să fie instanțiat înainte de a încerca să-l apeleze. Deși acest lucru poate părea evident
atunci când este spus în acest fel, se împiedică mulți oameni care încearcă să folosească sistemul pentru prima
timp.

Să revenim pentru o clipă la elementele de bază. Există trei faze de execuție de bază care există în
Orice ns-3 scenariu. Prima fază este uneori numită „Timp de configurare” sau „Configurare
Timp" și există în perioada în care principal funcția scriptului tău rulează, dar
înainte Simulator::Run se numește. A doua fază este uneori numită „Timp de simulare”
și există în perioada în care Simulator::Run își execută activ evenimentele.
După ce termină executarea simulării, Simulator::Run va readuce controlul la
il principal funcţie. Când se întâmplă acest lucru, scriptul intră în ceea ce se poate numi „Teardown
Faza", care este momentul în care structurile și obiectele create în timpul instalării sunt demontate și
eliberată.

Poate cea mai frecventă greșeală făcută în încercarea de a utiliza sistemul de urmărire este să presupunem că
entitati construite dinamic în timpul simulare timp sunt disponibile în timpul configurării
timp. În special, an ns-3 Priză este un obiect dinamic creat adesea de Aplicatii la
comunica intre Nodurile. O ns-3 Aplicatii are întotdeauna un „Ora de pornire” și un „Oprire
Timpul" asociat cu acesta. În marea majoritate a cazurilor, an Aplicatii nu va încerca
pentru a crea un obiect dinamic până când acesta StartApplication metoda este numită la un „Start
Timp". Acest lucru este pentru a ne asigura că simularea este complet configurată înaintea aplicației
încearcă să facă orice (ce s-ar întâmpla dacă ar încerca să se conecteze la un Nod care nu a existat
încă în timpul configurării?). Ca urmare, în timpul fazei de configurare nu puteți
conectați o sursă de urmărire la un canal de urmărire dacă una dintre ele este creată dinamic în timpul
simulare.

Cele două soluții la acest connundrum sunt

1. Creați un eveniment simulator care este rulat după ce obiectul dinamic este creat și conectați
urmărirea când acel eveniment este executat; sau

2. Creați obiectul dinamic în momentul configurării, apoi conectați-l și dați obiectul
sistemul de utilizat în timpul simulării.

Am luat a doua abordare în a cincea.cc exemplu. Această decizie ne-a impus să creăm
il Aplicația mea Aplicatii, al cărui scop întreg este de a lua a Priză ca parametru.

Walkthrough: a cincea.cc
Acum, să aruncăm o privire la programul exemplu pe care l-am construit prin disecția congestiei
testul ferestrei. Deschis exemple/tutorial/al cincilea.cc în editorul tău preferat. Ar trebui sa vezi
un cod cu aspect familiar:

/* -*- Mod: C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Acest program este software gratuit; îl puteți redistribui și/sau modifica
* în conformitate cu termenii GNU General Public License versiunea 2 ca
* publicat de Free Software Foundation;
*
* Acest program este distribuit în speranța că va fi util,
* dar FĂRĂ NICIO GARANȚIE; fără nici măcar garanția implicită a
* VANTABILITATE sau ADECVENȚĂ PENTRU UN ANUMIT SCOP. Vezi
* Licență publică generală GNU pentru mai multe detalii.
*
* Ar fi trebuit să primiți o copie a licenței publice generale GNU
* împreună cu acest program; dacă nu, scrieți la Free Software
* Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 SUA
*/

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

folosind namespace ns3;

NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");

Toate acestea au fost acoperite, așa că nu o vom repeta. Următoarele rânduri de sursă sunt
ilustrație de rețea și un comentariu care abordează problema descrisă mai sus cu Priză.

// ================================================== ============================
//
// nodul 0 nodul 1
// +----------------+ +----------------+
// | ns-3 TCP | | ns-3 TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | punct la punct | | punct la punct |
// +----------------+ +----------------+
// | |
// +---------------------+
// 5 Mbps, 2 ms
//
//
// Vrem să ne uităm la modificările din fereastra de congestie TCP ns-3. Avem nevoie
// pentru a porni un flux și a conecta atributul CongestionWindow pe socket
// al expeditorului. În mod normal, s-ar folosi o aplicație on-off pentru a genera un
// flux, dar aceasta are câteva probleme. În primul rând, priza pornit-oprit
// aplicația nu este creată până la ora de începere a aplicației, așa că nu am fi
// capabil să cupleze socket-ul (acum) la momentul configurării. În al doilea rând, chiar dacă noi
// ar putea aranja un apel după ora de pornire, socket-ul nu este public, așa că noi
// nu am putut ajunge la asta.
//
// Deci, putem pregăti o versiune simplă a aplicației on-off care face ce
// noi vrem. În plus, nu avem nevoie de toată complexitatea on-off
// cerere. Pe partea minus, nu avem un ajutor, așa că trebuie să ajungem
// puțin mai implicat în detalii, dar acest lucru este banal.
//
// Deci, mai întâi, creăm un socket și facem trace connect pe el; apoi trecem
// acest socket în constructorul aplicației noastre simple pe care apoi îl vom
// se instalează în nodul sursă.
// ================================================== ============================
//

Acest lucru ar trebui, de asemenea, să se explice de la sine.

Următoarea parte este declarația Aplicația mea Aplicatii pe care le-am pus împreună pentru a permite
il Priză pentru a fi creat în momentul configurării.

clasa MyApp: aplicație publică
{
public:

MyApp ();
virtual ~MyApp();

void Configurare (Ptr socket, adresa adresei, uint32_t packetSize,
uint32_t nPackets, DataRate dataRate);

privat:
virtual void StartApplication (void);
virtual void StopApplication (void);

void ScheduleTx (void);
void SendPacket (void);

Ptr m_socket;
Adresa m_peer;
uint32_t m_packetSize;
uint32_t m_nPackets;
DataRate m_dataRate;
EventId m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};

Puteți vedea că această clasă moștenește de la ns-3 Aplicatii clasă. Aruncăm o privire la
src/network/model/application.h dacă te interesează ceea ce se moștenește. The Aplicația mea
clasa este obligată să depășească StartApplication si Opriți aplicația metode. Aceste
metodele sunt apelate automat când Aplicația mea este necesar pentru a începe și a opri trimiterea datelor
în timpul simulării.

Pornire / oprire Aplicatii
Merită să petreceți puțin timp explicând modul în care evenimentele încep de fapt în
sistem. Aceasta este o altă explicație destul de profundă și poate fi ignorată dacă nu ești
plănuiesc să se aventureze în măruntaiele sistemului. Este util, însă, în asta
discuția atinge modul în care unele părți foarte importante ale ns-3 lucrează și expune unele
idiomuri importante. Dacă intenționați să implementați noi modele, probabil că doriți
înțelegeți această secțiune.

Cea mai obișnuită modalitate de a începe pomparea evenimentelor este pornirea unui Aplicatii. Acest lucru se face ca
rezultatul următoarelor (sperăm) rânduri cunoscute ale an ns-3 scenariu:

Aplicații ApplicationContainer =...
apps.Start (Secunde (1.0));
apps.Stop (Secunde (10.0));

Codul containerului aplicației (vezi src/network/helper/application-container.h daca esti
interesat) parcurge aplicațiile și apelurile conținute,

app->SetStartTime (startTime);

ca urmare a aplicații.Porniți suna si

aplicație->SetStopTime (stopTime);

ca urmare a aplicații.Opriți apel.

Rezultatul final al acestor apeluri este că vrem să avem simulatorul automat
dați apeluri la noi Aplicatii pentru a le spune când să înceapă și să se oprească. În cazul în care
Aplicația mea, moștenește din clasă Aplicatii și anulează StartApplication și
Opriți aplicația. Acestea sunt funcțiile care vor fi apelate de simulator la
timpul potrivit. În cazul în care Aplicația mea vei găsi asta MyApp::StartApplication face
inițială Lega și Connect pe soclu și apoi începe fluxul de date prin apelare
MyApp::SendPacket. MyApp::StopApplication oprește generarea de pachete prin anularea oricăruia
evenimente de trimitere în așteptare, apoi închide socket-ul.

Unul dintre lucrurile frumoase despre ns-3 este că puteți ignora complet implementarea
detalii despre modul în care dvs Aplicatii este apelat „automagic” de simulator la corect
timp. Dar din moment ce ne-am aventurat deja adânc în ns-3 deja, hai să mergem.

Dacă te uiți la src/network/model/application.cc vei descoperi că SetStartTime metodă
unui Aplicatii doar setează variabila membru m_startTime si SetStopTime metodă
doar seturi m_stopTime. De acolo, fără câteva indicii, traseul se va termina probabil.

Cheia pentru a relua traseul este să știi că există o listă globală a tuturor
nodurile din sistem. Ori de câte ori creați un nod într-o simulare, un pointer către acel Nod
se adaugă la global NodeList.

Aruncati o privire la src/network/model/node-list.cc si cauta NodeList::Add. Publicul
implementarea statică apelează la o implementare privată numită NodeListPriv::Add. Acest
este un idom relativ comun în ns-3. Deci, aruncați o privire la NodeListPriv::Add. Acolo tu
vor găsi,

Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Initialize, nod);

Acest lucru vă spune că ori de câte ori un Nod este creat într-o simulare, ca efect secundar, un apel
la acel nod inițializa este programată pentru dvs. metoda care are loc la ora zero. Nu
citește prea mult în acest nume, totuși. Nu înseamnă că nodul va începe să funcționeze
orice, poate fi interpretat ca un apel informațional către Nod care îi spune că
simularea a început, nu un apel la acțiune care îi spune Nodului să înceapă să facă ceva.

Asa de, NodeList::Add programează indirect un apel către Nod::Initialize la momentul zero pentru a sfătui a
Nod nou pe care a început simularea. Dacă te uiți înăuntru src/network/model/node.h tu
nu va găsi totuși o metodă numită Nod::Initialize. Se dovedește că
inițializa metoda este moștenită de la clasă Obiect. Toate obiectele din sistem pot fi
notificat când începe simularea, iar obiectele din clasa Node sunt doar un fel de ele
obiecte.

Aruncati o privire la src/core/model/object.cc următorul și căutați Object::Initialize. Acest cod
nu este atât de simplu pe cât v-ați fi așteptat de atunci ns-3 Obiecte a sustine
agregare. Codul din Object::Initialize apoi trece prin toate obiectele care
au fost agregate împreună și numesc lor DoInitialize metodă. Acesta este un alt idiom
care este foarte comun în ns-3, numit uneori „model de design șablon.”: un public
metoda API non-virtuală, care rămâne constantă în toate implementările și care apelează la a
metodă de implementare virtuală privată care este moștenită și implementată de subclase.
Numele sunt de obicei ceva de genul MethodName pentru API-ul public și DoMethodName pentru
API-ul privat.

Acest lucru ne spune că ar trebui să căutăm a Node::DoInitialize metoda în
src/network/model/node.cc pentru metoda care ne va continua traseul. Dacă localizați
cod, veți găsi o metodă care trece prin toate dispozitivele din Nod și apoi
toate aplicațiile din apelarea Node dispozitiv->Inițializați si aplicație->Inițializare
respectiv.

Poate știți deja aceste cursuri Dispozitiv si Aplicatii ambii mostenesc din clasa Obiect
și astfel următorul pas va fi să ne uităm la ce se întâmplă când Aplicație::DoInitialize is
numit. Aruncăm o privire la src/network/model/application.cc si vei gasi:

anula
Aplicație::DoInitialize (void)
{
m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, this);
if (m_stopTime != TimeStep (0))
{
m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, aceasta);
}
Object::DoInitialize ();
}

Aici ajungem în sfârșit la capătul traseului. Dacă ai păstrat totul drept, când tu
implementează o ns-3 Aplicatii, noua ta aplicație moștenește de la clasă Aplicatii. Tu
suprascrie StartApplication si Opriți aplicația metode și să ofere mecanisme pentru
pornirea și oprirea fluxului de date din noua dvs Aplicatii. Când un Nod este
creat în simulare, este adăugat la un global NodeList. Acțiunea de a adăuga un Nod la
acest NodeList face ca un eveniment simulator să fie programat pentru ora zero, care apelează la
Nod::Initialize metoda noului adăugat nou care va fi apelată când începe simularea.
Deoarece un Nod moștenește de la Obiect, aceasta se numește Object::Initialize metoda pe Nod
care, la rândul său, numește DoInitialize metode pe toate Obiecte agregate la
Nod (gândiți-vă la modele de mobilitate). De când Nodul Obiect a depășit DoInitialize, Că
metoda este apelată când începe simularea. The Node::DoInitialize metoda apelează
inițializa metode ale tuturor Aplicatii pe nod. De cand Aplicatii sunt, de asemenea,
Obiecte, Asta cauzează Aplicație::DoInitialize a se numi. Când
Aplicație::DoInitialize este numit, programează evenimente pentru StartApplication si
Opriți aplicația apelează la Aplicatii. Aceste apeluri sunt concepute pentru a porni și opri
fluxul de date din Aplicatii

Aceasta a fost o altă călătorie destul de lungă, dar trebuie făcută o singură dată, iar tu acum
înţelege o altă bucată foarte profundă din ns-3.

Aplicația mea Aplicatii
Aplicația mea Aplicatii are nevoie de un constructor și un destructor, desigur:

MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (fals),
m_packetsSent (0)
{
}

MyApp::~MyApp()
{
m_socket = 0;
}

Existența următorului bit de cod este motivul pentru care am scris asta Aplicatii in
primul loc.

anula
MyApp::Configurare (Ptr socket, adresa adresei, uint32_t packetSize,
uint32_t nPackets, DataRate dataRate)
{
m_socket = priză;
m_peer = adresa;
m_packetSize = packetSize;
m_nPackets = nPackets;
m_dataRate = dataRate;
}

Acest cod ar trebui să se explice de la sine. Doar inițializam variabilele membre.
Cel important din perspectiva trasării este Ptr priză pe care noi
necesare pentru a furniza aplicației în timpul configurării. Amintiți-vă că mergem
pentru a crea Priză ca o TcpSocket (care este implementat de TcpNewReno) și agățați-l
Sursa de urmărire „CongestionWindow” înainte de a o transmite către Configurarea metodă.

anula
MyApp::StartApplication (void)
{
m_running = adevărat;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Conectare (m_peer);
SendPacket ();
}

Codul de mai sus este implementarea suprascrisă Aplicație::StartApplication o sa fie
apelat automat de simulator pentru a porni Aplicatii alergând la momentul potrivit
timp. Puteți vedea că face o Priză Lega Operațiune. Dacă sunteți familiarizat cu
Berkeley Sockets, aceasta nu ar trebui să fie o surpriză. Ea efectuează lucrările necesare pe local
partea conexiunii exact așa cum v-ați aștepta. Următoarele Connect va face ceea ce este
necesare pentru a stabili o conexiune cu TCP la Adresă m_peer. Acum ar trebui să fie clar
de ce trebuie să amânăm o mare parte din acest timp pentru simulare, din moment ce Connect va avea nevoie
o rețea complet funcțională de finalizat. După Connect, Aplicatii apoi începe
crearea de evenimente de simulare prin apelare Trimite pachet.

Următorul fragment de cod explică Aplicatii cum să opriți crearea de evenimente de simulare.

anula
MyApp::StopApplication (void)
{
m_running = fals;

if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}

dacă (m_socket)
{
m_socket->Închidere ();
}
}

De fiecare dată când este programat un eveniment de simulare, an eveniment este creat. Dacă eveniment este in asteptare
executarea sau executarea, metoda acesteia Rulează va reveni adevărat. În acest cod, dacă
Rulează() se întoarce adevărat, noi Anulare evenimentul care îl elimină din evenimentul simulator
coadă. Făcând acest lucru, rupem lanțul de evenimente pe care Aplicatii folosește să păstreze
trimiterea acestuia Pachete si Aplicatii tace. După ce am liniștit Aplicatii we
Închide soclul care rupe conexiunea TCP.

Socket-ul este de fapt șters în destructor atunci când m_socket = 0 este executat. Acest
elimină ultima referință la Ptr-ul de bază care provoacă distrugătorul de
acel obiect care urmează să fie numit.

Reamintim că StartApplication denumit Trimite pachet pentru a începe lanțul de evenimente care descrie
il Aplicatii comportament.

anula
MyApp::SendPacket (void)
{
Ptr pachet = Creare (m_packetSize);
m_socket->Trimite (pachet);

if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}

Aici, vezi asta Trimite pachet face tocmai asta. Se creează o Pachet și apoi face a Trimiteți
care, dacă cunoașteți Berkeley Sockets, este probabil exact ceea ce vă așteptați să vedeți.

Este responsabilitatea Aplicatii pentru a continua programarea lanțului de evenimente, deci
apelează liniile următoare ScheduleTx pentru a programa un alt eveniment de transmisie (a Trimite pachet) pană la
Aplicatii decide că a trimis suficient.

anula
MyApp::ScheduleTx (void)
{
dacă (m_running)
{
Time tNext (Secunde (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}

Aici, vezi asta ScheduleTx face exact asta. Dacă Aplicatii rulează (dacă
Opriți aplicația nu a fost apelat) va programa un nou eveniment, care sună Trimite pachet
din nou. Cititorul de alertă va observa ceva care provoacă și noi utilizatori. Rata de date
unui Aplicatii este doar atat. Nu are nimic de-a face cu rata de date a unui subiacent
Canal. Aceasta este rata la care Aplicatii produce biți. Nu ia în
ține cont de orice suprasarcină pentru diferitele protocoale sau canale pe care le utilizează pentru a transporta
date. Dacă setați rata de date a unui Aplicatii la aceeași rată de date cu cea de bază
Canal veți obține în cele din urmă o depășire a tamponului.

Urmă chiuvete
Scopul acestui exercițiu este de a obține apeluri de urmărire de la TCP care indică
fereastra de congestionare a fost actualizată. Următoarea bucată de cod implementează codul corespunzător
chiuveta de urme:

gol static
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd);
}

Acest lucru ar trebui să vă fie foarte familiar acum, așa că nu ne vom opri asupra detaliilor. Această funcție
doar înregistrează timpul de simulare curent și noua valoare a ferestrei de congestie fiecare
momentul în care este schimbat. Probabil vă puteți imagina că ați putea încărca rezultatul rezultat
într-un program de grafică (gnuplot sau Excel) și vedeți imediat un grafic frumos al
comportamentul ferestrei de congestie în timp.

Am adăugat un nou canal de urmărire pentru a arăta unde sunt aruncate pachetele. Vom adăuga o eroare
model la acest cod, de asemenea, așa că am vrut să demonstrăm acest lucru.

gol static
RxDrop (Ptr p)
{
NS_LOG_UNCOND ("RxDrop la " << Simulator::Now ().GetSeconds ());
}

Acest canal de urmărire va fi conectat la sursa de urmărire „PhyRxDrop” a punct-la-punct
NetDevice. Această sursă de urmărire se declanșează atunci când un pachet este aruncat de stratul fizic al unui
NetDevice. Dacă faci un mic ocol până la sursă
(src/point-to-point/model/point-to-point-net-device.cc) vei vedea că această urmă
sursa se referă la PointToPointNetDevice::m_phyRxDropTrace. Dacă te uiți apoi înăuntru
src/point-to-point/model/point-to-point-net-device.h pentru această variabilă membru, veți face
constată că este declarată ca a TracedCallback Pachet> >. Asta ar trebui să-ți spună
că ținta de apel invers ar trebui să fie o funcție care returnează void și ia un singur
parametru care este a Ptr Pachet> (presupunând că folosim ConnectWithoutContext) -- doar
ce avem mai sus.

Principal Program
Următorul cod ar trebui să vă fie foarte familiar până acum:

int
main (int argc, char *argv[])
{
Nodurile NodeContainer;
noduri.Creează (2);

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

Dispozitive NetDeviceContainer;
dispozitive = pointToPoint.Install (noduri);

Acest lucru creează două noduri cu un canal punct la punct între ele, așa cum se arată în
ilustrație la începutul fișierului.

Următoarele câteva rânduri de cod arată ceva nou. Dacă urmărim o conexiune care se comportă
perfect, vom ajunge cu o fereastră de aglomerație care crește monoton. Pentru a vedea oricare
comportament interesant, vrem cu adevărat să introducem erori de legătură care vor arunca pachete,
provoacă ACK-uri duplicate și declanșează comportamentele mai interesante ale ferestrei de congestie.

ns-3 furnizează ErrorModel obiecte de care se pot atașa Canale. Noi folosim
RateErrorModel ceea ce ne permite să introducem erori în a Canal la un dat rată.

Ptr em = CreateObject ();
em->SetAttribute („ErrorRate”, DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

Codul de mai sus instanțiază a RateErrorModel Obiect și setăm „ErrorRate” Atribut
la valoarea dorită. Apoi setăm instanțiatul rezultat RateErrorModel ca eroare
model folosit de punct la punct NetDevice. Acest lucru ne va oferi niște retransmisii și
face intriga noastră un pic mai interesantă.

InternetStackHelper stivă;
stack.Install (noduri);

Adresă Ipv4AddressHelper;
adresa.SetBase ("10.1.1.0", "255.255.255.252");
Ipv4InterfaceContainer interfețe = adresa.Assign (dispozitive);

Codul de mai sus ar trebui să fie familiar. Instalează stive de internet pe cele două noduri ale noastre și
creează interfețe și atribuie adrese IP pentru dispozitivele punct la punct.

Deoarece folosim TCP, avem nevoie de ceva pe nodul destinație pentru a primi TCP
conexiuni și date. The PacketSink Aplicatii este folosit în mod obișnuit în ns-3 pentru asta
scop.

uint16_t sinkPort = 8080;
Adresă sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
PacketSinkHelper pachetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (1));
sinkApps.Start (Secunde (0.));
sinkApps.Stop (Secunde (20.));

Toate acestea ar trebui să fie familiare, cu excepția,

PacketSinkHelper pachetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny (), sinkPort));

Acest cod instanțiază a PacketSinkHelper și îi spune să creeze socket-uri folosind clasa
ns3::TcpSocketFactory. Această clasă implementează un model de design numit „fabrica de obiecte”
care este un mecanism folosit în mod obișnuit pentru a specifica o clasă folosită pentru a crea obiecte într-un
mod abstract. Aici, în loc să trebuiască să creați obiectele în sine, furnizați
PacketSinkHelper un șir care specifică a TypeId șir folosit pentru a crea un obiect care
poate fi apoi folosit, la rândul său, pentru a crea instanțe ale Obiectelor create de fabrică.

Parametrul rămas îi spune Aplicatii ce adresă și port ar trebui Lega la.

Următoarele două linii de cod vor crea socket-ul și vor conecta sursa de urmărire.

Ptr ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
TcpSocketFactory::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&CwndChange));

Prima instrucțiune apelează funcția membru static Socket::CreateSocket și oferă o
Nod și un explicit TypeId pentru fabrica de obiecte folosită pentru a crea socket-ul. Acesta este un
apel de nivel ușor mai scăzut decât cel PacketSinkHelper apelați mai sus și utilizează un C++ explicit
tastați în loc de unul la care face referire un șir. În rest, conceptual este același
lucru.

Odată ce TcpSocket este creat și atașat la Nod, putem folosi
TraceConnectWithoutContext pentru a conecta sursa de urmărire CongestionWindow la receptorul nostru de urmărire.

Amintiți-vă că am codificat un Aplicatii ca să putem lua asta Priză tocmai am făcut (în timpul
timpul de configurare) și folosiți-l în timpul de simulare. Acum trebuie să instanțiem asta
Aplicatii. Nu ne-am dat probleme pentru a crea un ajutor care să gestioneze Aplicatii so
va trebui să-l creăm și să îl instalăm „manual”. Acest lucru este de fapt destul de ușor:

Ptr app = CreateObject ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
noduri.Get (0)->AddApplication (aplicație);
aplicație->Start (Secunde (1.));
aplicație->Stop (Secunde (20.));

Prima linie creează un Obiect de tip Aplicația mea -- al nostru Aplicatii. A doua linie spune
il Aplicatii ceea ce Priză să utilizați, la ce adresă să vă conectați, la câte date să trimiteți
fiecare eveniment de trimitere, câte evenimente de trimitere de generat și rata la care se produc date
din acele evenimente.

Apoi, adăugăm manual Aplicația mea Aplicatii la nodul sursă și apelați în mod explicit
acasă si Stop metode pe Aplicatii pentru a-i spune când să înceapă și să nu mai facă
lucru.

Trebuie să facem de fapt conectarea de la receptor punct la punct NetDevice eveniment de eliminare
pentru noi RxDrop apel invers acum.

devices.Get (1)->TraceConnectWithoutContext(„PhyRxDrop”, MakeCallback (&RxDrop));

Acum ar trebui să fie evident că primim o referință la primire Nod NetDevice
din containerul său și conectând sursa de urmărire definită de atributul „PhyRxDrop” pe
acel dispozitiv la chiuveta de urmărire RxDrop.

În cele din urmă, îi spunem simulatorului să înlocuiască orice Aplicatii și opriți procesarea
evenimente la 20 de secunde în simulare.

Simulator::Stop (secunde(20));
Simulator::Run ();
Simulator::Destroy ();

0 reveni;
}

Amintiți-vă că de îndată ce Simulator::Run este apelat, timpul de configurare se termină și simulare
timpul începe. Toată munca pe care am orchestrat-o prin crearea Aplicatii si predandu-l
modul de conectare și trimitere de date se întâmplă de fapt în timpul acestui apel de funcție.

De îndată ce Simulator::Run revine, simularea este completă și intrăm în demontare
fază. În acest caz, Simulator::Distruge are grijă de detaliile sângeroase și tocmai ne întoarcem
un cod de succes după finalizarea acestuia.

Alergare a cincea.cc
Din moment ce am furnizat dosarul a cincea.cc pentru dvs., dacă v-ați construit distribuția (în
modul de depanare deoarece folosește NS_LOG -- reamintim că versiunile optimizate se optimizează NS_LOG) aceasta
te va astepta sa fugi.

$ ./waf --al cincilea
Waf: se introduce în directorul `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
Waf: Ieșim din directorul `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
„build” finalizat cu succes (0.684s)
1 536
1.0093 1072
1.01528 1608
1.02167 2144
...
1.11319 8040
1.12151 8576
1.12983 9112
RxDrop la 1.13696
...

Probabil că puteți vedea imediat un dezavantaj al utilizării tipăritelor de orice fel în urmele dvs.
Primim acele mesaje waf străine tipărite pe toate informațiile noastre interesante
cu acele mesaje RxDrop. Vom remedia asta în curând, dar sunt sigur că abia așteptați să vedeți
rezultatele tuturor acestor lucrări. Să redirecționăm acea ieșire către un fișier numit cwnd.dat:

$ ./waf --run fifth > cwnd.dat 2>&1

Acum editați „cwnd.dat” în editorul dvs. preferat și eliminați starea de construire a waf și aruncați-o
linii, lăsând doar datele urmărite (puteți comenta și
TraceConnectWithoutContext ("PhyRxDrop", MakeCallback (&RxDrop)); în scenariu pentru a scăpa
a picăturii se imprimă la fel de ușor.

Acum puteți rula gnuplot (dacă îl aveți instalat) și îi spuneți să genereze ceva frumos
poze:

$ gnuplot
gnuplot> setați dimensiunea png terminalului 640,480
gnuplot> setați ieșirea „cwnd.png”
gnuplot> trasează „cwnd.dat” folosind titlul 1:2 „Fereastra de congestionare” cu puncte de linii
gnuplot> ieșire

Acum ar trebui să aveți un grafic al ferestrei de congestie în funcție de timpul de stat în fișier
"cwnd.png" loading="lenes" care arată astfel:
[Image]

Utilizarea Nivel mediu Ajutoare
În secțiunea anterioară, am arătat cum să conectați o sursă de urmărire și să obțineți cu speranță
informații interesante dintr-o simulare. Poate vă amintiți că am sunat
logare la ieșirea standard folosind std::out un „instrument contondent” mult mai devreme în aceasta
capitol. De asemenea, am scris despre cum a fost o problemă să analizați în ordine rezultatul jurnalului
pentru a izola informații interesante. S-ar putea să ți-ai trecut prin minte că am cheltuit foarte mult
de timp implementând un exemplu care prezintă toate problemele cu care pretindem că le rezolvăm
il ns-3 sistem de urmărire! ai avea dreptate. Dar, suportă-ne. Încă nu am terminat.

Unul dintre cele mai importante lucruri pe care vrem să le facem este să avem capacitatea de a face cu ușurință
controlați cantitatea de ieșire care iese din simulare; și vrem să-i salvăm și pe aceștia
date într-un fișier, astfel încât să ne putem referi la el mai târziu. Putem folosi ajutoarele de urmărire de nivel mediu
prevazut in ns-3 să faci exact asta și să completezi imaginea.

Oferim un script care scrie evenimentele de schimbare și eliminare a cwnd dezvoltate în exemplu
a cincea.cc pe disc în fișiere separate. Modificările cwnd sunt stocate ca un ASCII separat de tabulatori
fișierul și evenimentele de eliminare sunt stocate într-un fișier PCAP. Schimbările pentru ca acest lucru să se întâmple sunt
destul de mic.

Walkthrough: al şaselea.cc
Să aruncăm o privire la modificările necesare de la care să trecem a cincea.cc la al şaselea.cc. Deschis
exemple/tutorial/sixth.cc în editorul tău preferat. Puteți vedea prima schimbare după
în căutarea CwndChange. Veți descoperi că am schimbat semnăturile pentru urmă
se scufundă și au adăugat o singură linie la fiecare chiuvetă care scrie informațiile urmărite în a
flux reprezentând un fișier.

gol static
CwndChange (Ptr flux, 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;
}

gol static
RxDrop (Ptr dosar, Ptr p)
{
NS_LOG_UNCOND ("RxDrop la " << Simulator::Now ().GetSeconds ());
fisier->Write(Simulator::Now(), p);
}

Am adăugat un parametru „stream” la CwndChange chiuveta de urme. Acesta este un obiect care
deține (menține în siguranță în viață) un flux de ieșire C++. Se pare că acesta este un lucru foarte simplu
obiect, ci unul care gestionează problemele de viață pentru flux și rezolvă o problemă care chiar
utilizatorii experimentați C++ se întâlnesc. Se pare că constructorul de copiere pentru std::ostream
este marcat ca privat. Aceasta înseamnă că std::ostreams nu se supune semanticii valorii și nu pot
să fie utilizat în orice mecanism care necesită copierea fluxului. Aceasta include ns-3
sistemul de apel invers, care, după cum vă amintiți, necesită obiecte care se supun semanticii valorii.
În plus, rețineți că am adăugat următoarea linie în fișierul CwndChange chiuveta de urme
implementare:

*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Acesta ar fi un cod foarte familiar dacă l-ați înlocui *stream->GetStream () cu std::out, După cum
în:

std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Acest lucru ilustrează faptul că Ptr este într-adevăr doar cărând în jur o
std::ofstream pentru tine și îl poți folosi aici ca orice alt flux de ieșire.

O situație similară se întâmplă în RxDrop cu excepția faptului că obiectul este trecut în jur (a
Ptr) reprezintă un fișier PCAP. Există o singură căptușeală în chiuveta de urmărire
scrieți un marcaj de timp și conținutul pachetului care este aruncat în fișierul PCAP:

fisier->Write(Simulator::Now(), p);

Desigur, dacă avem obiecte care reprezintă cele două fișiere, trebuie să le creăm undeva
și, de asemenea, să le facă să fie trecute la chiuvete de urme. Dacă te uiți în principal funcţie,
veți găsi un cod nou pentru a face exact asta:

AsciiTraceHelper asciiTraceHelper;
Ptr stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, flux));

...

PcapHelper pcapHelper;
Ptr fișier = pcapHelper.CreateFile ("al șaselea.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext(„PhyRxDrop”, MakeBoundCallback (&RxDrop, fișier));

În prima secțiune a fragmentului de cod de mai sus, creăm fișierul de urmărire ASCII,
crearea unui obiect responsabil cu gestionarea acestuia și utilizarea unei variante a callback-ului
funcția de creație pentru a aranja ca obiectul să fie trecut la chiuvetă. Urma noastră ASCII
ajutoarele oferă un set bogat de funcții pentru a facilita utilizarea fișierelor text (ASCII). Noi suntem
Vom ilustra aici utilizarea funcției de creare a fluxului de fișiere.

CreateFileStream Funcția va instanția a std::ofstream obiect şi
creați un fișier nou (sau trunchiați un fișier existent). Acest std::ofstream este ambalat într-un
ns-3 obiect pentru managementul de viață și rezolvarea problemelor constructorului de copiere.

Atunci luăm asta ns-3 obiect reprezentând fișierul și transmiteți-l către MakeBoundCallback().
Această funcție creează un apel invers la fel ca MakeCallback(), dar „leagă” o nouă valoare la
apelul înapoi. Această valoare este adăugată ca prim argument la apel invers înainte de a fi
numit.

In esenta, MakeBoundCallback(&CwndChange, curent) face ca sursa de urmărire să adauge
parametru suplimentar „stream” în fața listei de parametri formali înainte de invocare
apelul înapoi. Aceasta modifică semnătura necesară a CwndChange chiuvetă pentru a se potrivi cu cea
prezentat mai sus, care include parametrul „extra”. Ptr curent.

În a doua secțiune de cod din fragmentul de mai sus, instanțiăm a PcapHelper pentru a face
același lucru pentru fișierul nostru de urmărire PCAP pe care l-am făcut cu AsciiTraceHelper. Linia de
cod,

Ptr fișier = pcapHelper.CreateFile ("sixth.pcap",
„w”, PcapHelper::DLT_PPP);

creează un fișier PCAP numit „sixth.pcap” cu modul fișier „w”. Aceasta înseamnă că noul fișier
este trunchiat (conținutul șters) dacă este găsit un fișier existent cu acel nume. Finala
parametrul este „tipul de legătură de date” al noului fișier PCAP. Acestea sunt aceleași cu PCAP
tipuri de linkuri de date de bibliotecă definite în bpf.h dacă sunteți familiarizat cu PCAP. În acest caz,
DLT_PPP indică faptul că fișierul PCAP va conține pachete prefixate cu point to
antete de puncte. Acest lucru este adevărat, deoarece pachetele provin de la dispozitivul nostru punct la punct
conducător auto. Alte tipuri comune de legături de date sunt DLT_EN10MB (10 MB Ethernet) adecvate pentru csma
dispozitive și DLT_IEEE802_11 (IEEE 802.11) adecvat pentru dispozitivele wifi. Acestea sunt definite
in src/network/helper/trace-helper.h dacă sunteți interesat să vedeți lista. The
intrările din listă se potrivesc cu cele din bpf.h dar le duplicăm pentru a evita o sursă PCAP
dependență.

A ns-3 obiectul care reprezintă fișierul PCAP este returnat de la CreateFile și folosit într-o legătură
apel invers exact așa cum a fost în cazul ASCII.

Un ocol important: este important de observat că, deși ambele aceste obiecte sunt
declarat în moduri foarte asemănătoare,

Ptr fisier...
Ptr curent ...

Obiectele subiacente sunt complet diferite. De exemplu, cel Ptr este
indicator inteligent către o ns-3 Obiect care este un lucru destul de greu pe care îl susține
Atribute și este integrat în sistemul Config. The Ptr, Pe
pe de altă parte, este un indicator inteligent către un obiect numărat de referință care este foarte ușor
lucru. Nu uitați să vă uitați la obiectul la care faceți referire înainte de a face presupuneri
despre „puterile” pe care le poate avea acel obiect.

De exemplu, aruncați o privire src/network/utils/pcap-file-wrapper.h în distribuţie şi
înștiințare,

clasa PcapFileWrapper : obiect public

acea clasă PcapFileWrapper este o ns-3 Obiect în virtutea moștenirii sale. Atunci uită-te la
src/network/model/output-stream-wrapper.h și observă,

clasa OutputStreamWrapper : public
SimpleRefCount

că acest obiect nu este un ns-3 Obiect, este „doar” un obiect C++ care se întâmplă
suportă numărarea intruzivă a referințelor.

Ideea aici este că doar pentru că ai citit Ptr nu înseamnă neapărat
acea ceva este o ns-3 Obiect de care poți agăța ns-3 Atribute, de exemplu.

Acum, revenim la exemplu. Dacă construiți și rulați acest exemplu,

$ ./waf --al șase

veți vedea aceleași mesaje ca atunci când ați rulat „al cincilea”, dar două fișiere noi vor apărea
apar în directorul de nivel superior al dvs ns-3 distribuție.

al saselea.cwnd al saselea.pcap

Deoarece „sixth.cwnd” este un fișier text ASCII, îl puteți vizualiza cu pisică sau fișierul tău preferat
vizualizator.

1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144
...
9.69256 5149 5204
9.89311 5204 5259

Aveți un fișier separat de file cu un marcaj de timp, o veche fereastră de congestie și una nouă
fereastră de congestie potrivită pentru importarea directă în programul dvs. de plot. Nu sunt
printuri străine în fișier, nu este necesară analizarea sau editarea.

Deoarece „sixth.pcap” este un fișier PCAP, îl puteți vizualiza cu tcpdump.

citire din fișierul sixth.pcap, tip link PPP (PPP)
1.136956 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 17177:17681, ack 1, win 32768, options [TS val 1133 ecr 1127,eol]
1.403196 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 33280:33784, ack 1, win 32768, options [TS val 1399 ecr 1394,eol]
...
7.426220 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 785704:786240, ack 1, win 32768, options [TS val 7423 ecr 7421,eol]
9.630693 IP 10.1.1.1.49153 > 10.1.1.2.8080: Flags [.], seq 882688:883224, ack 1, win 32768, options [TS val 9620 ecr 9618,eol]

Aveți un fișier PCAP cu pachetele care au fost aruncate în simulare. Nu sunt
alte pachete sunt prezente în fișier și nu există nimic altceva care să facă viață
dificil.

A fost o călătorie lungă, dar acum suntem într-un punct în care putem aprecia ns-3
sistem de urmărire. Am scos evenimente importante din mijlocul implementării TCP
și un driver de dispozitiv. Am stocat aceste evenimente direct în fișiere utilizabile cu cele cunoscute
unelte. Am făcut acest lucru fără a modifica niciunul din codul de bază implicat și am făcut acest lucru în
doar 18 linii de cod:

gol static
CwndChange (Ptr flux, 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 ("sixth.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, flux));

...

gol static
RxDrop (Ptr dosar, Ptr p)
{
NS_LOG_UNCOND ("RxDrop la " << Simulator::Now ().GetSeconds ());
fisier->Write(Simulator::Now(), p);
}

...

PcapHelper pcapHelper;
Ptr fișier = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext(„PhyRxDrop”, MakeBoundCallback (&RxDrop, fișier));

Urmă Ajutoare
ns-3 Ajutoarele de urmărire oferă un mediu bogat pentru configurarea și selectarea diferitelor
urmăriți evenimentele și scrieți-le în fișiere. În secțiunile anterioare, în primul rând
BuildingTopologies, am văzut mai multe varietăți de metode de ajutor de urmărire proiectate
pentru utilizare în interiorul altor ajutoare (dispozitive).

Poate vă amintiți că ați văzut unele dintre aceste variații:

pointToPoint.EnablePcapAll ("al doilea");
pointToPoint.EnablePcap ("al doilea", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("al treilea", csmaDevices.Get (0), true);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Ceea ce poate să nu fie evident, însă, este că există un model consistent pentru toate
metode legate de urme găsite în sistem. Acum vom lua puțin timp și vom arunca o privire
la „imaginea de ansamblu”.

În prezent, există două cazuri de utilizare principale ale ajutoarelor de urmărire în ns-3: ajutoare de dispozitiv
și ajutoare de protocol. Ajutoarele de dispozitiv analizează problema de a specifica ce urme
ar trebui să fie activat printr-o pereche (nod, dispozitiv). De exemplu, poate doriți să specificați
că urmărirea PCAP ar trebui să fie activată pe un anumit dispozitiv pe un anumit nod. Acest
urmează din ns-3 modelul conceptual al dispozitivului, precum și modelele conceptuale ale
diverși ajutoare pentru dispozitive. Urmând în mod firesc de aici, fișierele create urmează a
- - convenție de numire.

Ajutoarele de protocol analizează problema specificării prin care urme ar trebui activate
o pereche de protocol și interfață. Aceasta rezultă din ns-3 stiva de protocol conceptual
model, precum și modelele conceptuale ale ajutoarelor de stivă de internet. Desigur, urma
fișierele ar trebui să urmeze a - - convenție de numire.

Prin urmare, ajutoarele de urmărire se încadrează în mod natural într-o taxonomie bidimensională. Sunt
subtilități care împiedică toate cele patru clase să se comporte identic, dar ne străduim să o facem
fă-le pe toate să funcționeze cât mai similar posibil; iar ori de câte ori este posibil există analogi pentru
toate metodele din toate clasele.

┌────────────────┬──────┬───────
│ │ PCAP │ ASCII │
└────────────────┴──────┴──────────

│Device Helper │ │ │
├────────────────┼──────┼───────
│Protocol Helper │ │ │
└────────────────┴──────┴──────────

Folosim o abordare numită a mixin pentru a adăuga funcționalitate de urmărire la clasele noastre de ajutor. A
mixin este o clasă care oferă funcționalitate atunci când este moștenită de o subclasă.
Moștenirea de la un mixin nu este considerată o formă de specializare, ci este într-adevăr o modalitate de a face acest lucru
colectează funcționalitatea.

Să aruncăm o privire rapidă asupra tuturor acestor patru cazuri și a acestora mixine.

Dispozitiv Ajutoare
PCAP
Scopul acestor ajutoare este de a facilita adăugarea unei facilitati de urmărire PCAP coerente la un
ns-3 dispozitiv. Dorim ca toate variantele de urmărire PCAP să funcționeze la fel
toate dispozitivele, astfel încât metodele acestor ajutoare sunt moștenite de ajutoarele de dispozitiv. Aruncă o privire
at src/network/helper/trace-helper.h dacă vrei să urmărești discuția în timp ce te uiți la
cod real.

Clasa PcapHelperForDevice este mixin oferă funcționalitate de nivel înalt pentru utilizare
Urmărirea PCAP într-un ns-3 dispozitiv. Fiecare dispozitiv trebuie să implementeze o singură metodă virtuală
moștenit din această clasă.

virtual void EnablePcapInternal (prefix std::string, Ptr nd, bool promiscuu, bool explicitFilename) = 0;

Semnătura acestei metode reflectă viziunea centrată pe dispozitiv a situației la aceasta
nivel. Toate metodele publice moștenite de la clasă PcapUserHelperForDevice A se reduce la
apelând această metodă de implementare unică dependentă de dispozitiv. De exemplu, cel mai jos nivel
metoda PCAP,

void EnablePcap (prefix std::string, Ptr nd, bool promiscuous = fals, bool explicitFilename = fals);

va apela implementarea dispozitivului de EnablePcapInternal direct. Toate celelalte PCAP publice
metodele de urmărire se bazează pe această implementare pentru a oferi un nivel suplimentar de utilizator
funcţionalitate. Ceea ce înseamnă acest lucru pentru utilizator este că toți asistența dispozitivului din sistem o vor face
au toate metodele de urmărire PCAP disponibile; iar aceste metode vor funcționa toate la fel
drum peste dispozitive dacă dispozitivul implementează EnablePcapInternal corect.

Aplicate
void EnablePcap (prefix std::string, Ptr nd, bool promiscuous = fals, bool explicitFilename = fals);
void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = fals);
void EnablePcap (prefix std::string, NetDeviceContainer d, bool promiscuous = false);
void EnablePcap (prefix std::string, NodeContainer n, bool promiscuous = false);
void EnablePcap (std::prefix șir, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
void EnablePcapAll (prefix std::string, bool promiscuous = false);

În fiecare dintre metodele prezentate mai sus, există un parametru implicit numit promiscuu acea
implicit la fals. Acest parametru indică faptul că urma nu trebuie adunată
modul promiscuu. Dacă doriți ca urmele dvs. să includă tot traficul văzut de dispozitiv
(și dacă dispozitivul acceptă un mod promiscuu), adăugați pur și simplu un parametru adevărat la oricare dintre
apelurile de mai sus. De exemplu,

Ptr nd;
...
helper.EnablePcap ("prefix", nd, true);

va permite capturi în mod promiscuu pe NetDevice specificat de nd.

Primele două metode includ și un parametru implicit numit explicitFilename asta va fi
fi discutat mai jos.

Sunteți încurajat să citiți documentația API pentru curs PcapHelperForDevice pentru a găsi
detaliile acestor metode; dar pentru a rezuma...

· Puteți activa urmărirea PCAP pe o anumită pereche nod/net-dispozitiv furnizând un
Ptr la un EnablePcap metodă. Ptr este implicit din moment ce dispozitivul net
trebuie să aparțină exact unui singur Nod. De exemplu,

Ptr nd;
...
helper.EnablePcap ("prefix", nd);

· Puteți activa urmărirea PCAP pe o anumită pereche nod/net-dispozitiv furnizând un
std::string reprezentând un șir de servicii de nume de obiect la un EnablePcap metodă.
Ptr este căutat din șirul de nume. Din nou, este implicit din moment ce
dispozitivul net numit trebuie să aparțină exact unui Nod. De exemplu,

Nume::Add ("server" ...);
Nume::Add ("server/eth0" ...);
...
helper.EnablePcap ("prefix", "server/ath0");

· Puteți activa urmărirea PCAP pe o colecție de perechi nod/net-dispozitiv furnizând a
NetDeviceContainer. Pentru fiecare NetDevice în container se verifică tipul. Pentru fiecare
dispozitiv de tipul adecvat (același tip cu cel gestionat de dispozitivul de ajutor), urmărirea este
activat. Din nou, este implicit deoarece dispozitivul net găsit trebuie să aparțină
exact un Nod. De exemplu,

NetDeviceContainer d = ...;
...
helper.EnablePcap ("prefix", d);

· Puteți activa urmărirea PCAP pe o colecție de perechi nod/net-dispozitiv furnizând a
NodeContainer. Pentru fiecare Nod din NodeContainer este atașat NetDevices sunt iterate.
Pentru fiecare NetDevice atașat fiecărui Nod din container, tipul dispozitivului respectiv este
verificat. Pentru fiecare dispozitiv de tipul adecvat (același tip cu cel gestionat de dispozitiv
helper), urmărirea este activată.

NodeContainer n;
...
helper.EnablePcap ("prefix", n);

· Puteți activa urmărirea PCAP pe baza ID-ului nodului și ID-ului dispozitivului, precum și cu
explicit PTR. Fiecare Nod din sistem are un ID de Nod întreg și fiecare dispozitiv conectat
la un Nod are un ID de dispozitiv întreg.

helper.EnablePcap ("prefix", 21, 1);

· În cele din urmă, puteți activa urmărirea PCAP pentru toate dispozitivele din sistem, cu același tip
ca cel gestionat de asistentul dispozitivului.

helper.EnablePcapAll ("prefix");

Numele fișierelor
În descrierile metodelor de mai sus este implicită construcția unui nume de fișier complet de către
metoda de implementare. Prin convenție, PCAP urmărește în ns-3 sistem sunt de forma
- id>- id>.pcap

După cum sa menționat anterior, fiecare Nod din sistem va avea un ID de Nod atribuit de sistem; și
fiecare dispozitiv va avea un index de interfață (numit și id de dispozitiv) relativ la nodul său.
Prin urmare, implicit, un fișier de urmărire PCAP creat ca urmare a activării urmăririi pe primul
dispozitivul Nodului 21 care folosește prefixul „prefix” ar fi prefix-21-1.pcap.

Puteți utiliza întotdeauna ns-3 serviciu de nume obiect pentru a face acest lucru mai clar. De exemplu, dacă
utilizați serviciul de nume obiect pentru a atribui numele „server” Nodului 21, PCAP rezultat
numele fișierului de urmărire va deveni automat, prefix-server-1.pcap iar dacă atribuiți și
numele „eth0” pe dispozitiv, numele fișierului PCAP îl va prelua automat și va fi
denumit prefix-server-eth0.pcap.

În cele din urmă, două dintre metodele prezentate mai sus,

void EnablePcap (prefix std::string, Ptr nd, bool promiscuous = fals, bool explicitFilename = fals);
void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = fals);

au un parametru implicit numit explicitFilename. Când este setat la adevărat, acest parametru
dezactivează mecanismul automat de completare a numelui de fișier și vă permite să creați un fișier explicit
nume de fișier. Această opțiune este disponibilă numai în metodele care permit urmărirea PCAP pe a
dispozitiv unic.

De exemplu, pentru a aranja ca un asistent de dispozitiv să creeze un singur PCAP promiscuu
fișier de captură cu un anumit nume my-pcap-file.pcap pe un dispozitiv dat, se poate:

Ptr nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);

Prima adevărat parametrul activează urmele modului promiscuu, iar al doilea îi spune ajutorului
a interpreta prefix parametru ca nume complet de fișier.

ASCII
Comportamentul asistentului de urmărire ASCII mixin este substanțial similar cu versiunea PCAP.
Aruncati o privire la src/network/helper/trace-helper.h daca vrei sa urmaresti discutia
în timp ce se uită la codul real.

Clasa AsciiTraceHelperForDevice adaugă funcționalitatea de nivel înalt pentru utilizarea ASCII
urmărirea la o clasă de ajutor de dispozitiv. Ca și în cazul PCAP, fiecare dispozitiv trebuie să implementeze a
o singură metodă virtuală moștenită din urma ASCII mixin.

virtual void EnableAsciiInternal (Ptr curent,
std::prefix șir,
Ptr nd,
bool explicitFilename) = 0;

Semnătura acestei metode reflectă viziunea centrată pe dispozitiv a situației la aceasta
nivel; și, de asemenea, faptul că asistentul poate scrie într-un flux de ieșire partajat. Toate
metodele publice legate de urme ASCII moștenite de la clasă AsciiTraceHelperForDevice
reduceți la apelarea acestei metode de implementare unică dependentă de dispozitiv. De exemplu, cel
metode de urmărire ascii de cel mai scăzut nivel,

void EnableAscii (prefix std::string, Ptr nd, bool explicitFilename = false);
void EnableAscii (Ptr pârâu, Ptr nd);

va apela implementarea dispozitivului de EnableAsciiInternal direct, oferind fie a
prefix sau flux valid. Toate celelalte metode publice de urmărire ASCII se vor baza pe acestea
funcții de nivel scăzut pentru a oferi funcționalități suplimentare la nivel de utilizator. Ce înseamnă asta
utilizatorul este că toți ajutoarele de dispozitiv din sistem vor avea toate metodele de urmărire ASCII
disponibil; și aceste metode vor funcționa toate în același mod pe toate dispozitivele dacă dispozitivele
punerea în aplicare a EnablAsciiInternal corect.

Aplicate
void EnableAscii (prefix std::string, Ptr nd, bool explicitFilename = false);
void EnableAscii (Ptr pârâu, Ptr nd);

void EnableAscii (std::string prefix, std::string ndName, bool explicitFilename = false);
void EnableAscii (Ptr stream, std::string ndName);

void EnableAscii (prefix std::string, NetDeviceContainer d);
void EnableAscii (Ptr flux, NetDeviceContainer d);

void EnableAscii (prefix std::string, NodeContainer n);
void EnableAscii (Ptr flux, NodeContainer n);

void EnableAsciiAll (prefix std::string);
void EnableAsciiAll (Ptr curent);

void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
void EnableAscii (Ptr flux, uint32_t nodeid, uint32_t deviceid);

Sunteți încurajat să citiți documentația API pentru curs AsciiTraceHelperForDevice la
găsiți detaliile acestor metode; dar pentru a rezuma...

· Există de două ori mai multe metode disponibile pentru urmărirea ASCII decât pentru PCAP
trasarea. Acest lucru se datorează faptului că, în plus față de modelul în stil PCAP, unde urme din fiecare
perechea unică nod/dispozitiv sunt scrise într-un fișier unic, acceptăm un model în care urmărește
informațiile pentru multe perechi noduri/dispozitive sunt scrise într-un fișier comun. Aceasta înseamnă că
- - mecanismul de generare a numelui de fișier este înlocuit cu un mecanism de
se referă la un fișier comun; iar numărul de metode API este dublat pentru a permite toate
combinații.

· La fel ca în urmărirea PCAP, puteți activa urmărirea ASCII pe un anumit (nod, dispozitiv net)
pereche prin furnizarea unui Ptr la un EnableAscii metodă. Ptr este implicită
deoarece dispozitivul net trebuie să aparțină exact unui Nod. De exemplu,

Ptr nd;
...
helper.EnableAscii („prefix”, nd);

· Primele patru metode includ, de asemenea, un parametru implicit numit explicitFilename acea
funcționează similar cu parametrii echivalenti în cazul PCAP.

În acest caz, nu sunt scrise contexte de urmărire în fișierul de urmărire ASCII, deoarece acestea ar fi
redundant. Sistemul va alege numele fișierului care urmează să fie creat folosind aceleași reguli ca
descrise în secțiunea PCAP, cu excepția faptului că fișierul va avea sufixul tr în loc de
.pcap.

· Dacă doriți să activați urmărirea ASCII pe mai multe dispozitive de rețea și să trimiteți toate urmele
la un singur fișier, puteți face asta și folosind un obiect pentru a face referire la un singur fișier.
Am văzut deja acest lucru în exemplul „cwnd” de mai sus:

Ptr nd1;
Ptr nd2;
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAscii (stream, nd1);
helper.EnableAscii (stream, nd2);

În acest caz, urmăriți contexte sunt scrise în fișierul de urmărire ASCII, deoarece sunt necesare
pentru a dezambiguiza urmele de la cele două dispozitive. Rețineți că, deoarece utilizatorul este complet
specificând numele fișierului, șirul ar trebui să includă ,tr sufix pentru consecvență.

· Puteți activa urmărirea ASCII pe o anumită pereche (nod, dispozitiv net) furnizând a
std::string reprezentând un șir de servicii de nume de obiect la un EnablePcap metodă.
Ptr este căutat din șirul de nume. Din nou, este implicit din moment ce
dispozitivul net numit trebuie să aparțină exact unui Nod. De exemplu,

Nume::Adăugați ("client" ...);
Nume::Add ("client/eth0" ...);
Nume::Add ("server" ...);
Nume::Add ("server/eth0" ...);
...
helper.EnableAscii ("prefix", "client/eth0");
helper.EnableAscii ("prefix", "server/eth0");

Acest lucru ar avea ca rezultat două fișiere numite ``prefix-client-eth0.tr`` și
``prefix-server-eth0.tr`` cu urme pentru fiecare dispozitiv din
fișierul de urmărire respectiv. Deoarece toate funcțiile ``EnableAscii``
sunt supraîncărcate pentru a prelua un înveliș de flux, puteți utiliza acest formular ca
bine::

Nume::Adăugați ("client" ...);
Nume::Add ("client/eth0" ...);
Nume::Add ("server" ...);
Nume::Add ("server/eth0" ...);
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAscii (stream, "client/eth0");
helper.EnableAscii (stream, "server/eth0");

Acest lucru ar avea ca rezultat un singur fișier de urmărire numit trace-file-name.tr care contine toate
evenimentele de urmărire pentru ambele dispozitive. Evenimentele ar fi dezambiguate de contextul urmelor
siruri de caractere.

· Puteți activa urmărirea ASCII pe o colecție de perechi (nod, dispozitiv net) furnizând un
NetDeviceContainer. Pentru fiecare NetDevice în container se verifică tipul. Pentru fiecare
dispozitiv de tipul adecvat (același tip cu cel gestionat de dispozitivul de ajutor), urmărirea este
activat. Din nou, este implicit deoarece dispozitivul net găsit trebuie să aparțină
exact un Nod. De exemplu,

NetDeviceContainer d = ...;
...
helper.EnableAscii („prefix”, d);

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII,
fiecare urmează după `` - - .tr``
convenţie.

Combinarea tuturor urmelor într-un singur fișier se realizează în mod similar cu exemplele
de mai sus:

NetDeviceContainer d = ...;
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAscii (stream, d);

· Puteți activa urmărirea ASCII pe o colecție de perechi (nod, dispozitiv net) furnizând un
NodeContainer. Pentru fiecare Nod din NodeContainer este atașat NetDevices sunt iterate.
Pentru fiecare NetDevice atașat fiecărui Nod din container, tipul dispozitivului respectiv este
verificat. Pentru fiecare dispozitiv de tipul adecvat (același tip cu cel gestionat de dispozitiv
helper), urmărirea este activată.

NodeContainer n;
...
helper.EnableAscii („prefix”, n);

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII, fiecare dintre ele urmează
il - id>- id>.tr convenţie. Combinând toate urmele într-un
un singur fișier se realizează în mod similar cu exemplele de mai sus.

· Puteți activa urmărirea PCAP pe baza ID-ului nodului și ID-ului dispozitivului, precum și cu
explicit PTR. Fiecare Nod din sistem are un ID de Nod întreg și fiecare dispozitiv conectat
la un Nod are un ID de dispozitiv întreg.

helper.EnableAscii („prefix”, 21, 1);

Desigur, urmele pot fi combinate într-un singur fișier, așa cum se arată mai sus.

· În cele din urmă, puteți activa urmărirea PCAP pentru toate dispozitivele din sistem, cu același tip
ca cel gestionat de asistentul dispozitivului.

helper.EnableAsciiAll ("prefix");

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII, unul pentru fiecare dispozitiv
în sistemul de tipul gestionat de ajutor. Toate aceste fișiere vor urma
- id>- id>.tr convenţie. Combinând toate urmele într-un singur
fișierul se realizează în mod similar cu exemplele de mai sus.

Numele fișierelor
Implicită în descrierile metodei în stil prefix de mai sus este construcția completului
nume de fișiere prin metoda de implementare. Prin convenție, urmele ASCII în ns-3 sistem
sunt de forma - id>- id>.tr

După cum sa menționat anterior, fiecare Nod din sistem va avea un ID de Nod atribuit de sistem; și
fiecare dispozitiv va avea un index de interfață (numit și id de dispozitiv) relativ la nodul său.
Prin urmare, implicit, un fișier de urmărire ASCII creat ca urmare a activării urmăririi pe primul
dispozitivul Nodului 21, folosind prefixul „prefix”, ar fi prefix-21-1.tr.

Puteți utiliza întotdeauna ns-3 serviciu de nume obiect pentru a face acest lucru mai clar. De exemplu, dacă
utilizați serviciul de nume obiect pentru a atribui numele „server” Nodului 21, rezultatul
Numele fișierului de urmărire ASCII va deveni automat, prefix-server-1.tr iar dacă de asemenea atribui
numele „eth0” pe dispozitiv, numele fișierului de urmărire ASCII va prelua automat acest lucru
și fii chemat prefix-server-eth0.tr.

Mai multe dintre metode au un parametru implicit numit explicitFilename. Când este setat la
adevărat, acest parametru dezactivează mecanismul automat de completare a numelui de fișier și vă permite
pentru a crea un nume de fișier explicit. Această opțiune este disponibilă numai în metodele care iau a
prefix și activați urmărirea pe un singur dispozitiv.

Protocol Ajutoare
PCAP
Scopul acestora mixine este de a facilita adăugarea unei facilitati de urmărire PCAP consecventă la
protocoale. Dorim ca toate variantele de urmărire PCAP să funcționeze la fel în toate
protocoale, astfel încât metodele acestor ajutoare sunt moștenite de ajutoarele de stivă. Aruncăm o privire la
src/network/helper/trace-helper.h dacă vrei să urmărești discuția în timp ce te uiți la
cod real.

În această secțiune vom ilustra metodele aplicate protocolului IPv4. Pentru
specificați urme în protocoale similare, înlocuiți doar tipul corespunzător. De exemplu,
folosește o Ptr în loc de a Ptr și sunați Activați PcapIpv6 în loc de Activați PcapIpv4.

Clasa PcapHelperForIpv4 oferă funcționalitatea de nivel înalt pentru utilizarea urmăririi PCAP
în IPv4 protocol. Fiecare asistent de protocol care permite aceste metode trebuie să implementeze unul singur
metoda virtuala mostenita din aceasta clasa. Va exista o implementare separată pentru
IPv6, de exemplu, dar singura diferență va fi în numele metodelor și semnăturile.
Sunt necesare nume de metode diferite pentru a dezambigua clasa IPv4 din IPv6 care sunt ambele
derivat din clasă Obiect, și metode care au aceeași semnătură.

virtual void EnablePcapIpv4Internal (prefix std::string,
Ptr ipv4,
interfață uint32_t,
bool explicitFilename) = 0;

Semnătura acestei metode reflectă protocolul și vizualizarea centrată pe interfață a
situatie la acest nivel. Toate metodele publice moștenite de la clasă PcapHelperForIpv4
reduceți la apelarea acestei metode de implementare unică dependentă de dispozitiv. De exemplu, cel
metoda PCAP de cel mai scăzut nivel,

void EnablePcapIpv4 (prefix std::string, Ptr ipv4, interfață uint4_t, bool explicitFilename = false);

va apela implementarea dispozitivului de Activați PcapIpv4Internal direct. Toate celelalte publice
Metodele de urmărire PCAP se bazează pe această implementare pentru a oferi un nivel suplimentar de utilizator
funcţionalitate. Ce înseamnă acest lucru pentru utilizator este că toți ajutoarele de protocol din sistem
va avea disponibile toate metodele de urmărire PCAP; iar aceste metode vor funcționa toate în
același mod în toate protocoalele dacă ajutorul implementează Activați PcapIpv4Internal corect.

Aplicate
Aceste metode sunt concepute pentru a fi în corespondență unu-la-unu cu Nodul- și
NetDevice- versiuni centrate ale versiunilor de dispozitiv. În loc de Node și NetDevice pereche
constrângeri, folosim constrângeri de protocol și interfață.

Rețineți că, la fel ca în versiunea dispozitivului, există șase metode:

void EnablePcapIpv4 (prefix std::string, Ptr ipv4, interfață uint4_t, bool explicitFilename = false);
void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, interfață uint32_t, bool explicitFilename = false);
void EnablePcapIpv4 (prefix std::string, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std::prefix șir, NodeContainer n);
void EnablePcapIpv4 (std::prefix șir, uint32_t nodeid, uint32_t interfață, bool explicitFilename);
void EnablePcapIpv4All (prefix std::string);

Sunteți încurajat să citiți documentația API pentru curs PcapHelperForIpv4 pentru a găsi
detalii despre aceste metode; dar pentru a rezuma...

· Puteți activa urmărirea PCAP pe o anumită pereche de protocol/interfață furnizând un
Ptr si interfață la un EnablePcap metodă. De exemplu,

Ptr ipv4 = nod->GetObject ();
...
helper.EnablePcapIpv4 („prefix”, ipv4, 0);

· Puteți activa urmărirea PCAP pe o anumită pereche nod/net-dispozitiv furnizând un
std::string reprezentând un șir de servicii de nume de obiect la un EnablePcap metodă.
Ptr este căutat din șirul de nume. De exemplu,

Names::Add ("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("prefix", "serverIpv4", 1);

· Puteți activa urmărirea PCAP pe o colecție de perechi de protocol/interfață furnizând un
IPv4InterfaceContainer. Pentru fiecare IPv4 / perechea de interfață în container protocolul
tipul este verificat. Pentru fiecare protocol de tipul adecvat (același tip cu cel gestionat de
asistentul dispozitivului), urmărirea este activată pentru interfața corespunzătoare. De exemplu,

Nodurile NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (noduri);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfețe Ipv4InterfaceContainer = ipv4.Assign (dispozitive);
...
helper.EnablePcapIpv4 („prefix”, interfețe);

· Puteți activa urmărirea PCAP pe o colecție de perechi de protocol/interfață furnizând un
NodeContainer. Pentru fiecare Nod din NodeContainer se găsește protocolul corespunzător.
Pentru fiecare protocol, interfețele sale sunt enumerate și urmărirea este activată pe rezultatul
perechi. De exemplu,

NodeContainer n;
...
helper.EnablePcapIpv4 ("prefix", n);

· Puteți activa urmărirea PCAP și pe baza ID-ului nodului și a interfeței. In acest
caz, id-ul nodului este tradus în a Ptr și se caută protocolul corespunzător
în nod. Protocolul rezultat și interfața sunt utilizate pentru a specifica rezultatul
sursa de urma.

helper.EnablePcapIpv4 ("prefix", 21, 1);

· În cele din urmă, puteți activa urmărirea PCAP pentru toate interfețele din sistem, cu asociate
protocolul fiind de același tip cu cel gestionat de asistentul dispozitivului.

helper.EnablePcapIpv4All ("prefix");

Numele fișierelor
Implicită în toate descrierile metodelor de mai sus este construcția întregului
nume de fișiere prin metoda de implementare. Prin convenție, urmele PCAP preluate pentru dispozitive în
il ns-3 sistemul sunt de forma " - - .pcap". În cazul
urme de protocol, există o corespondență unu-la-unu între protocoale și Nodurile. Acest
este pentru că protocolul Obiecte sunt agregate la Nod Obiecte. Din moment ce nu există global
ID de protocol în sistem, folosim id-ul de nod corespunzător în denumirea fișierelor. Prin urmare
există posibilitatea unor coliziuni de nume de fișiere în numele fișierelor de urmărire alese automat.
Din acest motiv, convenția de nume de fișier este modificată pentru urmele protocolului.

După cum sa menționat anterior, fiecare Nod din sistem va avea un ID de Nod atribuit de sistem.
Deoarece există o corespondență unu-la-unu între instanțe de protocol și instanțe Node
folosim Node id. Fiecare interfață are un ID de interfață în raport cu protocolul său. Folosim
convenția" -n -i .pcap" pentru denumirea fișierelor de urmărire în
ajutoare de protocol.

Prin urmare, în mod implicit, un fișier de urmărire PCAP creat ca urmare a activării urmăririi
ar fi interfața 1 a protocolului Ipv4 al Nodului 21 folosind prefixul „prefix”.
„prefix-n21-i1.pcap”.

Puteți utiliza întotdeauna ns-3 serviciu de nume obiect pentru a face acest lucru mai clar. De exemplu, dacă
utilizați serviciul de nume obiect pentru a atribui numele „serverIpv4” la Ptr pe Node
21, numele fișierului de urmărire PCAP rezultat va deveni automat,
„prefix-nserverIpv4-i1.pcap”.

Mai multe dintre metode au un parametru implicit numit explicitFilename. Când este setat la
adevărat, acest parametru dezactivează mecanismul automat de completare a numelui de fișier și vă permite
pentru a crea un nume de fișier explicit. Această opțiune este disponibilă numai în metodele care iau a
prefix și activați urmărirea pe un singur dispozitiv.

ASCII
Comportamentul ajutoarelor de urmărire ASCII este substanțial similar cu cazul PCAP. Ia o
privi la src/network/helper/trace-helper.h dacă vrei să urmărești discuția în timp ce
privind codul real.

În această secțiune vom ilustra metodele aplicate protocolului IPv4. Pentru
specificați urme în protocoale similare, înlocuiți doar tipul corespunzător. De exemplu,
folosește o Ptr în loc de a Ptr și sunați Activați AsciiIpv6 în loc de
Activați AsciiIpv4.

Clasa AsciiTraceHelperForIpv4 adaugă funcționalitatea de nivel înalt pentru utilizarea ASCII
urmărirea la un asistent de protocol. Fiecare protocol care permite aceste metode trebuie să implementeze a
o singură metodă virtuală moștenită din această clasă.

virtual void EnableAsciiIpv4Internal (Ptr curent,
std::prefix șir,
Ptr ipv4,
interfață uint32_t,
bool explicitFilename) = 0;

Semnătura acestei metode reflectă viziunea centrată pe protocol și interfață a
situația la acest nivel; și, de asemenea, faptul că asistentul poate scrie la un shared
flux de ieșire. Toate metodele publice moștenite de la clasă
PcapAndAsciiTraceHelperForIpv4 reduceți la apelarea acestui singur dispozitiv dependent
metoda de implementare. De exemplu, metodele de urmărire ASCII de cel mai scăzut nivel,

void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interfață uint4_t, bool explicitFilename = false);
void EnableAsciiIpv4 (Ptr pârâu, Ptr ipv4, interfață uint4_t);

va apela implementarea dispozitivului de EnableAsciiIpv4Internal direct, oferind fie
prefixul sau fluxul. Toate celelalte metode publice de urmărire ASCII se vor baza pe acestea
funcții de nivel scăzut pentru a oferi funcționalități suplimentare la nivel de utilizator. Ce înseamnă asta
utilizatorul este că toți ajutoarele de dispozitiv din sistem vor avea toate metodele de urmărire ASCII
disponibil; și aceste metode vor funcționa toate în același mod peste protocoale dacă
implementarea protocoalelor EnablAsciiIpv4Internal corect.

Aplicate
void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interfață uint4_t, bool explicitFilename = false);
void EnableAsciiIpv4 (Ptr pârâu, Ptr ipv4, interfață uint4_t);

void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, interfață uint32_t, bool explicitFilename = false);
void EnableAsciiIpv4 (Ptr flux, std::string ipv4Name, interfață uint32_t);

void EnableAsciiIpv4 (prefix std::string, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr flux, Ipv4InterfaceContainer c);

void EnableAsciiIpv4 (std::string prefix, NodeContainer n);
void EnableAsciiIpv4 (Ptr flux, NodeContainer n);

void EnableAsciiIpv4All (prefix std::string);
void EnableAsciiIpv4All (Ptr curent);

void EnableAsciiIpv4 (std::prefix șir, uint32_t nodeid, uint32_t deviceid, bool explicitFilename);
void EnableAsciiIpv4 (Ptr flux, uint32_t nodeid, interfață uint32_t);

Sunteți încurajat să citiți documentația API pentru curs PcapAndAsciiHelperForIpv4 la
găsiți detaliile acestor metode; dar pentru a rezuma...

· Există de două ori mai multe metode disponibile pentru urmărirea ASCII decât pentru PCAP
trasarea. Acest lucru se datorează faptului că, în plus față de modelul în stil PCAP, unde urme din fiecare
perechea unică de protocol/interfață sunt scrise într-un fișier unic, acceptăm un model în care
informațiile de urmărire pentru multe perechi de protocol/interfață sunt scrise într-un fișier comun. Acest
înseamnă că -n - mecanismul de generare a numelui fișierului este
înlocuit cu un mecanism de referire la un fișier comun; iar numărul de metode API este
dublat pentru a permite toate combinațiile.

· La fel ca în urmărirea PCAP, puteți activa urmărirea ASCII pe un anumit protocol/interfață
pereche prin furnizarea unui Ptr si un interfață la un EnableAscii metodă. De exemplu,

Ptr ipv4;
...
helper.EnableAsciiIpv4 („prefix”, ipv4, 1);

În acest caz, nu sunt scrise contexte de urmărire în fișierul de urmărire ASCII, deoarece acestea ar fi
redundant. Sistemul va alege numele fișierului care urmează să fie creat folosind aceleași reguli ca
descrise în secțiunea PCAP, cu excepția faptului că fișierul va avea în schimb sufixul „.tr”.
de „.pcap”.

· Dacă doriți să activați urmărirea ASCII pe mai multe interfețe și să trimiteți toate urmele
la un singur fișier, puteți face asta și folosind un obiect pentru a face referire la un singur fișier.
Avem deja ceva similar cu asta în exemplul „cwnd” de mai sus:

Ptr protocol4 = node1->GetObject ();
Ptr protocol4 = node2->GetObject ();
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAsciiIpv4 (stream, protocol1, 1);
helper.EnableAsciiIpv4 (stream, protocol2, 1);

În acest caz, contextele de urmărire sunt scrise în fișierul de urmărire ASCII, deoarece sunt necesare
pentru a dezambiguiza urmele din cele două interfețe. Rețineți că, deoarece utilizatorul este complet
specificând numele fișierului, șirul ar trebui să includă „,tr” pentru consecvență.

· Puteți activa urmărirea ASCII pe un anumit protocol furnizând un std::string
reprezentând un șir de servicii de nume de obiect la un EnablePcap metodă. Ptr is
ridică privirea din șirul numelui. The în numele de fişiere rezultate este implicită deoarece
există o corespondență unu-la-unu între instanțe de protocol și noduri, De exemplu,

Nume::Adăugați ("nod1Ipv4" ...);
Nume::Adăugați ("nod2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("prefix", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("prefix", "node2Ipv4", 1);

Acest lucru ar avea ca rezultat două fișiere numite „prefix-nnode1Ipv4-i1.tr” și
„prefix-nnode2Ipv4-i1.tr” cu urme pentru fiecare interfață din fișierul de urmărire respectiv.
Deoarece toate funcțiile EnableAscii sunt supraîncărcate pentru a prelua un stream wrapper, puteți
foloseste si acea forma:

Nume::Adăugați ("nod1Ipv4" ...);
Nume::Adăugați ("nod2Ipv4" ...);
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAsciiIpv4 (stream, „node1Ipv4”, 1);
helper.EnableAsciiIpv4 (stream, „node2Ipv4”, 1);

Acest lucru ar avea ca rezultat un singur fișier de urmărire numit „trace-file-name.tr” care conține toate
a evenimentelor de urmărire pentru ambele interfețe. Evenimentele ar fi dezambiguate prin urme
șiruri de context.

· Puteți activa urmărirea ASCII pe o colecție de perechi de protocol/interfață furnizând un
IPv4InterfaceContainer. Pentru fiecare protocol de tipul adecvat (același tip ca este
gestionat de asistentul dispozitivului), urmărirea este activată pentru interfața corespunzătoare.
Din nou, este implicită deoarece există o corespondență unu-la-unu între fiecare
protocolul și nodul acestuia. De exemplu,

Nodurile NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (noduri);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfețe Ipv4InterfaceContainer = ipv4.Assign (dispozitive);
...
...
helper.EnableAsciiIpv4 („prefix”, interfețe);

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII, fiecare dintre ele urmează
cel -n -i .tr conventie. Combinând toate urmele într-un
un singur fișier se realizează în mod similar cu exemplele de mai sus:

Nodurile NodeContainer;
...
NetDeviceContainer devices = deviceHelper.Install (noduri);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfețe Ipv4InterfaceContainer = ipv4.Assign (dispozitive);
...
Ptr flux = asciiTraceHelper.CreateFileStream ("nume-fișier-urmă.tr");
...
helper.EnableAsciiIpv4 (stream, interfețe);

· Puteți activa urmărirea ASCII pe o colecție de perechi de protocol/interfață furnizând un
NodeContainer. Pentru fiecare Nod din NodeContainer se găsește protocolul corespunzător.
Pentru fiecare protocol, interfețele sale sunt enumerate și urmărirea este activată pe rezultatul
perechi. De exemplu,

NodeContainer n;
...
helper.EnableAsciiIpv4 ("prefix", n);

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII, fiecare dintre ele urmează
cel - - .tr conventie. Combinând toate urmele într-un
un singur fișier se realizează în mod similar cu exemplele de mai sus.

· Puteți activa urmărirea PCAP și pe baza ID-ului nodului și a ID-ului dispozitivului. In acest
caz, id-ul nodului este tradus în a Ptr și se caută protocolul corespunzător
în nod. Protocolul rezultat și interfața sunt utilizate pentru a specifica rezultatul
sursa de urma.

helper.EnableAsciiIpv4 („prefix”, 21, 1);

Desigur, urmele pot fi combinate într-un singur fișier, așa cum se arată mai sus.

· În cele din urmă, puteți activa urmărirea ASCII pentru toate interfețele din sistem, cu asociate
protocolul fiind de același tip cu cel gestionat de asistentul dispozitivului.

helper.EnableAsciiIpv4All ("prefix");

Acest lucru ar duce la crearea unui număr de fișiere de urmărire ASCII, unul pentru fiecare
interfață în sistem legată de un protocol de tipul gestionat de helper. Toate
aceste fișiere vor urma -n -i
toate urmele într-un singur fișier sunt realizate în mod similar cu exemplele de mai sus.

Numele fișierelor
Implicită în descrierile metodei în stil prefix de mai sus este construcția completului
nume de fișiere prin metoda de implementare. Prin convenție, urmele ASCII în ns-3 sistem
sunt de forma " - - .tr"

După cum sa menționat anterior, fiecare Nod din sistem va avea un ID de Nod atribuit de sistem.
Deoarece există o corespondență unu-la-unu între protocoale și noduri, folosim pentru a node-id
pentru a identifica identitatea protocolului. Fiecare interfață dintr-un anumit protocol va avea un
index de interfață (numit și simplu interfață) în raport cu protocolul său. În mod implicit,
apoi, un fișier de urmărire ASCII creat ca urmare a activării urmăririi pe primul dispozitiv al
Nodul 21, folosind prefixul „prefix”, ar fi „prefix-n21-i1.tr”. Utilizați prefixul pentru
dezambiguizează mai multe protocoale per nod.

Puteți utiliza întotdeauna ns-3 serviciu de nume obiect pentru a face acest lucru mai clar. De exemplu, dacă
utilizați serviciul de nume obiect pentru a atribui numele „serverIpv4” protocolului de pe Node
21 și, de asemenea, specificați interfața unu, numele fișierului de urmărire ASCII rezultat va fi automat
deveni, „prefix-nserverIpv4-1.tr”.

Mai multe dintre metode au un parametru implicit numit explicitFilename. Când este setat la
adevărat, acest parametru dezactivează mecanismul automat de completare a numelui de fișier și vă permite
pentru a crea un nume de fișier explicit. Această opțiune este disponibilă numai în metodele care iau a
prefix și activați urmărirea pe un singur dispozitiv.

Rezumat
ns-3 include un mediu extrem de bogat care permite utilizatorilor de la mai multe niveluri să personalizeze
tipurile de informații care pot fi extrase din simulări.

Există funcții de ajutor de nivel înalt care permit utilizatorilor să controleze pur și simplu colecția de
ieșiri predefinite la o granularitate fină. Există funcții de ajutor de nivel mediu de permis
utilizatorii mai sofisticați să personalizeze modul în care sunt extrase și salvate informațiile; și acolo
sunt funcții de bază de nivel scăzut pentru a permite utilizatorilor experți să modifice sistemul pentru a prezenta noi și
informații neexportate anterior într-un mod care va fi imediat accesibil utilizatorilor la
niveluri superioare.

Acesta este un sistem foarte cuprinzător și ne dăm seama că este mult de digerat, mai ales
pentru utilizatorii noi sau cei care nu sunt foarte familiarizați cu C++ și idiomurile sale. Luăm în considerare
sistemul de urmărire o parte foarte importantă a ns-3 și de aceea recomand să deveniți la fel de familiar ca
posibil cu ea. Este probabil cazul că înțelegerea restului ns-3 sistem
va fi destul de simplu odată ce ați stăpânit sistemul de urmărire

DATE COLECTIE


Capitolul final al tutorialului prezintă câteva componente la care au fost adăugate ns-3 în versiune
3.18, și care sunt încă în curs de dezvoltare. Această secțiune de tutorial este, de asemenea, a
lucru în curs.

motivaţia
Unul dintre principalele puncte ale rulării simulărilor este generarea de date de ieșire, fie pentru
scopuri de cercetare sau pur și simplu pentru a afla despre sistem. În capitolul anterior, noi
a introdus subsistemul de urmărire și exemplul al şaselea.cc. din care urma PCAP sau ASCII
sunt generate fișiere. Aceste urme sunt valoroase pentru analiza datelor folosind o varietate de
instrumente externe și pentru mulți utilizatori, astfel de date de ieșire sunt un mijloc preferat de colectare
date (pentru analiza prin instrumente externe).

Cu toate acestea, există și cazuri de utilizare pentru mai mult decât generarea de fișiere de urmărire, inclusiv
Următor:

· generarea de date care nu se mapează bine la urmele PCAP sau ASCII, cum ar fi non-pachet
date (de exemplu, tranziții de mașină de stare a protocolului),

· simulări mari pentru care cerințele I/O de disc pentru generarea fișierelor de urmărire sunt
prohibitiv sau greoi și

· nevoia de on-line reducerea sau calculul datelor, în timpul simulării.
Un bun exemplu în acest sens este definirea unei condiții de terminare pentru simulare, a spune
atunci când să se oprească când a primit suficiente date pentru a forma o încredere suficient de îngustă
interval în jurul estimării unui parametru.

ns-3 cadrul de colectare a datelor este conceput pentru a oferi aceste capabilități suplimentare
dincolo de rezultatul bazat pe urme. Recomandăm cititorului interesat de acest subiect să consulte
il ns-3 Manual pentru o tratare mai detaliată a acestui cadru; aici, rezumam cu
un exemplu de program unele dintre capabilitățile de dezvoltare.

Exemplu Cod
Exemplul tutorialului exemple/tutorial/seventh.cc seamănă cu al şaselea.cc exemplu noi
revizuit anterior, cu excepția câtorva modificări. În primul rând, a fost activat pentru IPv6
suport cu o opțiune de linie de comandă:

CommandLine cmd;
cmd.AddValue ("useIpv6", "Use Ipv6", useV6);
cmd.Parse (argc, argv);

Dacă utilizatorul specifică foloseșteIpv6, programul va fi rulat folosind IPv6 în loc de IPv4.
ajutor opțiune, disponibilă pentru toate ns-3 programe care acceptă obiectul CommandLine ca
prezentat mai sus, poate fi invocat după cum urmează (vă rugăm să rețineți că folosiți ghilimele duble):

./waf --run "seventh --help"

care produce:

ns3-dev-seventh-debug [Argumente de program] [Argumente generale]

Argumente ale programului:
--useIpv6: Folosește Ipv6 [false]

Argumente generale:
--PrintGlobals: Tipăriți lista de globaluri.
--PrintGroups: Tipăriți lista de grupuri.
--PrintGroup=[grup]: Tipăriți toate TypeId-urile grupului.
--PrintTypeIds: Tipăriți toate TypeId-urile.
--PrintAttributes=[typeid]: Imprimă toate atributele typeid.
--PrintHelp: imprimați acest mesaj de ajutor.

Această implicită (utilizarea IPv4, deoarece useIpv6 este fals) poate fi schimbată prin comutarea booleanului
valoare după cum urmează:

./waf --run "seventh --useIpv6=1"

și aruncați o privire la pcap-ul generat, cum ar fi cu tcpdump:

tcpdump -r al șaptelea.pcap -nn -tt

Aceasta a fost o scurtă digresiune în suportul IPv6 și linia de comandă, care a fost, de asemenea
introdus mai devreme în acest tutorial. Pentru un exemplu dedicat de utilizare a liniei de comandă,
te rog vezi src/core/examples/command-line-example.cc.

Acum revenim la colectarea datelor. În exemple/tutorial/ director, tastați următoarele
comanda: dif -u al şaselea.cc al şaptelea.cc, și examinați câteva dintre noile linii ale acestui difer:

+ std::string probeType;
+ std::string tracePath;
+ dacă (useV6 == false)
+ {
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+}
+ altfel
+ {
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+}
...
+ // Folosiți GnuplotHelper pentru a reprezenta numărul de octeți de pachete în timp
+ GnuplotHelper plotHelper;
+
+ // Configurați plotul. Primul argument este prefixul numelui fișierului
+ // pentru fișierele de ieșire generate. Al doilea, al treilea și al patrulea
+ // argumentele sunt, respectiv, titlul diagramei, axa x și etichetele axei y
+ plotHelper.ConfigurePlot ("număr-al șaptelea-pachet-octet",
+ „Număr de octeți de pachete în funcție de timp”,
+ „Timp (secunde)”,
+ „Număr de octeți de pachet”);
+
+ // Specificați tipul sondei, calea sursei de urmărire (în spațiul de nume de configurare) și
+ // Sondați sursa de urmărire a ieșirii ("OutputBytes") pentru a reprezenta un grafic. Al patrulea argument
+ // specifică numele etichetei seriei de date de pe grafic. Ultimul
+ // Argumentul formatează graficul specificând unde trebuie plasată cheia.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ „OutputBytes”,
+ „Număr de octeți de pachet”,
+ GnuplotAggregator::KEY_BELOW);
+
+ // Folosiți FileHelper pentru a scrie numărul de octeți de pachete în timp
+ FileHelper fileHelper;
+
+ // Configurați fișierul care urmează să fie scris și formatarea datelor de ieșire.
+ fileHelper.ConfigureFile ("numărul de octeți de pachete al șaptelea",
+ FileAggregator::FORMATED);
+
+ // Setați etichetele pentru acest fișier de ieșire formatat.
+ fileHelper.Set2dFormat ("Timp (secunde) = %.3e\tNumăr de octeți de pachete = %.0f");
+
+ // Specificați tipul sondei, calea sondei (în spațiul de nume de configurare) și
+ // Sondați sursa de urmărire a ieșirii ("OutputBytes") pentru a scrie.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+
Simulator::Stop (Secunde (20));
Simulator::Run ();
Simulator::Destroy ();

Cititorul atent va fi observat, la testarea atributului liniei de comandă IPv6 de mai sus,
acea al şaptelea.cc a creat o serie de fișiere de ieșire noi:

al șaptelea-pachet-octet-count-0.txt
al șaptelea-pachet-octet-count-1.txt
al șaptelea-pachet-octet-count.dat
al șaptelea-pachet-octet-count.plt
al șaptelea-pachet-byte-count.png
al șaptelea-pachet-octet-count.sh

Acestea au fost create de afirmațiile suplimentare introduse mai sus; în special, de către a
GnuplotHelper și un FileHelper. Aceste date au fost produse prin conectarea culegerii de date
componente pentru ns-3 sursele de urmărire și distribuirea datelor într-un format formatat gnuplot si
într-un fișier text formatat. În secțiunile următoare, vom analiza fiecare dintre acestea.

GnuplotHelper
GnuplotHelper este un ns-3 obiect ajutor care vizează producerea de gnuplot parcele cu
cât mai puține afirmații, pentru cazuri obișnuite. Se agață ns-3 urmărirea surselor cu date
tipuri suportate de sistemul de colectare a datelor. Nu tot ns-3 tipurile de date ale surselor de urmărire sunt
acceptate, dar multe dintre tipurile comune de urmărire sunt, inclusiv TracedValues ​​cu vechi
tipuri de date (POD).

Să ne uităm la rezultatul produs de acest ajutor:

al șaptelea-pachet-octet-count.dat
al șaptelea-pachet-octet-count.plt
al șaptelea-pachet-octet-count.sh

Primul este un fișier de date gnuplot cu o serie de marcaje temporale și pachete delimitate de spațiu
număr de octeți. Vom acoperi mai jos cum a fost configurată această ieșire de date, dar haideți
continuați cu fișierele de ieșire. Fișierul al șaptelea-pachet-octet-count.plt este un complot gnuplot
fișier, care poate fi deschis din gnuplot. Cititorii care înțeleg sintaxa gnuplot pot
vezi că aceasta va produce un fișier PNG de ieșire formatat numit
al șaptelea-pachet-byte-count.png. În sfârșit, un mic script shell
al șaptelea-pachet-octet-count.sh rulează acest fișier de plot prin gnuplot pentru a produce fișierul dorit
PNG (care poate fi vizualizat într-un editor de imagini); adică comanda:

sh numărul-al șaptelea-pachet-octeți.sh

va ceda al șaptelea-pachet-byte-count.png. De ce nu a fost produs acest PNG în primul
loc? Răspunsul este că, furnizând fișierul plt, utilizatorul poate configura manual fișierul
rezultat dacă se dorește, înainte de a produce PNG-ul.

Titlul imaginii PNG afirmă că acest diagramă este un grafic al „Număr de octeți de pachete în funcție de timp” și
că prezintă datele sondate corespunzătoare căii sursei de urmărire:

/NodeList/*/$ns3::Ipv6L3Protocol/Tx

Observați wild-cardul din calea de urmărire. Pe scurt, ceea ce surprinde acest complot este complotul
de octeți de pachet observați la sursa de urmărire de transmisie a obiectului Ipv6L3Protocol;
în mare parte, segmente TCP de 596 de octeți într-o direcție și accesări TCP de 60 de octeți în cealaltă (două
sursele de urmărire a nodului au fost potrivite de această sursă de urmărire).

Cum a fost configurat asta? Trebuie furnizate câteva declarații. În primul rând, GnuplotHelper
obiectul trebuie declarat și configurat:

+ // Folosiți GnuplotHelper pentru a reprezenta numărul de octeți de pachete în timp
+ GnuplotHelper plotHelper;
+
+ // Configurați plotul. Primul argument este prefixul numelui fișierului
+ // pentru fișierele de ieșire generate. Al doilea, al treilea și al patrulea
+ // argumentele sunt, respectiv, titlul diagramei, axa x și etichetele axei y
+ plotHelper.ConfigurePlot ("număr-al șaptelea-pachet-octet",
+ „Număr de octeți de pachete în funcție de timp”,
+ „Timp (secunde)”,
+ „Număr de octeți de pachet”);

Până în acest moment, a fost configurată o parcelă goală. Prefixul numelui de fișier este primul
argument, titlul complotului este al doilea, eticheta axei x a treia și eticheta axei y
al patrulea argument.

Următorul pas este configurarea datelor și aici este conectată sursa de urmărire.
Mai întâi, rețineți că mai sus în program am declarat câteva variabile pentru utilizare ulterioară:

+ std::string probeType;
+ std::string tracePath;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";

Le folosim aici:

+ // Specificați tipul sondei, calea sursei de urmărire (în spațiul de nume de configurare) și
+ // Sondați sursa de urmărire a ieșirii ("OutputBytes") pentru a reprezenta un grafic. Al patrulea argument
+ // specifică numele etichetei seriei de date de pe grafic. Ultimul
+ // Argumentul formatează graficul specificând unde trebuie plasată cheia.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ „OutputBytes”,
+ „Număr de octeți de pachet”,
+ GnuplotAggregator::KEY_BELOW);

Primele două argumente sunt numele tipului sondei și calea sursei de urmărire. Aceste
două sunt probabil cele mai greu de determinat atunci când încercați să utilizați acest cadru pentru a reprezenta un altul
urme. Urma sondei aici este Tx urme sursa clasei Ipv6L3Protocol. Cand noi
examinați implementarea acestei clase (src/internet/model/ipv6-l3-protocol.cc) putem observa:

.AddTraceSource ("Tx", "Trimite pachet IPv6 la interfața de ieșire.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))

Aceasta spune că Tx este un nume pentru variabilă m_txTrace, care are o declarație de:

/ **
* \brief Callback pentru a urmări pachetele TX (transmisie).
*/
TracedCallback , Ptr , uint6_t> m_txTrace;

Se pare că această semnătură specifică sursă de urmărire este suportată de o clasă Probe (ce
avem nevoie aici) din clasa Ipv6PacketProbe. Vedeți fișierele
src/internet/model/ipv6-packet-probe.{h,cc}.

Deci, în instrucțiunea PlotProbe de mai sus, vedem că instrucțiunea agăță urma
sursă (identificată prin șirul de cale) cu o potrivire ns-3 Tip sondă de Ipv6PacketProbe. Dacă
nu am acceptat acest tip de sondă (se potrivește semnătura sursei de urmărire), nu am fi putut
a folosit această declarație (deși unele declarații de nivel inferior mai complicate ar fi putut fi
utilizat, așa cum este descris în manual).

Ipv6PacketProbe exportă, în sine, unele surse de urmărire care extrag datele din
obiect pachet sondat:

TypeId
Ipv6PacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent ()
.AddConstructor ()
.AddTraceSource ("Ieșire",
„Pachetul plus obiectul său IPv6 și interfața care servesc ca ieșire pentru această sondă”,
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource ("OutputBytes",
„Numărul de octeți din pachet”,
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
;
return tid;
}

Al treilea argument al declarației noastre PlotProbe specifică faptul că suntem interesați de
numărul de octeți din acest pachet; în special, sursa de urmărire „OutputBytes” a
Ipv6PacketProbe. În cele din urmă, ultimele două argumente ale enunțului furnizează legenda complotului
pentru această serie de date ("Packet Byte Count") și o instrucțiune opțională de formatare gnuplot
(GnuplotAggregator::KEY_BELOW) că vrem ca cheia de plot să fie inserată sub plot.
Alte opțiuni includ NO_KEY, KEY_INSIDE și KEY_ABOVE.

Suportat Urmă Tipuri de
Următoarele valori urmărite sunt acceptate cu Sondele de la această scriere:

┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┐
│Tipul TracedValue │ Tipul sondei │ Fișier │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│duble │ DoubleProbe │ statistici/model/duble-probe.h │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│uint8_t │ Uinteger8Probe │ statistici/model/uinteger-8-probe.h │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│uint16_t │ Uinteger16Probe │ statistici/model/uinteger-16-probe.h │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│uint32_t │ Uinteger32Probe │ statistici/model/uinteger-32-probe.h │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│bool │ BooleanProbe │ statistics/model/uinteger-16-probe.h │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┤
│ns3::Time │ TimeProbe │ statistici/model/time-probe.h │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────────────┘

Următoarele tipuri de TraceSource sunt acceptate de Probes de la data scrierii acestui articol:

┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┬───────────────────────────────────── ──────────┐
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┼───────────────────────────────────── ──────────┤
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┼───────────────────────────────────── ──────────┤
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┼───────────────────────────────────── ──────────┤
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┼───────────────────────────────────── ──────────┤
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┼───────────────────────────────────── ──────────┤
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────- ────────────┴───────────────────────────────────── ──────────┘

După cum se poate observa, doar câteva surse de urme sunt acceptate și toate sunt orientate către
ieșirea dimensiunii pachetului (în octeți). Cu toate acestea, majoritatea tipurilor de date fundamentale
disponibile ca TracedValues ​​poate fi suportat cu acești ajutoare.

FileHelper
Clasa FileHelper este doar o variație a exemplului anterior GnuplotHelper. The
programul de exemplu oferă rezultate formatate ale acelorași date marcate de timp, după cum urmează:

Timp (secunde) = 9.312e+00 Număr de octeți de pachete = 596
Timp (secunde) = 9.312e+00 Număr de octeți de pachete = 564

Sunt furnizate două fișiere, unul pentru nodul „0” și unul pentru nodul „1”, așa cum se poate vedea în
nume de fișiere. Să ne uităm la cod bucată cu bucată:

+ // Folosiți FileHelper pentru a scrie numărul de octeți de pachete în timp
+ FileHelper fileHelper;
+
+ // Configurați fișierul care urmează să fie scris și formatarea datelor de ieșire.
+ fileHelper.ConfigureFile ("numărul de octeți de pachete al șaptelea",
+ FileAggregator::FORMATED);

Prefixul fișierului helper este primul argument, iar un specificator de format este următorul. niste
alte opțiuni pentru formatare includ SPACE_SEPARATED, COMMA_SEPARATED și TAB_SEPARATED.
Utilizatorii pot schimba formatarea (dacă este specificat FORMATTED) cu un șir de format
cum urmează:

+
+ // Setați etichetele pentru acest fișier de ieșire formatat.
+ fileHelper.Set2dFormat ("Timp (secunde) = %.3e\tNumăr de octeți de pachete = %.0f");

În cele din urmă, urmele sursei de interes trebuie să fie agățată. Din nou, probeType și tracePath
sunt utilizate variabilele din acest exemplu, iar sursa de urmărire a sondei este „OutputBytes”.
coroiat:

+
+ // Specificați tipul sondei, calea sursei de urmărire (în spațiul de nume de configurare) și
+ // Sondați sursa de urmărire a ieșirii ("OutputBytes") pentru a scrie.
+ fileHelper.WriteProbe (probeType,
+ tracePath,
+ "OutputBytes");
+

Câmpurile wildcard din acest specificator de sursă de urmărire se potrivesc cu două surse de urmărire. spre deosebire de
Exemplu GnuplotHelper, în care două serii de date au fost suprapuse pe același diagramă, aici, două
fișiere separate sunt scrise pe disc.

Rezumat
Suportul pentru colectarea datelor este nou începând cu ns-3.18 și suport de bază pentru furnizarea de serii cronologice
ieșirea a fost adăugată. Modelul de bază descris mai sus poate fi replicat în cadrul
domeniul de aplicare al sondelor existente și al surselor de urmărire. Mai multe capabilități, inclusiv
procesarea statisticilor va fi adăugată în versiunile viitoare.

CONCLUZIE


Futures
Acest document este conceput ca un document viu. Sperăm și ne așteptăm să crească în timp
pentru a acoperi din ce în ce mai multe din piulițele și șuruburile de ns-3.

Scrierea manualelor și a capitolelor tutoriale nu este ceva de care suntem entuziasmați cu toții, dar este
foarte important pentru proiect. Dacă sunteți expert în unul dintre aceste domenii, vă rugăm
ia în considerare contribuția la ns-3 prin furnizarea unuia dintre aceste capitole; sau orice alt capitol tu
poate crede că este important.

Închidere
ns-3 este un sistem mare și complicat. Este imposibil să acoperiți toate lucrurile pe care le aveți
va trebui să știți într-un mic tutorial. Cititorii care doresc să afle mai multe sunt încurajați să o facă
citiți următoarea documentație suplimentară:

· ns-3 manual

· ns-3 documentația bibliotecii de modele

· ns-3 Doxygen (documentația API)

· ns-3 Wiki

-- Cel ns-3 echipă de dezvoltare.

Utilizați ns-3-tutorial online folosind serviciile onworks.net



Cele mai recente programe online Linux și Windows