EnglishFranceseSpagnolo

Favicon di OnWorks

ns-3-tutorial - Online nel cloud

Esegui ns-3-tutorial nel provider di hosting gratuito OnWorks su Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

Questo è il comando ns-3-tutorial che può essere eseguito nel provider di hosting gratuito OnWorks utilizzando una delle nostre molteplici workstation online gratuite come Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

PROGRAMMA:

NOME


Tutorial-ns-3 - Tutorial ns-3

Questa è la NS-3 Esercitazione. La documentazione principale per il progetto ns-3 è disponibile in cinque
le forme:

· NS-3 Doxygen: Documentazione delle API pubbliche del simulatore

· Esercitazione (Questo documento), Manuale e Libreria di modelli per il con i più recenti rilasciare che a
sviluppo albero

· NS-3 wiki

Questo documento è scritto in testoristrutturato per Sfinge ed è mantenuto nel
documento/tutorial directory del codice sorgente di ns-3.

INTRODUZIONE


Le NS-3 simulator è un simulatore di rete a eventi discreti destinato principalmente alla ricerca
e uso didattico. Il NS-3 progetto, iniziato nel 2006, è un progetto open-source
in via di sviluppo NS-3.

Lo scopo di questo tutorial è introdurre nuove NS-3 utenti al sistema in modo strutturato
modo. A volte è difficile per i nuovi utenti raccogliere informazioni essenziali dai dettagli
manuali e per convertire queste informazioni in simulazioni di lavoro. In questo tutorial, noi
costruirà diverse simulazioni di esempio, introducendo e spiegando concetti chiave e
caratteristiche mentre andiamo.

Man mano che il tutorial si sviluppa, introdurremo il completo NS-3 documentazione e fornire
puntatori al codice sorgente per chi è interessato ad approfondire il funzionamento del
.

Vale la pena notare alcuni punti chiave all'inizio:

· NS-3 è open-source e il progetto si sforza di mantenere un ambiente aperto per
ricercatori a contribuire e condividere il loro software.

· NS-3 non è un'estensione retrocompatibile di NS-2; è un nuovo simulatore. Il due
i simulatori sono entrambi scritti in C++ ma NS-3 è un nuovo simulatore che non supporta il
NS-2 API. Alcuni modelli da NS-2 sono già stati trasferiti da NS-2 a NS-3.
progetto continuerà a mantenere NS-2 while NS-3 è in costruzione e studierà
meccanismi di transizione e integrazione.

About NS-3
NS-3 è stato sviluppato per fornire una piattaforma di simulazione di rete aperta ed estensibile, per
ricerca e formazione in rete. In breve, NS-3 fornisce modelli di come i dati a pacchetto
le reti funzionano e funzionano e fornisce un motore di simulazione che gli utenti possono condurre
esperimenti di simulazione. Alcuni dei motivi per usarlo NS-3 includere per eseguire studi che
sono più difficili o impossibili da eseguire con sistemi reali, per studiare il comportamento del sistema
in un ambiente altamente controllato e riproducibile e per apprendere come funzionano le reti.
Gli utenti noteranno che il modello disponibile è impostato in NS-3 si concentra sulla modellazione di come Internet
i protocolli e le reti funzionano, ma NS-3 non è limitato ai sistemi Internet; diversi utenti
stiamo usando NS-3 modellare sistemi non basati su Internet.

Esistono molti strumenti di simulazione per gli studi di simulazione di rete. Di seguito sono riportati alcuni
caratteristiche distintive di NS-3 a differenza di altri strumenti.

· NS-3 è concepito come un insieme di librerie che possono essere combinate tra loro e anche con altre
librerie software esterne. Mentre alcune piattaforme di simulazione forniscono agli utenti un
ambiente di interfaccia utente grafica unica e integrata in cui vengono svolte tutte le attività
out, NS-3 è più modulare in questo senso. Diversi animatori esterni e analisi dei dati
e gli strumenti di visualizzazione possono essere utilizzati con NS-3. Tuttavia, gli utenti dovrebbero aspettarsi di lavorare a
la riga di comando e con strumenti di sviluppo software C++ e/o Python.

· NS-3 è utilizzato principalmente su sistemi Linux, sebbene esista il supporto per FreeBSD, Cygwin
(per Windows) e il supporto nativo di Windows Visual Studio è in procinto di essere
sviluppato.

· NS-3 non è un prodotto software ufficialmente supportato da nessuna azienda. Supporto per NS-3
viene eseguito al meglio sulla mailing list ns-3-users.

Per NS-2 Utenti
Per chi ha familiarità con NS-2 (uno strumento popolare che ha preceduto NS-3), il più visibile verso l'esterno
cambiare quando si passa a NS-3 è la scelta del linguaggio di scripting. Programmi in NS-2 sono
script in OTcl e i risultati delle simulazioni possono essere visualizzati utilizzando Network Animator
nome. Non è possibile eseguire una simulazione in NS-2 puramente da C++ (cioè come main()
programma senza alcun OTcl). Inoltre, alcuni componenti di NS-2 sono scritti in C++ e
altri in OTcl. In NS-3, il simulatore è scritto interamente in C++, con Python opzionale
legature. Gli script di simulazione possono quindi essere scritti in C++ o in Python. Nuovi animatori
e visualizzatori sono disponibili e in fase di sviluppo. Da quando NS-3 genera pcap
file di traccia dei pacchetti, è possibile utilizzare anche altre utilità per analizzare le tracce. In questo
tutorial, ci concentreremo prima sullo scripting direttamente in C++ e sull'interpretazione dei risultati
tramite file di traccia.

Ma ci sono anche somiglianze (entrambi, ad esempio, sono basati su oggetti C++ e alcuni
codice da NS-2 è già stato portato a NS-3). Cercheremo di evidenziare le differenze
fra NS-2 che a NS-3 mentre procediamo in questo tutorial.

Una domanda che sentiamo spesso è "Devo ancora usare? NS-2 o spostati in NS-3?" In questo
l'opinione dell'autore, a meno che l'utente non sia in qualche modo investito NS-2 (sia basato sull'esistente
comfort personale e conoscenza di NS-2, o sulla base di uno specifico modello di simulazione che
è disponibile solo in NS-2), un utente sarà più produttivo con NS-3 per i seguenti
motivi:

· NS-3 è attivamente mantenuto con una mailing list di utenti attivi e reattivi, mentre NS-2 is
solo leggermente mantenuto e non ha visto uno sviluppo significativo nel suo albero di codice principale
per oltre un decennio.

· NS-3 fornisce funzionalità non disponibili in NS-2, come l'esecuzione di un codice di implementazione
ambiente (consentendo agli utenti di eseguire codice di implementazione reale nel simulatore)

· NS-3 fornisce un livello base di astrazione inferiore rispetto a NS-2, permettendogli di allinearsi
meglio con il modo in cui i sistemi reali sono messi insieme. Alcune limitazioni trovate in NS-2 (Quali
supportare correttamente più tipi di interfacce sui nodi) sono state risolte in NS-3.

NS-2 ha un insieme più diversificato di moduli forniti rispetto a quello che ha NS-3, a causa della sua lunga
storia. Però, NS-3 ha modelli più dettagliati in diverse aree di ricerca popolari
(compresi i modelli LTE e WiFi sofisticati) e il relativo supporto del codice di implementazione
ammette uno spettro molto ampio di modelli ad alta fedeltà. Gli utenti potrebbero essere sorpresi di apprendere che
l'intero stack di rete Linux può essere incapsulato in un NS-3 nodo, utilizzando Direct
Quadro di esecuzione del codice (DCE). NS-2 a volte i modelli possono essere portati su NS-3, soprattutto
se sono stati implementati in C++.

In caso di dubbio, una buona linea guida sarebbe quella di guardare entrambi i simulatori (così come altri
simulatori), e in particolare i modelli disponibili per la tua ricerca, ma tieni presente
che la tua esperienza possa essere migliore nell'uso dello strumento che viene attivamente sviluppato e
mantenuto (NS-3).

Contribuire
NS-3 è un simulatore didattico e di ricerca, da e per la comunità di ricerca. Lo farà
fare affidamento sui continui contributi della comunità per sviluppare nuovi modelli, eseguire il debug o
mantenere quelli esistenti e condividere i risultati. Ci sono alcune politiche che speriamo lo facciano
incoraggiare le persone a contribuire a NS-3 come hanno per NS-2:

· Licenza open source basata sulla compatibilità GNU GPLv2

· wiki

· Contributo Code pagina, simile a NS-2il popolare codice contributo di pagina

· Aperto insetto Tracker

Ci rendiamo conto che se stai leggendo questo documento, contribuire al progetto è
probabilmente non è la tua principale preoccupazione a questo punto, ma vogliamo che tu sappia che
contribuire è nello spirito del progetto e anche l'atto di lasciarci una nota
sulla tua prima esperienza con NS-3 (ad esempio "questa sezione del tutorial non era chiara..."),
segnalazioni di documentazione obsoleta, ecc. sono molto apprezzate.

Esercitazione Organizzazione
Il tutorial presuppone che i nuovi utenti possano inizialmente seguire un percorso come il seguente:

· Prova a scaricare e creare una copia;

· Prova a eseguire alcuni programmi di esempio;

· Guarda l'output della simulazione e prova a regolarlo.

Di conseguenza, abbiamo cercato di organizzare il tutorial lungo le suddette ampie sequenze di
eventi.

RISORSE


Le Web
Ci sono diverse risorse importanti di cui nessuna NS-3 l'utente deve essere consapevole. Il web principale
il sito si trova su http://www.nsnam.org e fornisce l'accesso alle informazioni di base sul
NS-3 sistema. La documentazione dettagliata è disponibile tramite il sito Web principale all'indirizzo
http://www.nsnam.org/documentation/. È inoltre possibile trovare documenti relativi al sistema
architettura da questa pagina.

C'è un Wiki che completa il principale NS-3 sito web che troverai su
http://www.nsnam.org/wiki/. Lì troverai le domande frequenti per utenti e sviluppatori, oltre a
guide alla risoluzione dei problemi, codice fornito da terze parti, documenti, ecc.

Il codice sorgente può essere trovato e sfogliato su http://code.nsnam.org/. Lì troverai
l'albero di sviluppo corrente nel repository denominato ns-3-dev. Rilasci passati e
si possono trovare anche repository sperimentali degli sviluppatori principali.

mutevole
I sistemi software complessi hanno bisogno di un modo per gestire l'organizzazione e le modifiche al
codice e documentazione sottostante. Ci sono molti modi per eseguire questa impresa e potresti
ho sentito parlare di alcuni dei sistemi attualmente utilizzati per farlo. Il Concorrente
Version System (CVS) è probabilmente il più noto.

Le NS-3 project utilizza Mercurial come sistema di gestione del codice sorgente. Anche se non lo fai
devi sapere molto su Mercurial per completare questo tutorial, ti consigliamo
familiarizzare con Mercurial e usarlo per accedere al codice sorgente. Mercurial ha un
sito web a http://www.selenic.com/mercurial/, da cui puoi ottenere binario o sorgente
versioni di questo sistema di gestione della configurazione del software (SCM). Selenic (lo sviluppatore
di Mercurial) fornisce anche un tutorial su
http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/e una guida QuickStart su
http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/.

Puoi anche trovare informazioni vitali sull'utilizzo di Mercurial e NS-3 sul principale NS-3 sito web
sito.

Waf
Una volta scaricato il codice sorgente sul sistema locale, dovrai compilarlo
sorgente per produrre programmi utilizzabili. Proprio come nel caso della gestione del codice sorgente, ci
sono molti gli strumenti disponibili per svolgere questa funzione. Probabilmente il più noto di questi
gli strumenti sono make. Oltre ad essere il più noto, make è probabilmente il più difficile
da utilizzare in un sistema molto grande e altamente configurabile. Per questo motivo, molte alternative
sono stati sviluppati. Recentemente questi sistemi sono stati sviluppati utilizzando Python
Lingua.

Il sistema di build Waf viene utilizzato sul NS-3 progetto. È uno della nuova generazione di
Sistemi di compilazione basati su Python. Non avrai bisogno di capire nessun Python per costruire il
esistente NS-3 .

Per coloro interessati ai dettagli cruenti di Waf, il sito Web principale può essere trovato all'indirizzo
http://code.google.com/p/waf/.

Mercato Ambiente
Come accennato in precedenza, lo scripting in NS-3 è fatto in C++ o Python. La maggior parte della NS-3 L'API è
disponibile in Python, ma i modelli sono scritti in C++ in entrambi i casi. un lavoro
In questo documento si presuppone la conoscenza del C++ e dei concetti orientati agli oggetti. noi prenderemo
un po' di tempo per rivedere alcuni dei concetti più avanzati o un linguaggio forse sconosciuto
caratteristiche, modi di dire e modelli di design così come appaiono. Non vogliamo che questo tutorial
trasformarsi in un tutorial C++, quindi ci aspettiamo un comando di base del linguaggio.
C'è un numero quasi inimmaginabile di fonti di informazione sul C++ disponibile sul
web o cartaceo.

Se non conosci il C++, potresti voler trovare un tutorial o un libro di cucina o un sito web
ed esamina almeno le caratteristiche di base della lingua prima di procedere. Per
esempio, questo lezione.

Le NS-3 Il sistema utilizza diversi componenti della "toolchain" GNU per lo sviluppo. UN
la toolchain software è l'insieme degli strumenti di programmazione disponibili in un dato ambiente. Per
una rapida rassegna di ciò che è incluso nella toolchain GNU vedere,
http://en.wikipedia.org/wiki/GNU_toolchain. NS-3 usa gcc, GNU binutils e gdb.
Tuttavia, non usiamo gli strumenti del sistema di compilazione GNU, né make né autotools. Usiamo Waf
per queste funzioni.

Tipicamente an NS-3 autore lavorerà in Linux o in un ambiente simile a Linux. Per quelli
in esecuzione sotto Windows, esistono ambienti che simulano l'ambiente Linux per
vari gradi. Il NS-3 progetto ha in passato (ma non attualmente) supportato
sviluppo nell'ambiente Cygwin per questi utenti. Vedere http://www.cygwin.com/ per
dettagli sul download e visitare il NS-3 wiki per ulteriori informazioni su Cygwin e
NS-3. MinGW non è attualmente ufficialmente supportato. Un'altra alternativa a Cygwin è quella di
installa un ambiente di macchina virtuale come il server VMware e installa un virtuale Linux
macchina.

presa di corrente Programmazione
Assumeremo una struttura di base con l'API Berkeley Sockets negli esempi utilizzati in questo
tutorial. Se non conosci i socket, ti consigliamo di rivedere l'API e alcuni usi comuni
casi. Per una buona panoramica della programmazione dei socket TCP/IP consigliamo TCP / IP Prese in
C, Donahoo che a Calvert.

C'è un sito web associato che include la fonte per gli esempi nel libro, che
puoi trovare su: http://cs.baylor.edu/~donahoo/practical/CSockets/.

Se capisci i primi quattro capitoli del libro (o per chi non ha accesso
a una copia del libro, i client e i server echo mostrati nel sito Web sopra) lo farai
essere in buona forma per capire il tutorial. C'è un libro simile su Multicast
Prese, Multicast Prese, Makofske che a Almeroth. che copre il materiale di cui potresti aver bisogno
capisci se guardi gli esempi multicast nella distribuzione.

COME INIZIATA


Questa sezione ha lo scopo di portare un utente a uno stato funzionante a partire da una macchina che
potrebbe non aver mai avuto NS-3 installato. Copre piattaforme supportate, prerequisiti, modi per
ottenere NS-3, modi per costruire NS-3e modi per verificare la compilazione ed eseguire programmi semplici.

Panoramica
NS-3 è costruito come un sistema di librerie software che lavorano insieme. I programmi utente possono essere
scritto che collega (o importa da) queste librerie. I programmi utente sono scritti in
i linguaggi di programmazione C++ o Python.

NS-3 è distribuito come codice sorgente, il che significa che il sistema di destinazione deve avere un
ambiente di sviluppo software per creare prima le librerie, quindi creare l'utente
. NS-3 potrebbe in linea di principio essere distribuito come librerie predefinite per selezionati
sistemi, e in futuro potrebbe essere distribuito in questo modo, ma al momento molti utenti
in realtà fanno il loro lavoro modificando NS-3 stesso, quindi avere il codice sorgente in giro da ricostruire
le biblioteche sono utili. Se qualcuno volesse intraprendere il lavoro di fare pre-costruito
librerie e pacchetti per sistemi operativi, contattare la mailing di ns-developers
elenco.

Di seguito, esamineremo due modi per scaricare e creare NS-3. Il primo è
per scaricare e creare una versione ufficiale dal sito Web principale. Il secondo è andare a prendere
e creare copie di sviluppo di NS-3. Esamineremo entrambi gli esempi poiché gli strumenti
coinvolti sono leggermente diversi.

Download NS-3
Le NS-3 sistema nel suo complesso è un sistema abbastanza complesso e ha un numero di dipendenze da
altri componenti. Insieme ai sistemi con cui molto probabilmente avrai a che fare ogni giorno (il
GNU toolchain, Mercurial, un editor di testo) dovrai assicurarti che un certo numero di
librerie aggiuntive sono presenti sul sistema prima di procedere. NS-3 fornisce un wiki
pagina che include pagine con molti suggerimenti e suggerimenti utili. Una di queste pagine è la
pagina "Installazione", http://www.nsnam.org/wiki/Installation.

La sezione "Prerequisiti" di questa pagina wiki spiega quali pacchetti sono richiesti per
supporto comune NS-3 opzioni e fornisce anche i comandi utilizzati per installarli per
varianti comuni di Linux. Gli utenti di Cygwin dovranno utilizzare il programma di installazione di Cygwin (se sei un
utente Cygwin, l'hai usato per installare Cygwin).

Si consiglia di cogliere l'occasione per esplorare il NS-3 wiki un po' visto che c'è davvero
una ricchezza di informazioni lì.

Da questo punto in avanti, assumeremo che il lettore stia lavorando in Linux o in un
Ambiente di emulazione Linux (Linux, Cygwin, ecc.) e ha installato la toolchain GNU e
verificata insieme ai prerequisiti di cui sopra. Supponiamo anche che
hai Mercurial e Waf installati e in esecuzione sul sistema di destinazione.

Le NS-3 il codice è disponibile nei repository Mercurial sul server http://code.nsnam.org.
Puoi anche scaricare una versione tarball su http://www.nsnam.org/release/, oppure puoi lavorare
con i repository che utilizzano Mercurial. Raccomandiamo di usare Mercurial a meno che non ci sia una buona
motivo per non farlo. Vedere la fine di questa sezione per istruzioni su come ottenere un tarball
rilasciare.

Il modo più semplice per iniziare a usare i repository Mercurial è usare il ns-3-allineone
ambiente. Questo è un insieme di script che gestisce il download e la creazione di
vari sottosistemi di NS-3 per te. Ti consigliamo di iniziare il tuo NS-3 lavorare in questo
ambiente.

Una pratica è creare una directory chiamata spazio di lavoro nella propria home directory sotto la quale
si possono mantenere repository Mercurial locali. Qualsiasi nome di directory andrà bene, ma assumeremo
che spazio di lavoro è qui utilizzato (nota: pronti contro termine può essere utilizzato anche in alcuni documenti come
nome della directory di esempio).

Download NS-3 utilizzando a tarball
Un tarball è un particolare formato di archivio software in cui sono raggruppati più file
insieme e l'archivio possibilmente compresso. NS-3 le versioni del software sono fornite tramite a
tarball scaricabile. Il processo per il download NS-3 tramite tarball è semplice; hai appena
devi scegliere una versione, scaricarla e decomprimerla.

Supponiamo che tu, come utente, desideri costruire NS-3 in una directory locale chiamata
spazio di lavoro. Se adotti il spazio di lavoro approccio alla directory, puoi ottenere una copia di una versione
digitando quanto segue nella shell di Linux (sostituisci i numeri di versione appropriati,
Certo):

$ cd
$ mkdir area di lavoro
$ cd area di lavoro
$wget http://www.nsnam.org/release/ns-allinone-3.22.tar.bz2
$ tar xjf ns-allinone-3.22.tar.bz2

Se entri nella directory ns-allinene-3.22 dovresti vedere una serie di file:

$ l
cuocere costanti.py ns-3.22 LEGGIMI
build.py netanim-3.105 pybindgen-0.16.0.886 util.py

Ora sei pronto per costruire la base NS-3 distribuzione.

Download NS-3 utilizzando Infornare
Bake è uno strumento per l'integrazione e la costruzione distribuita, sviluppato per il NS-3 progetto.
Bake può essere utilizzato per recuperare le versioni di sviluppo del NS-3 software e per scaricare e
costruire estensioni alla base NS-3 distribuzione, come l'esecuzione diretta del codice
ambiente, Network Simulation Cradle, possibilità di creare nuovi collegamenti Python e altri.

Recentemente NS-3 versioni, Bake è stato incluso nel tarball delle versioni. La configurazione
file incluso nella versione rilasciata consentirà di scaricare qualsiasi software che era
corrente al momento del rilascio. Cioè, ad esempio, la versione di Bake che è
distribuito con il NS-3.21 rilascio può essere utilizzato per recuperare i componenti per questo NS-3 rilasciare
o precedente, ma non può essere utilizzato per recuperare i componenti per le versioni successive (a meno che il
bakeconf.xml il file è aggiornato).

Puoi anche ottenere la copia più recente di infornare digitando quanto segue nel tuo Linux
shell (supponendo che tu abbia installato Mercurial):

$ cd
$ mkdir area di lavoro
$ cd area di lavoro
$ hg clone http://code.nsnam.org/bake

Durante l'esecuzione del comando hg (Mercurial), dovresti vedere qualcosa di simile al seguente
visualizzato,

...
directory di destinazione: cuocere
chiedendo tutte le modifiche
aggiunta di modifiche
aggiunta di manifest
aggiunta di modifiche ai file
aggiunti 339 changeset con 796 modifiche a 63 file
aggiornamento all'impostazione predefinita del ramo
45 file aggiornati, 0 file uniti, 0 file rimossi, 0 file non risolti

Al termine del comando clone, dovresti avere una directory chiamata infornare, i contenuti
dei quali dovrebbe essere simile al seguente:

$ l
cuocere bakeconf.xml doc generate-binary.py TODO
Bake.py esempi di test

Nota che hai appena scaricato alcuni script Python e un modulo Python chiamato
infornare. Il prossimo passo sarà usare quegli script per scaricare e costruire il NS-3
distribuzione a tua scelta.

Sono disponibili alcuni target di configurazione:

1. NS-3.22: il modulo corrispondente allo sblocco; scaricherà componenti simili
al tarball di rilascio.

2. ns-3-dev: un modulo simile ma utilizzando l'albero del codice di sviluppo

3. ns-allinene-3.22: il modulo che include altre funzionalità opzionali come il clic
routing, openflow per NS-3e il supporto per la simulazione di rete

4. ns-3-allineone: simile alla versione rilasciata del modulo allinone, ma per
codice di sviluppo.

L'istantanea dello sviluppo attuale (inedito) di NS-3 può essere trovato su
http://code.nsnam.org/ns-3-dev/. Gli sviluppatori tentano di mantenere questi repository in
stati coerenti e funzionanti ma sono in un'area di sviluppo con codice non rilasciato
presente, quindi potresti prendere in considerazione la possibilità di rimanere con una versione ufficiale se non ne hai bisogno
funzionalità di nuova introduzione.

Puoi trovare l'ultima versione del codice controllando l'elenco dei repository
o andando al "ns-3 Rilasci" pagina Web e facendo clic sul collegamento dell'ultima versione.
Procederemo in questo esempio di tutorial con NS-3.22.

Ora useremo lo strumento di cottura per abbattere i vari pezzi di NS-3 sarai
usando. Per prima cosa, diremo una parola sull'esecuzione di Bake.

bake funziona scaricando i pacchetti sorgente in una directory sorgente e installando
librerie in una directory di compilazione. bake può essere eseguito facendo riferimento al binario, ma se uno
sceglie di eseguire bake dall'esterno della directory in cui è stato scaricato, è consigliabile
per inserire bake nel tuo percorso, come segue (esempio di shell bash di Linux). Per prima cosa, cambia
nella directory 'bake', quindi imposta le seguenti variabili di ambiente

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

Questo metterà il programma bake.py nel percorso della shell e consentirà ad altri programmi di
trova eseguibili e librerie create da bake. Sebbene molti casi d'uso di cottura non lo facciano
richiedono l'impostazione di PATH e PYTHONPATH come sopra, build complete di ns-3-allinone (con il
pacchetti opzionali) in genere lo fanno.

Entra nella directory dell'area di lavoro e digita quanto segue nella tua shell:

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

Successivamente, chiederemo a Bake di verificare se disponiamo di strumenti sufficienti per scaricare vari componenti.
Tipo:

$ ./bake.py assegno

Dovresti vedere qualcosa come il seguente,

> Python - OK
> Compilatore GNU C++ - OK
> Mercuriale - OK
> CVS - OK
> GIT - OK
> Bazar - OK
> Strumento catrame - OK
> Strumento di decompressione - OK
> Strumento Unrar - manca
> Utilità di compressione dati 7z - OK
> Utilità di compressione dati XZ - OK
> Crea - OK
> cMake - OK
> strumento patch - OK
> strumento di conferma automatica - OK

> Percorso cercato per gli strumenti: /usr/lib64/qt-3.3/bin /usr/lib64/ccache
/ Usr / local / bin /bidone / Usr / bin / usr / local / sbin / usr / sbin / sbin
/home/tom/bin bin

In particolare, i nostri principali strumenti di download come Mercurial, CVS, GIT e Bazaar
preoccupazioni a questo punto, poiché ci consentono di recuperare il codice. Si prega di installare mancante
strumenti in questa fase, nel modo consueto per il tuo sistema (se sei in grado di farlo), o contatta
l'amministratore di sistema in base alle esigenze per installare questi strumenti.

Quindi, prova a scaricare il software:

$ ./bake.py scarica

dovrebbe produrre qualcosa come:

>> Ricerca della dipendenza dal sistema pygoocanvas - OK
>> Ricerca della dipendenza del sistema python-dev - OK
>> Ricerca della dipendenza del sistema pygraphviz - OK
>> Download pybindgen-0.16.0.886 - OK
>> Ricerca della dipendenza del sistema g++ - OK
>> Ricerca della dipendenza del sistema qt4 - OK
>> Download di netanim-3.105 - OK
>> Download ns-3.22 - OK

Quanto sopra suggerisce che sono state scaricate tre fonti. Controlla il source elenco
ora e digita ls; si dovrebbe vedere:

$ l
netanim-3.105 ns-3.22 pybindgen-0.16.0.886

Ora sei pronto per costruire il NS-3 distribuzione.

Costruzione NS-3
Costruzione con build.py
Quando si lavora da un tarball rilasciato, la prima volta che si compila il NS-3 progetto che puoi
costruire utilizzando un comodo programma che si trova in tutto in uno directory. Questo programma si chiama
build.py. Questo programma otterrà il progetto configurato per te nel modo più comune
modo utile. Tuttavia, tieni presente che la configurazione più avanzata e il lavoro con NS-3 andrete a
tipicamente implicano l'uso del nativo NS-3 sistema di build, Waf, che verrà introdotto più avanti in questo
tutorial.

Se hai scaricato usando un tarball dovresti avere una directory chiamata qualcosa del genere
ns-allinene-3.22 sotto la vostra ~/spazio di lavoro directory. Digita quanto segue:

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

Perché stiamo lavorando con esempi e test in questo tutorial e perché non lo sono
costruito di default in NS-3, gli argomenti per build.py gli dicono di compilarli per noi. Il
il programma si imposta anche per impostazione predefinita sulla creazione di tutti i moduli disponibili. Più tardi, puoi costruire NS-3
senza esempi e prove, o eliminare i moduli che non sono necessari per il tuo lavoro,
se desideri.

Vedrai molti messaggi tipici di output del compilatore visualizzati durante la compilazione dello script di compilazione
i vari pezzi che hai scaricato. Alla fine dovresti vedere quanto segue:

Waf: lasciare la directory `/path/to/workspace/ns-allinone-3.22/ns-3.22/build'
'build' è terminato con successo (6m25.032s)

Moduli realizzati:
applicazioni aodv dell'antenna
bridge edifici config-store
core csma layout csma
dsdv dsr energia
fd-net-device monitor di flusso internet
rete lr-wpan lte
mobilità mpi netanim (no Python)
rete nix-vector-routing olsr
propagazione del layout punto-punto punto-punto
statistiche dello spettro sixlowpan
tap-bridge test (no Python) lettura della topologia
uan onda dispositivo di rete virtuale
Wi-Fi wimax

Moduli non costruiti (vedi tutorial ns-3 per spiegazioni):
brite clic openflow
Visualizzatore

Uscita dalla directory `./ns-3.22'

Per quanto riguarda la parte relativa ai moduli non realizzati:

Moduli non costruiti (vedi tutorial ns-3 per spiegazioni):
brite clic openflow
Visualizzatore

Questo significa solo che alcuni NS-3 i moduli che hanno dipendenze da librerie esterne potrebbero non farlo
sono stati costruiti, o che la configurazione ha richiesto specificamente di non compilarli. lo fa
non significa che il simulatore non sia stato compilato correttamente o che fornirà errori
risultati per i moduli elencati come in costruzione.

Costruzione con infornare
Se hai usato bake sopra per recuperare il codice sorgente dai repository del progetto, puoi continuare a farlo
usalo per costruire NS-3. genere

$ ./bake.py build

e dovresti vedere qualcosa come:

>> Costruzione pybindgen-0.16.0.886 - OK
>> Costruzione netanim-3.105 - OK
>> Edificio ns-3.22 - OK

Suggerimento: Tu può anche eseguire entrambi passi, scarica che a costruire by chiamata 'bake.py schierare'.

Se si verifica un errore, dai un'occhiata a cosa dice il seguente comando
tu; può dare un suggerimento su una dipendenza mancante:

$ ./bake.py spettacolo

Questo elencherà le varie dipendenze dei pacchetti che stai cercando di creare.

Costruzione con Waf
Fino a questo punto, abbiamo usato sia il build.py script, o il infornare strumento, per ottenere
iniziato con la costruzione NS-3. Questi strumenti sono utili per costruire NS-3 e sostenere
biblioteche, e chiamano in NS-3 directory per chiamare lo strumento di compilazione Waf per eseguire il
edificio vero e proprio. La maggior parte degli utenti passa rapidamente all'utilizzo diretto di Waf per configurare e
costruire NS-3. Quindi, per procedere, cambia la tua directory di lavoro in NS-3 elenco
che hai inizialmente costruito.

Non è strettamente necessario a questo punto, ma sarà utile fare una piccola deviazione
e guarda come apportare modifiche alla configurazione del progetto. Probabilmente il più
l'utile modifica alla configurazione che puoi apportare sarà quella di costruire la versione ottimizzata del
codice. Per impostazione predefinita, hai configurato il tuo progetto per creare la versione di debug. diciamo
il progetto per realizzare una build ottimizzata. Per spiegare a Waf che dovrebbe essere ottimizzato
build che includono gli esempi e i test, sarà necessario eseguire quanto segue
comandi:

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

Questo esegue Waf dalla directory locale (fornita per comodità dell'utente).
Il primo comando per ripulire la build precedente non è in genere strettamente necessario ma
è una buona pratica (ma vedi Silhouette Profili, sotto); rimuoverà il costruito in precedenza
librerie e file oggetto trovati nella directory costruire /. Quando il progetto viene riconfigurato
e il sistema di compilazione verifica la presenza di varie dipendenze, dovresti vedere un output che sembra
simile al seguente:

Impostazione in alto a : .
Partire per: costruire
Controllo di 'gcc' (compilatore c): /usr/bin/gcc
Verifica della versione cc: 4.2.1
Verifica della presenza di 'g++' (compilatore c++): /usr/bin/g++
Il controllo del boost include: 1_46_1
Controllo delle librerie boost: ok
Controllo del collegamento boost: ok
Controllo della posizione del clic: non trovato
Controllo del programma pkg-config: /sw/bin/pkg-config
Controllo di 'gtk+-2.0' >= 2.12: sì
Verifica di 'libxml-2.0' >= 2.7 : sì
Controllo del tipo uint128_t: non trovato
Controllo del tipo __uint128_t : sì
Verifica dell'implementazione ad alta precisione: intero a 128 bit (predefinito)
Controllo dell'intestazione stdint.h: sì
Controllo dell'intestazione inttypes.h: sì
Controllo dell'intestazione sys/inttypes.h: non trovato
Controllo dell'intestazione sys/types.h: sì
Controllo dell'intestazione sys/stat.h: sì
Controllo dell'intestazione dirent.h : sì
Controllo dell'intestazione stdlib.h: sì
Controllo del segnale di intestazione.h: sì
Controllo dell'intestazione pthread.h : sì
Controllo dell'intestazione stdint.h: sì
Controllo dell'intestazione inttypes.h: sì
Controllo dell'intestazione sys/inttypes.h: non trovato
Verifica della libreria rt: non trovata
Controllo dell'intestazione netpacket/packet.h: non trovato
Controllo dell'intestazione sys/ioctl.h : yes
Controllo dell'intestazione net/if.h: non trovato
Controllo dell'intestazione net/ethernet.h: sì
Controllo dell'intestazione linux/if_tun.h: non trovato
Controllo dell'intestazione netpacket/packet.h: non trovato
Controllo della posizione NSC: non trovato
Controllo di 'mpic++': sì
Controllo di 'sqlite3': sì
Controllo dell'intestazione linux/if_tun.h: non trovato
Controllo del programma sudo : /usr/bin/sudo
Controllo del programma valgrind: /sw/bin/valgrind
Controllo di 'gsl': sì
Verifica del flag di compilazione -Wno-error=deprecated-d... supporto: ok
Verifica del flag di compilazione -Wno-error=deprecated-d... supporto: ok
Verifica del flag di compilazione -fstrict-aliasing... supporto: ok
Verifica del flag di compilazione -fstrict-aliasing... supporto: ok
Verifica del flag di compilazione -Wstrict-aliasing... supporto: ok
Verifica del flag di compilazione -Wstrict-aliasing... supporto: ok
Controllo del programma doxygen: /usr/local/bin/doxygen
---- Riepilogo delle funzioni opzionali di NS-3:
Crea profilo: debug
Build directory: build
Associazioni Python: abilitate
Integrazione BRITE: non abilitata (BRITE non abilitata (vedi opzione --with-brite))
NS-3 Click Integration: non abilitato (nsclick non abilitato (vedi opzione --with-nsclick))
GtkConfigStore: abilitato
XmlIo: abilitato
Primitive di threading: abilitate
Simulatore in tempo reale: abilitato (librt non è disponibile)
Dispositivo di rete emulato: abilitato ( includere non rilevato)
Descrittore di file NetDevice: abilitato
Tocca FdNetDevice: non abilitato (richiede linux/if_tun.h)
Emulazione FdNetDevice : non abilitato (richiede netpacket/packet.h)
PlanetLab FdNetDevice : non abilitato (sistema operativo PlanetLab non rilevato (vedi opzione --force-planetlab))
Base di simulazione di rete: non abilitata (NSC non trovato (vedi opzione --with-nsc))
Supporto MPI: abilitato
NS-3 OpenFlow Integration: non abilitato (librerie boost richieste non trovate, mancanti: sistema, segnali, filesystem)
Uscita dati statistiche SQlite: abilitato
Tap Bridge : non abilitato ( includere non rilevato)
Visualizzatore PyViz: abilitato
Usa sudo per impostare suid bit: non abilitato (opzione --enable-sudo non selezionata)
Test di build: abilitato
Esempi di build: abilitato
GNU Scientific Library (GSL): abilitato
'configurare' è terminato con successo (1.944s)

Nota l'ultima parte dell'output di cui sopra. Alcuni NS-3 le opzioni non sono abilitate per impostazione predefinita oppure
richiedono il supporto del sistema sottostante per funzionare correttamente. Ad esempio, per abilitare
XmlTo, la libreria libxml-2.0 deve essere trovata nel sistema. Se questa libreria non lo fosse
trovato, il corrispondente NS-3 funzione non verrebbe abilitata e verrebbe visualizzato un messaggio
visualizzato. Nota inoltre che esiste una funzione per utilizzare il programma sudo per impostare il suid
un po' di certi programmi Questo non è abilitato per impostazione predefinita e quindi questa funzione viene segnalata
come "non abilitato".

Ora vai avanti e torna alla build di debug che include gli esempi e i test.

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

Il sistema di compilazione è ora configurato ed è possibile creare le versioni di debug del NS-3
programmi semplicemente digitando

$ ./waf

Ok, scusa, ti ho fatto costruire il NS-3 parte del sistema due volte, ma ora sai come farlo
modificare la configurazione e creare codice ottimizzato.

Lo script build.py discusso sopra supporta anche il --enable-esempi che a abilita-test
argomenti, ma in generale non supporta direttamente altre opzioni waf; per esempio, questo
non funzionerà:

$ ./build.py --disable-python

si tradurrà in

build.py: errore: nessuna opzione: --disable-python

Tuttavia, l'operatore speciale -- può essere utilizzato per passare ulteriori opzioni a waf, quindi
invece di quanto sopra, funzionerà quanto segue:

$ ./build.py --disable-python

in quanto genera il comando sottostante ./waf configure --disabilita-python.

Ecco alcuni altri suggerimenti introduttivi su Waf.

Configurazione vs. Silhouette
Alcuni comandi Waf sono significativi solo durante la fase di configurazione e alcuni comandi lo sono
valido in fase di costruzione. Ad esempio, se si desidera utilizzare le funzionalità di emulazione di
NS-3, potresti voler abilitare l'impostazione del bit suid usando sudo come descritto sopra. Questo
risulta essere un comando in fase di configurazione, quindi potresti riconfigurare usando il comando
seguente comando che include anche gli esempi e i test.

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

Se lo fai, Waf avrà eseguito sudo per cambiare i programmi di creazione del socket del
codice di emulazione da eseguire come root.

Ci sono molte altre opzioni di configurazione e build-time disponibili in Waf. Per esplorare questi
opzioni, digitare:

$ ./waf --aiuto

Useremo alcuni dei comandi relativi ai test nella prossima sezione.

Silhouette Profili
Abbiamo già visto come configurare Waf per mettere a punto or ottimizzati costruisce:

$ ./waf --build-profile=debug

C'è anche un profilo di build intermedio, rilasciare. -d è sinonimo di
--build-profilo.

Per impostazione predefinita, Waf mette gli artefatti di build nel costruire directory. Puoi specificare a
directory di output diversa con il --fuori opzione, ad es

$ ./waf configure --out=foo

La combinazione di questo con i profili di compilazione ti consente di passare tra le diverse opzioni di compilazione
in modo pulito:

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

Ciò ti consente di lavorare con più build anziché sovrascrivere sempre l'ultima
costruire. Quando cambi, Waf compilerà solo ciò che deve, invece di ricompilare
qualunque cosa.

Quando cambi profilo di build in questo modo, devi stare attento a dare lo stesso
parametri di configurazione ogni volta. Può essere conveniente definire un ambiente
variabili per aiutarti a evitare errori:

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

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

I compilatori
Negli esempi sopra, Waf usa il compilatore GCC C++, g ++, per costruire NS-3. Tuttavia,
è possibile modificare il compilatore C++ utilizzato da Waf definendo il CXX Industria XNUMX
variabile. Ad esempio, per utilizzare il compilatore Clang C++, clangore++,

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

Si può anche impostare Waf per fare la compilazione distribuita con distcc in un modo simile:

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

Maggiori informazioni su distcc e la compilation distribuita può essere trovata su di esso progetto pagina per
Sezione documentazione.

Installazione
Waf può essere utilizzato per installare librerie in vari punti del sistema. Il predefinito
la posizione in cui vengono compilate le librerie e gli eseguibili è in costruire directory, e perché
Waf conosce la posizione di queste librerie ed eseguibili, non è necessario installarle
le biblioteche altrove.

Se gli utenti scelgono di installare cose al di fuori della directory di build, gli utenti possono emettere il
./waf install comando. Per impostazione predefinita, il prefisso per l'installazione è / Usr / local, Così ./waf
install installerà programmi in / Usr / local / bin, biblioteche in / Usr / local / lib e
intestazioni in /usr/local/include. I privilegi di superutente sono in genere necessari per l'installazione su
il prefisso predefinito, quindi il comando tipico sarebbe sudo ./waf install. Quando corri
programmi con Waf, Waf preferirà prima usare le librerie condivise nella directory build,
quindi cercherà le librerie nel percorso della libreria configurato nell'ambiente locale. Così
durante l'installazione delle librerie nel sistema, è buona norma verificare che le
le biblioteche vengono utilizzate.

Gli utenti possono scegliere di installare con un prefisso diverso passando il --prefisso opzione in
configurare il tempo, come ad esempio:

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

Se più tardi dopo la compilazione l'utente emette il ./waf install comando, il prefisso /opt/locale
verrà utilizzato.

Le ./waf cavedano il comando dovrebbe essere usato prima di riconfigurare il progetto se Waf sarà
utilizzato per installare le cose con un prefisso diverso.

In sintesi, non è necessario chiamare ./waf install usare NS-3. La maggior parte degli utenti non lo farà
bisogno di questo comando poiché Waf prenderà le librerie correnti dal costruire elenco,
ma alcuni utenti potrebbero trovarlo utile se il loro caso d'uso implica lavorare con programmi esterni
di NS-3 directory.

Uno Waf
C'è solo uno script Waf, al livello più alto del NS-3 albero di origine. Mentre lavori, tu
potresti ritrovarti a passare molto tempo in graffio/, o nel profondo origine/..., e aver bisogno di
invoca Waf. Potresti semplicemente ricordare dove sei e invocare Waf in questo modo:

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

ma questo diventa noioso e soggetto a errori, e ci sono soluzioni migliori.

Se hai il pieno NS-3 repository questo piccolo gioiello è un inizio:

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

Ancora meglio è definirlo come una funzione di shell:

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

$ build waff

Se hai solo il tarball, una variabile d'ambiente può aiutarti:

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

$ graffio del cd
$ build waff

Potrebbe essere allettante in una directory del modulo aggiungere un banale waf sceneggiatura sulla falsariga di
exec ../../waf. Per favore no. È fonte di confusione per i nuovi arrivati, e quando è fatto male
porta a sottili errori di costruzione. Le soluzioni di cui sopra sono la strada da percorrere.

Testing NS-3
È possibile eseguire gli unit test del NS-3 distribuzione eseguendo il ./prova.py -c core
sceneggiatura:

$ ./test.py -c nucleo

Questi test vengono eseguiti in parallelo da Waf. Alla fine dovresti vedere un rapporto che dice che

92 di 92 test superati (92 superati, 0 falliti, 0 bloccati, 0 errori valgrind)

Questo è il messaggio importante.

Vedrai anche l'output di riepilogo da Waf e il test runner che esegue ogni test,
che in realtà assomiglierà a qualcosa del tipo:

Waf: entrare nella directory `/percorso/a/workspace/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/path/to/workspace/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (1.799s)

Moduli realizzati:
ponte di applicazioni aodv
fai clic su config-store core
csma csma-layout dsdv
emu monitor di flusso di energia
rete internet lte
mobilità mpi netanim
rete nix-vector-routing ns3tcp
ns3wifi olsr flusso aperto
propagazione del layout punto-punto punto-punto
statistiche dello spettro tap-bridge
strumenti di test del modello
topologia-letta uan dispositivo-rete-virtuale
visualizzatore wifi wimax

PASS: TestSuite ns3-interferenza wifi
PASS: istogramma TestSuite

...

PASS: oggetto TestSuite
PASS: Generatori di numeri casuali di TestSuite
92 di 92 test superati (92 superati, 0 falliti, 0 bloccati, 0 errori valgrind)

Questo comando viene in genere eseguito dagli utenti per verificare rapidamente che un NS-3 la distribuzione ha
costruito correttamente. (Notare l'ordine del PASSAGGIO: ... le linee possono variare, il che va bene. cosa c'è?
importante è che la riga di riepilogo alla fine riporti che tutti i test sono stati superati; nessuno ha fallito o
incidentato.)

corsa a Copione
Di solito eseguiamo script sotto il controllo di Waf. Ciò consente al sistema di build di garantire
che i percorsi delle librerie condivise siano impostati correttamente e che le librerie siano disponibili su
tempo di esecuzione. Per eseguire un programma, usa semplicemente il --correre opzione in Waf. Corriamo il NS-3
equivalente dell'onnipresente programma Hello World digitando quanto segue:

$ ./waf --esegui ciao-simulator

Waf prima controlla per assicurarsi che il programma sia compilato correttamente ed esegue una build se
necessario. Waf quindi esegue il programma, che produce il seguente output.

Ciao Simulatore

Congratulazioni! Ora sei un utente ns-3!

Che do I do if I non vedere , il produzione?

Se vedi messaggi Waf che indicano che la build è stata completata con successo, ma non lo fai
vedi l'output "Hello Simulator", è probabile che tu abbia cambiato la modalità di costruzione in
ottimizzati nel Costruzione con Waf sezione, ma ho perso la modifica di nuovo a mettere a punto modalità.
Tutto l'output della console utilizzato in questo tutorial utilizza uno speciale NS-3 componente di registrazione che
è utile per stampare i messaggi dell'utente sulla console. L'output di questo componente è
disabilitato automaticamente quando compili il codice ottimizzato: è "ottimizzato". Se tu
non vedi l'output "Hello Simulator", digita quanto segue:

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

per dire a Waf di creare le versioni di debug di NS-3 programmi che includono gli esempi
e prove. Devi comunque creare la versione di debug effettiva del codice digitando

$ ./waf

Ora, se esegui il ciao-simulatore programma, dovresti vedere l'output previsto.

Programma argomenti
Per fornire argomenti della riga di comando a an NS-3 programma usa questo schema:

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

Sostituisci il nome del tuo programma con , e gli argomenti per .
--modello-di-comando argomento a Waf è fondamentalmente una ricetta per costruire l'attuale
riga di comando che Waf dovrebbe usare per eseguire il programma. Waf controlla che la build sia
complete, imposta i percorsi della libreria condivisa, quindi richiama l'eseguibile utilizzando il fornito
modello della riga di comando, inserendo il nome del programma per il %s segnaposto. (lo ammetto
è un po' imbarazzante, ma è così. Patch benvenute!)

Un altro esempio particolarmente utile è l'esecuzione autonoma di una suite di test. Supponiamo che a
il mio test test suite esiste (non esiste). Sopra, abbiamo usato il ./prova.py script per eseguire un intero
una sfilza di test in parallelo, invocando ripetutamente il vero programma di test, corridore.
Invocare corridore direttamente per una singola prova:

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

Questo passa gli argomenti a corridore programma. Da quando il mio test non esiste, an
verrà generato un messaggio di errore. Per stampare il disponibile corridore opzioni:

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

Debug
Correre NS-3 programmi sotto il controllo di un'altra utility, come un debugger (per esempio gdb)
o controllo della memoria (per esempio valgrind), usi un simile --command-template="..." forma.

Ad esempio, per eseguire il tuo NS-3 Programma ciao-simulatore con gli argomenti sotto il
gdb debugger:

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

Si noti che il NS-3 il nome del programma va con --correre argomento e l'utilità di controllo
(Qui gdb) è il primo token in --modello-comando discussione. Il --arg dice gdb
che il resto della riga di comando appartiene al programma "inferiore". (Alcuni gdb's
non capisco il --arg caratteristica. In questo caso, omettere gli argomenti del programma da
--modello-di-comandoe usa il gdb command set args.)

Possiamo combinare questa ricetta e la precedente per eseguire un test sotto il debugger:

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

lavoro elenco
Waf ha bisogno di correre dalla sua posizione nella parte superiore del NS-3 albero. Questo diventa il lavoro
directory in cui verranno scritti i file di output. Ma cosa succede se vuoi tenerli fuori?
, il NS-3 albero sorgente? Utilizzare il --cwd argomento:

$ ./waf --cwd=...

Potrebbe essere più conveniente iniziare con la directory di lavoro in cui si desidera l'output
file, nel qual caso un piccolo riferimento indiretto può aiutare:

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

Questo abbellimento della versione precedente salva la directory di lavoro corrente, cdè per
la directory Waf, quindi indica a Waf di cambiare la directory di lavoro precedente ai salvati
directory di lavoro corrente prima di eseguire il programma.

CONCETTUALE OVERVIEW


La prima cosa che dobbiamo fare prima di iniziare effettivamente a guardare o scrivere NS-3 il codice è to
spiegare alcuni concetti e astrazioni fondamentali nel sistema. Molto di questo può apparire
chiaramente ovvio per alcuni, ma ti consigliamo di dedicare del tempo a leggerlo
sezione solo per assicurarti di iniziare su solide basi.

Le astrazioni
In questa sezione, esamineremo alcuni termini comunemente usati nelle reti, ma che hanno un
significato specifico in NS-3.

Nodo
Nel gergo di Internet, un dispositivo informatico che si connette a una rete è chiamato a host or
a volte e fine sistema. Perché NS-3 è un Rete simulatore, non specificamente an
Internet simulatore, non usiamo intenzionalmente il termine host poiché è molto vicino
associati a Internet e ai suoi protocolli. Invece, usiamo anche un termine più generico
utilizzato da altri simulatori che hanno origine nella teoria dei grafi --- il nodo.

In NS-3 l'astrazione del dispositivo di elaborazione di base è chiamata nodo. Questa astrazione è
rappresentato in C++ dalla classe Nodo. Nodo fornisce metodi per la gestione del
rappresentazioni di dispositivi di calcolo nelle simulazioni.

Dovresti pensare a un Nodo come un computer a cui aggiungerete funzionalità. uno aggiunge
cose come applicazioni, stack di protocollo e schede periferiche con i loro associati
driver per consentire al computer di svolgere un lavoro utile. Usiamo lo stesso modello base in NS-3.

Applicazioni
In genere, il software per computer è diviso in due grandi classi. Sistema Software organizza
varie risorse del computer come memoria, cicli del processore, disco, rete, ecc.,
secondo un modello di calcolo. Il software di sistema di solito non utilizza tali risorse
per completare le attività che avvantaggiano direttamente un utente. Un utente in genere esegue un'operazione applicazione
che acquisisce e utilizza le risorse controllate dal software di sistema per realizzare alcuni
obbiettivo.

Spesso, la linea di separazione tra il sistema e il software applicativo è fatta a
modifica del livello di privilegio che si verifica nei trap del sistema operativo. In NS-3 non c'è reale
concetto di sistema operativo e soprattutto nessun concetto di livelli di privilegio o chiamate di sistema.
Tuttavia, abbiamo l'idea di un'applicazione. Proprio come le applicazioni software vengono eseguite su
computer per eseguire compiti nel "mondo reale", NS-3 le applicazioni vengono eseguite su NS-3 Nodes a
simulazioni di guida nel mondo simulato.

In NS-3 l'astrazione di base per un programma utente che genera alcune attività per essere
simulata è l'applicazione. Questa astrazione è rappresentata in C++ dalla classe
Applicazioni. Applicazioni fornisce metodi per gestire le rappresentazioni di
la nostra versione di applicazioni a livello utente nelle simulazioni. Gli sviluppatori sono tenuti a
specializzarsi Applicazioni classe nel senso della programmazione orientata agli oggetti per creare nuovi
applicazioni. In questo tutorial, useremo le specializzazioni di classe Applicazioni detto
Applicazione UdpEchoClient che a UdpEchoServerApplicazione. Come ci si potrebbe aspettare, questi
le applicazioni compongono un set di applicazioni client/server utilizzato per generare e simulare l'eco
pacchetti di rete

canale
Nel mondo reale, si può connettere un computer a una rete. Spesso i media su cui
i flussi di dati in queste reti sono chiamati canali. Quando colleghi il cavo Ethernet a
la spina nel muro, stai collegando il tuo computer a una comunicazione Ethernet
canale. Nel mondo simulato di NS-3, si collega a Nodo a un oggetto che rappresenta a
canale di comunicazione. Qui l'astrazione di base della sottorete di comunicazione è chiamata
canale ed è rappresentato in C++ dalla classe canale.

Le canale fornisce metodi per la gestione degli oggetti della sottorete di comunicazione e
nodi di collegamento ad essi. Canali può anche essere specializzato dagli sviluppatori nell'oggetto
senso di programmazione orientato. UN canale la specializzazione può modellare qualcosa di semplice come a
filo. Lo specializzato canale può anche modellare cose complicate come una grande Ethernet
switch, o spazio tridimensionale pieno di ostacoli nel caso di reti wireless.

Useremo versioni specializzate del canale detto Canale Csma, Canale PuntoAPunto
che a Canale Wifi in questo tutorial. Il Canale Csma, ad esempio, modella una versione di a
sottorete di comunicazione che implementa a vettore senso multiplo accesso in termini di comunicazione
medio. Questo ci offre funzionalità simili a Ethernet.

Rete Dispositivo
Un tempo se volevi connettere un computer a una rete, dovevi
acquistare un tipo specifico di cavo di rete e un dispositivo hardware chiamato (nella terminologia del PC) a
periferico carta che doveva essere installato nel tuo computer. Se la scheda periferica
implementato qualche funzione di rete, sono state chiamate schede di interfaccia di rete, o NIC.
Oggi la maggior parte dei computer viene fornita con l'hardware dell'interfaccia di rete integrato e gli utenti non vedono
questi elementi costitutivi.

Una NIC non funzionerà senza un driver software per controllare l'hardware. In Unix (o
Linux), un pezzo di hardware periferico è classificato come a dispositivo. I dispositivi sono controllati
utilizzando dispositivo drivere i dispositivi di rete (NIC) sono controllati utilizzando Rete dispositivo
driver noto collettivamente come rete dispositivi. In Unix e Linux ti riferisci a queste reti
dispositivi con nomi come eth0.

In NS-3 , il rete dispositivo l'astrazione copre sia il driver software che il simulato
hardware. Un dispositivo di rete è "installato" in a Nodo per abilitare il Nodo a
comunicare con gli altri Nodes nella simulazione via Canali. Proprio come in un vero computer,
a Nodo può essere collegato a più di uno canale tramite multiplo NetDevice.

L'astrazione del dispositivo di rete è rappresentata in C++ dalla classe NetDevice. NetDevice
fornisce metodi per gestire le connessioni a Nodo che a canale oggetti; e forse
specializzato dagli sviluppatori nel senso della programmazione orientata agli oggetti. Useremo il
diverse versioni specializzate del NetDevice detto Dispositivo CsmaNet, Dispositivo PointToPointNet,
che a Dispositivo WifiNet in questo tutorial. Proprio come una NIC Ethernet è progettata per funzionare con un
rete Ethernet, il Dispositivo CsmaNet è progettato per funzionare con a Canale Csma; il
Dispositivo PointToPointNet è progettato per funzionare con a Canale PuntoAPunto e WifiNetNevice
è progettato per funzionare con a Canale Wifi.

Topologia Helpers
In una rete reale, troverai computer host con NIC aggiunte (o integrate). In NS-3 we
direi che troverai Nodes con allegato NetDevice. In una grande rete simulata
dovrai organizzare molti collegamenti tra Nodes, NetDevice che a Canali.

Dal momento della connessione NetDevice a Nodes, NetDevice a Canali, assegnazione di indirizzi IP,
ecc., sono compiti così comuni in NS-3, forniamo ciò che chiamiamo topologia aiutanti per fare questo
il più facile possibile. Ad esempio, potrebbero essere necessari molti distinti NS-3 operazioni principali per
creare un NetDevice, aggiungere un indirizzo MAC, installare quel dispositivo di rete su un Nodo, configurare il
stack di protocollo del nodo, quindi collegare il NetDevice ad un canale. Ancora più operazioni
sarebbe necessario collegare più dispositivi su canali multipoint e quindi connettersi
singole reti insieme in internetwork. Forniamo oggetti helper per la topologia che
combinare queste numerose operazioni distinte in un modello facile da usare per la tua comodità.

A Nome NS-3 Copione
Se hai scaricato il sistema come suggerito sopra, avrai una versione di NS-3 in un
directory chiamata pronti contro termine sotto la tua home directory. Cambia in quella directory di rilascio e
dovresti trovare una struttura di directory simile alla seguente:

AUTORI esempi scratch utils waf.bat*
binding LICENZA src utils.py waf-tools
costruire ns3 test.py* utils.pyc wscript
CHANGES.html README testpy-output VERSIONE wutils.py
doc RELEASE_NOTES testpy.supp waf* wutils.pyc

Cambia in esempi/tutorial directory. Dovresti vedere un file chiamato prima.cc collocato
là. Questo è uno script che creerà un semplice collegamento punto-punto tra due nodi
ed echo un singolo pacchetto tra i nodi. Diamo un'occhiata a quella riga di script di
linea, quindi vai avanti e apri prima.cc nel tuo editor preferito.

boilerplate
La prima riga del file è una riga in modalità emacs. Questo dice a emacs della formattazione
convenzioni (stile di codifica) che usiamo nel nostro codice sorgente.

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

Questo è sempre un argomento un po' controverso, quindi tanto vale toglierlo di mezzo
subito. Il NS-3 progetto, come la maggior parte dei progetti di grandi dimensioni, ha adottato uno stile di codifica per
cui tutto il codice fornito deve aderire. Se vuoi contribuire con il tuo codice al
progetto, alla fine dovrai conformarti al NS-3 standard di codifica come descritto in
il file doc/codingstd.txt o mostrato sulla pagina web del progetto qui.

Ti consigliamo, beh, di abituarti all'aspetto e alla sensazione di NS-3 codificare e adottare
questo standard ogni volta che lavori con il nostro codice. Tutto il team di sviluppo e
i contribuenti lo hanno fatto con varie quantità di brontolii. La riga della modalità emacs sopra
rende più facile ottenere la formattazione corretta se si utilizza l'editor emacs.

Le NS-3 simulator è concesso in licenza utilizzando la GNU General Public License. Vedrai il
appropriato GNU legalese all'inizio di ogni file nel NS-3 distribuzione. spesso tu
vedrà un avviso di copyright per una delle istituzioni coinvolte nel NS-3 progetto sopra
il testo GPL e un autore elencati di seguito.

/*
* Questo programma è un software gratuito; puoi ridistribuirlo e/o modificarlo
* secondo i termini della GNU General Public License versione 2 as
* pubblicato dalla Free Software Foundation;
*
* Questo programma è distribuito nella speranza che possa essere utile,
* ma SENZA ALCUNA GARANZIA; senza nemmeno la garanzia implicita di
* COMMERCIABILITÀ o IDONEITÀ PER UN PARTICOLARE SCOPO. Vedi il
* GNU General Public License per maggiori dettagli.
*
* Dovresti aver ricevuto una copia della GNU General Public License
* insieme a questo programma; in caso contrario, scrivi al Software Libero
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 Stati Uniti
*/

Moduli Inclusioni
Il codice vero e proprio inizia con un numero di istruzioni di inclusione.

#include "ns3/core-module.h"
#include "ns3/modulo-rete.h"
#include "ns3/internet-module.h"
#include "ns3/punto-punto-modulo.h"
#include "ns3/applications-module.h"

Per aiutare i nostri utenti di script di alto livello a gestire il gran numero di file di inclusione presenti in
il sistema, che raggruppiamo include secondo moduli relativamente grandi. Forniamo un unico
include file che caricherà in modo ricorsivo tutti i file include utilizzati in ogni modulo.
Piuttosto che dover cercare esattamente l'intestazione di cui hai bisogno, e possibilmente dover ottenere un
numero di dipendenze corretto, ti diamo la possibilità di caricare un gruppo di file di grandi dimensioni
granularità. Questo non è l'approccio più efficiente, ma sicuramente rende la scrittura
script molto più facile.

Ciascuno dei NS-3 include file è posto in una directory chiamata ns3 (sotto la costruzione
directory) durante il processo di compilazione per evitare conflitti di nomi di file di inclusione. Il
ns3/modulo-core.h corrisponde al modulo ns-3 che troverai nella directory
sorgente/nucleo nella distribuzione della versione scaricata. Se elenchi questa directory lo farai
trovare un gran numero di file di intestazione. Quando fai una build, Waf posizionerà un'intestazione pubblica
file in un file ns3 directory sotto l'appropriato costruire/debug or costruire/ottimizzare elenco
a seconda della tua configurazione. Waf genererà anche automaticamente un modulo include
file per caricare tutti i file di intestazione pubblici.

Dal momento che, ovviamente, stai seguendo religiosamente questo tutorial, lo avrai già fatto
a

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

per configurare il progetto per eseguire build di debug che includono esempi e test.
Avrai anche fatto un

$ ./waf

per costruire il progetto. Quindi ora se guardi nella directory ../../build/debug/ns3 si
trova i quattro moduli include file mostrati sopra. Puoi dare un'occhiata al contenuto di
questi file e scoprono che includono tutti i file public include nella loro
rispettivi moduli.

Ns3 Spazio dei nomi
La riga successiva in prima.cc script è una dichiarazione dello spazio dei nomi.

usando lo spazio dei nomi ns3;

Le NS-3 il progetto è implementato in uno spazio dei nomi C++ chiamato ns3. Questo raggruppa tutto
NS-3-dichiarazioni correlate in un ambito al di fuori dello spazio dei nomi globale, che speriamo possa aiutare
con integrazione con altro codice. Il C++ utilizzando dichiarazione introduce il NS-3 namespace
nell'attuale regione dichiarativa (globale). Questo è un modo elegante per dire che dopo
questa dichiarazione, non dovrai digitare ns3:: operatore di risoluzione dell'ambito prima di tutto
, il NS-3 codice per poterlo utilizzare. Se non hai familiarità con gli spazi dei nomi, consulta
quasi tutti i tutorial C++ e confronta i ns3 spazio dei nomi e utilizzo qui con istanze di
std spazio dei nomi e il utilizzando namespace standard; affermazioni che troverai spesso nelle discussioni
of cout e flussi.

Registrazione
La riga successiva dello script è la seguente,

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Useremo questa dichiarazione come un luogo conveniente per parlare della nostra documentazione Doxygen
sistema. Se guardi il sito web del progetto, NS-3 progetto, troverai un link a
"Documentazione" nella barra di navigazione. Se selezioni questo link, verrai indirizzato al nostro
pagina di documentazione. C'è un link a "Ultima versione" che ti porterà al
documentazione per l'ultima versione stabile di NS-3. Se selezioni "API
Documentazione", verrai indirizzato al NS-3 Pagina della documentazione dell'API.

Lungo il lato sinistro troverete una rappresentazione grafica della struttura del
documentazione. Un buon punto di partenza è il NS-3 moduli "libro" in NS-3 navigazione
albero. Se ti espandi moduli vedrai un elenco di NS-3 documentazione del modulo. Il
il concetto di modulo qui si lega direttamente al modulo include i file discussi sopra. Il
NS-3 Il sottosistema di registrazione è discusso in C++ Costruisce Usato by Tutto moduli sezione, quindi
vai avanti ed espandi quel nodo di documentazione. Ora, espandi il Debug prenota e poi
selezionare la Registrazione .

Ora dovresti guardare la documentazione di Doxygen per il modulo di registrazione. Nel
lista di #define's nella parte superiore della pagina vedrai la voce per
NS_LOG_COMPONENT_DEFINE. Prima di buttarsi, probabilmente sarebbe bene cercare il
"Descrizione dettagliata" del modulo di registrazione per avere un'idea dell'operazione complessiva. Voi
può scorrere verso il basso o selezionare il collegamento "Altro..." sotto il diagramma di collaborazione da fare
Questo.

Una volta che hai un'idea generale di cosa sta succedendo, vai avanti e dai un'occhiata allo specifico
NS_LOG_COMPONENT_DEFINE documentazione. Non duplicherò la documentazione qui, ma per
riassumere, questa riga dichiara un componente di registrazione chiamato FirstScriptEsempio che permette
abilitare e disabilitare la registrazione dei messaggi della console facendo riferimento al nome.

Principale Funzione
Le prossime righe dello script che troverai sono,

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

Questa è solo la dichiarazione della funzione principale del tuo programma (script). Proprio come in
qualsiasi programma C++, è necessario definire una funzione principale che sarà la prima funzione eseguita.
Non c'è niente di speciale qui. Tuo NS-3 script è solo un programma C++.

La riga successiva imposta la risoluzione temporale su un nanosecondo, che risulta essere l'impostazione predefinita
valore:

Ora::SetResolution (Ora::NS);

La risoluzione è il valore temporale più piccolo che può essere rappresentato (così come il più piccolo
differenza rappresentabile tra due valori temporali). Puoi cambiare esattamente la risoluzione
una volta. Il meccanismo che consente questa flessibilità è un po' affamato di memoria, quindi una volta che
risoluzione è stata impostata in modo esplicito rilasciamo la memoria, impedendo ulteriori aggiornamenti.
(Se non imposti la risoluzione in modo esplicito, verrà impostata su un nanosecondo e il
memoria verrà rilasciata all'avvio della simulazione.)

Le due righe successive dello script sono usate per abilitare due componenti di registrazione che sono costruiti
nelle applicazioni Echo Client ed Echo Server:

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

Se hai letto la documentazione del componente di registrazione avrai visto che c'è
sono una serie di livelli di verbosità/dettaglio di registrazione che è possibile abilitare su ciascun componente.
Queste due righe di codice abilitano la registrazione del debug a livello INFO per i client echo e
server. In questo modo l'applicazione stamperà i messaggi man mano che i pacchetti vengono inviati
e ricevuto durante la simulazione.

Ora ci occuperemo direttamente della creazione di una topologia e dell'esecuzione di una simulazione.
Utilizziamo gli oggetti helper della topologia per rendere questo lavoro il più semplice possibile.

Topologia Helpers
NodoContenitore
Le prossime due righe di codice nel nostro script creeranno effettivamente il NS-3 Nodo oggetti che
rappresenterà i computer nella simulazione.

nodi NodeContainer;
nodi.Crea (2);

Troviamo la documentazione per il NodoContenitore classe prima di continuare. Un altro modo
per entrare nella documentazione per una data classe è tramite il Classi scheda nel Doxygen
pagine. Se hai ancora il Doxygen a portata di mano, scorri fino all'inizio della pagina e
selezionare la Classi scheda. Dovresti vedere apparire una nuova serie di schede, una delle quali è Classe
Lista. Sotto quella scheda vedrai un elenco di tutti i NS-3 classi. Scorrere verso il basso,
cercando ns3::ContenitoreNodo. Quando trovi la classe, vai avanti e selezionala per andare a
la documentazione per la classe.

Potresti ricordare che una delle nostre astrazioni chiave è il Nodo. Questo rappresenta un computer
a cui aggiungeremo cose come stack di protocollo, applicazioni e periferiche
carte. Il NodoContenitore l'helper per la topologia fornisce un modo conveniente per creare, gestire e
accedere a qualsiasi Nodo oggetti che creiamo per eseguire una simulazione. La prima riga sopra
dichiara semplicemente un NodeContainer che chiamiamo nodi. La seconda linea chiama Creare
metodo sul nodi oggetto e chiede al contenitore di creare due nodi. Come descritto in
il Doxygen, il contenitore chiama giù nel NS-3 sistema corretto per creare due Nodo
oggetti e memorizza internamente i puntatori a tali oggetti.

I nodi così come sono nello script non fanno nulla. Il prossimo passo nella costruzione di a
La topologia consiste nel connettere i nostri nodi in una rete. La forma più semplice di rete che noi
il supporto è un singolo collegamento punto-punto tra due nodi. Ne costruiremo uno
link qui.

PuntoAPuntoHelper
Stiamo costruendo un collegamento punto a punto e, secondo uno schema che diventerà abbastanza
familiare, utilizziamo un oggetto helper della topologia per eseguire il lavoro di basso livello richiesto per mettere
il collegamento insieme. Ricordiamo che due delle nostre astrazioni chiave sono il NetDevice e le
canale. Nel mondo reale, questi termini corrispondono grosso modo alle carte periferiche e
cavi di rete. Tipicamente queste due cose sono intimamente legate e non si può
aspettarsi di scambiare, ad esempio, dispositivi Ethernet e canali wireless. La nostra topologia
Gli aiutanti seguono questo accoppiamento intimo e quindi utilizzerai un singolo
PuntoAPuntoHelper per configurare e connettere NS-3 Dispositivo PointToPointNet che a
Canale PuntoAPunto oggetti in questo script.

Le prossime tre righe dello script sono,

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

La prima riga,

PuntoToPuntoHelper puntoToPunto;

istanzia a PuntoAPuntoHelper oggetto in pila. Da una prospettiva di alto livello il
riga successiva,

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

dice il PuntoAPuntoHelper oggetto di utilizzare il valore "5Mbps" (cinque megabit al secondo) come
il "DataRate" quando crea un Dispositivo PointToPointNet oggetto.

Da una prospettiva più dettagliata, la stringa "DataRate" corrisponde a ciò che chiamiamo an
Attributo di Dispositivo PointToPointNet. Se guardi il Doxygen per la classe
ns3::PointToPointNetDevice e trova la documentazione per il Ottieni IDTipo metodo, lo farai
trova un elenco di Attributi definito per il dispositivo. Tra questi c'è il "DataRate"
Attributo. La maggior parte visibile dall'utente NS-3 gli oggetti hanno elenchi simili di Attributi. Usiamo questo
meccanismo per configurare facilmente le simulazioni senza ricompilare come vedrai in a
seguente sezione.

Simile al "DataRate" sul Dispositivo PointToPointNet troverai un "Ritardo" Attributo
associato al Canale PuntoAPunto. La riga finale,

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

dice il PuntoAPuntoHelper utilizzare il valore "2ms" (due millisecondi) come valore del
ritardo di trasmissione di ogni canale punto a punto che crea successivamente.

NetDeviceContenitore
A questo punto dello script, abbiamo un NodoContenitore che contiene due nodi. Noi abbiamo un
PuntoAPuntoHelper che è innescato e pronto per essere fatto Dispositivi PointToPointNet e filo
Canale PuntoAPunto oggetti tra di loro. Proprio come abbiamo usato il NodoContenitore topologia
oggetto helper per creare il Nodes per la nostra simulazione, chiederemo il PuntoAPuntoHelper
per svolgere il lavoro necessario per creare, configurare e installare i nostri dispositivi per noi. Noi
avrà bisogno di avere un elenco di tutti gli oggetti NetDevice che vengono creati, quindi usiamo a
NetDeviceContainer per contenerli proprio come abbiamo usato un NodeContainer per contenere i nodi che
creato. Le seguenti due righe di codice,

dispositivi NetDeviceContainer;
dispositivi = pointToPoint.Install (nodi);

terminerà la configurazione dei dispositivi e del canale. La prima riga dichiara il dispositivo
contenitore di cui sopra e il secondo fa il lavoro pesante. Il Installazione metodo di
, il PuntoAPuntoHelper prende a NodoContenitore come parametro. Internamente, a
NetDeviceContenitore è creato. Per ogni nodo in NodoContenitore (deve esserci esattamente
due per un collegamento punto-punto) a Dispositivo PointToPointNet viene creato e salvato nel dispositivo
contenitore. UN Canale PuntoAPunto viene creato e i due Dispositivi PointToPointNet sono
Allegata. Quando gli oggetti sono creati da PuntoAPuntoHelper, l' Attributi in precedenza
impostati nell'helper vengono utilizzati per inizializzare il corrispondente Attributi nel creato
oggetti.

Dopo aver eseguito il pointToPoint.Install (nodi) chiamata avremo due nodi, ciascuno con an
dispositivo di rete punto-punto installato e un singolo canale punto-punto tra di loro.
Entrambi i dispositivi saranno configurati per trasmettere dati a cinque megabit al secondo nel
canale che ha un ritardo di trasmissione di due millisecondi.

Internet StackHelper
Ora abbiamo nodi e dispositivi configurati, ma non abbiamo stack di protocollo installati
sui nostri nodi Le prossime due righe di codice se ne occuperanno.

Stack di InternetStackHelper;
stack.Install (nodi);

Le Internet StackHelper è un aiutante di topologia che serve a impilare Internet su ciò che
PuntoAPuntoHelper è quello di dispositivi di rete punto-punto. Il Installazione il metodo richiede a
NodoContenitore come parametro. Quando viene eseguito, installerà uno stack Internet
(TCP, UDP, IP e così via) su ciascuno dei nodi nel contenitore del nodo.

IPv4AddressHelper
Successivamente dobbiamo associare i dispositivi sui nostri nodi agli indirizzi IP. Forniamo un
aiutante di topologia per gestire l'allocazione degli indirizzi IP. L'unica API visibile dall'utente è quella di
impostare l'indirizzo IP di base e la maschera di rete da utilizzare quando si esegue l'indirizzo effettivo
allocazione (che avviene a un livello inferiore all'interno dell'helper).

Le prossime due righe di codice nel nostro script di esempio, prima.cc,

Ipv4AddressIndirizzo dell'assistente;
indirizzo.SetBase ("10.1.1.0", "255.255.255.0");

dichiarare un oggetto address helper e dirgli che dovrebbe iniziare ad allocare gli indirizzi IP
dalla rete 10.1.1.0 utilizzando la maschera 255.255.255.0 per definire i bit allocabili. Di
di default gli indirizzi allocati inizieranno da uno e aumenteranno in modo monotono, quindi il primo
l'indirizzo allocato da questa base sarà 10.1.1.1, seguito da 10.1.1.2, ecc. Il basso
livello NS-3 il sistema ricorda effettivamente tutti gli indirizzi IP allocati e genererà a
errore fatale se si fa accidentalmente generare lo stesso indirizzo due volte (che è un
molto difficile da correggere l'errore, tra l'altro).

La prossima riga di codice,

Interfacce Ipv4InterfaceContainer = address.Assign (dispositivi);

esegue l'effettiva assegnazione dell'indirizzo. In NS-3 facciamo l'associazione tra un IP
indirizzo e un dispositivo che utilizza un Interfaccia IPv4 oggetto. Proprio come a volte abbiamo bisogno di un elenco di
dispositivi di rete creati da un aiutante per riferimento futuro a volte abbiamo bisogno di un elenco di
Interfaccia IPv4 oggetti. Il Contenitore di interfaccia IPv4 fornisce questa funzionalità.

Ora abbiamo costruito una rete punto-punto, con stack installati e indirizzi IP
assegnato. Ciò di cui abbiamo bisogno a questo punto sono le applicazioni per generare traffico.

Applicazioni
Un'altra delle astrazioni fondamentali del sistema ns-3 è il Applicazioni. In questo
script usiamo due specializzazioni del core NS-3 classe Applicazioni detto
UdpEchoServerApplicazione che a Applicazione UdpEchoClient. Proprio come abbiamo nel nostro precedente
spiegazioni, utilizziamo oggetti helper per aiutare a configurare e gestire gli oggetti sottostanti.
Qui, usiamo UdpEchoServerHelper che a UdpEchoClientHelper oggetti per semplificarci la vita.

UdpEchoServerHelper
Le seguenti righe di codice nel nostro script di esempio, prima.cc, sono usati per impostare un eco UDP
applicazione server su uno dei nodi che abbiamo creato in precedenza.

UdpEchoServerHelper echoServer (9);

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

La prima riga di codice nel frammento di cui sopra dichiara il UdpEchoServerHelper. Come di solito,
questa non è l'applicazione in sé, è un oggetto utilizzato per aiutarci a creare l'effettivo
applicazioni. Una delle nostre convenzioni è quella di posizionare necessario Attributi nell'aiutante
costruttore. In questo caso, l'aiutante non può fare nulla di utile se non è provvisto di
un numero di porta che anche il client conosce. Piuttosto che sceglierne uno e sperare
tutto funziona, richiediamo il numero di porta come parametro per il costruttore. Il
costruttore, a sua volta, fa semplicemente un Imposta attributo con il valore passato. Se vuoi, tu
può impostare la "Porta" Attributo su un altro valore in seguito usando Imposta attributo.

Simile a molti altri oggetti di supporto, il UdpEchoServerHelper l'oggetto ha un Installazione
metodo. È l'esecuzione di questo metodo che effettivamente provoca l'eco sottostante
applicazione server da istanziare e collegare a un nodo. È interessante notare che Installazione
il metodo richiede a NodoContenitore come parametro come l'altro Installazione metodi che abbiamo
visto. Questo è in realtà ciò che viene passato al metodo anche se non sembra così in
questo caso. C'è un C++ implicito conversione al lavoro qui che prende il risultato di
nodi.Ottieni (1) (che restituisce un puntatore intelligente a un oggetto nodo --- Ptr) e usa quello
in un costruttore per un senza nome NodoContenitore che viene poi passato a Installazione. Se si è
mai in perdita per trovare una particolare firma del metodo nel codice C++ che compila ed esegue
bene, cerca questo tipo di conversioni implicite.

Ora lo vediamo echoServer.Install sta per installare un UdpEchoServerApplicazione sul canale
nodo trovato all'indice numero uno dei NodoContenitore eravamo soliti gestire i nostri nodi. Installazione
restituiràun contenitore che contiene i puntatori a tutte le applicazioni (una in questo caso
da quando siamo passati a NodoContenitore contenente un nodo) creato dall'helper.

Le applicazioni richiedono un tempo per "iniziare" a generare traffico e potrebbe richiedere un tempo facoltativo per
"fermare". Forniamo entrambi. Questi tempi sono impostati utilizzando il Contenitore dell'applicazione metodi
Inizia che a Fermare. Questi metodi prendono Ora parametri. In questo caso, usiamo an esplicito C++
sequenza di conversione per prendere C++ double 1.0 e convertirlo in an NS-3 Ora oggetto usando
a secondi lancio. Tieni presente che le regole di conversione possono essere controllate dall'autore del modello,
e C++ ha le sue regole, quindi non puoi sempre presumere che i parametri saranno felici
convertito per te. Le due linee,

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

farà sì che l'applicazione del server echo Inizia (abilitarsi) in un secondo in
simulazione e per Fermare (disabilitarsi) a dieci secondi dall'inizio della simulazione. In virtù di
il fatto che abbiamo dichiarato un evento di simulazione (l'evento di arresto dell'applicazione) come
eseguito a dieci secondi, la simulazione durerà at meno dieci secondi.

UdpEchoClientHelper
L'applicazione client echo è impostata in un metodo sostanzialmente simile a quello per il
server. C'è un sottostante Applicazione UdpEchoClient che è gestito da an
UdpEchoClientHelper.

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

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

Per il client echo, invece, dobbiamo impostarne cinque diversi Attributi. I primi due
Attributi sono fissati durante la costruzione del UdpEchoClientHelper. Passiamo i parametri
che servono (internamente all'helper) per impostare "RemoteAddress" e "RemotePort"
Attributi in conformità con la nostra convenzione per rendere richiesto Attributi parametri in
costruttori ausiliari.

Ricordiamo che abbiamo usato an Contenitore di interfaccia IPv4 per tenere traccia degli indirizzi IP noi
assegnato ai nostri dispositivi. L'interfaccia zero nel interfacce contenitore sta per
corrispondono all'indirizzo IP del nodo zero nel nodi contenitore. Il primo
interfaccia nel interfacce container corrisponde all'indirizzo IP del primo nodo in
, il nodi contenitore. Quindi, nella prima riga di codice (da sopra), stiamo creando il
helper e dicendogli di impostare l'indirizzo remoto del client come indirizzo IP
assegnato al nodo su cui risiede il server. Gli diciamo anche di organizzare l'invio
pacchetti alla porta nove.

I "MaxPackets" Attributo dice al client il numero massimo di pacchetti che gli permettiamo
inviare durante la simulazione. L'"intervallo" Attributo dice al cliente quanto tempo aspettare
tra i pacchetti e "PacketSize" Attributo dice al client quanto è grande il suo pacchetto
i carichi utili dovrebbero essere. Con questa particolare combinazione di Attributi, stiamo dicendo a
client per inviare un pacchetto da 1024 byte.

Proprio come nel caso del server echo, diciamo al client echo di Inizia che a Fermare, ma
qui avviamo il client un secondo dopo che il server è stato abilitato (a due secondi dall'inizio del
simulazione).

Simulatore
Quello che dobbiamo fare a questo punto è eseguire effettivamente la simulazione. Questo è fatto usando
la funzione globale Simulatore::Esegui.

Simulatore::Esegui ();

Quando in precedenza abbiamo chiamato i metodi,

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

abbiamo effettivamente programmato eventi nel simulatore a 1.0 secondi, 2.0 secondi e due eventi
a 10.0 secondi. quando Simulatore::Esegui viene chiamato, il sistema inizierà a cercare attraverso il
l'elenco degli eventi programmati e la loro esecuzione. Innanzitutto eseguirà l'evento a 1.0 secondi,
che abiliterà l'applicazione del server echo (questo evento può, a sua volta, programmare molti
altri eventi). Quindi eseguirà l'evento programmato per t=2.0 secondi che inizierà
l'applicazione client echo. Anche in questo caso, questo evento potrebbe programmare molti altri eventi. La partenza
l'implementazione dell'evento nell'applicazione client echo inizierà la fase di trasferimento dei dati di
la simulazione inviando un pacchetto al server.

L'atto di inviare il pacchetto al server attiverà una catena di eventi che sarà
programmato automaticamente dietro le quinte e che eseguirà la meccanica del
eco dei pacchetti in base ai vari parametri di temporizzazione che abbiamo impostato nello script.

Alla fine, poiché inviamo un solo pacchetto (ricorda il MaxPackets Attributo è stato impostato su
uno), la catena di eventi innescata da quella singola richiesta di eco client si ridurrà e
la simulazione andrà inattiva. Una volta che ciò accadrà, gli eventi rimanenti saranno i Fermare
eventi per il server e il client. Quando questi eventi vengono eseguiti, non ci sono
ulteriori eventi da elaborare e Simulatore::Esegui ritorna. La simulazione è quindi completa.

Non resta che ripulire. Questo viene fatto chiamando la funzione globale
Simulatore::Distruggi. Poiché l'helper funziona (o di basso livello NS-3 codice) eseguito, loro
sistemato in modo che i ganci fossero inseriti nel simulatore per distruggere tutti gli oggetti
che sono stati creati. Non dovevi tenere traccia di nessuno di questi oggetti da solo ---
tutto quello che dovevi fare era chiamare Simulatore::Distruggi ed esci. Il NS-3 il sistema si è preso cura di
la parte difficile per te. Le restanti righe del nostro primo NS-3 sceneggiatura, prima.cc, fai solo
che:

Simulatore::Distruggi ();
0 ritorno;
}

Quando , il simulatore andrete a fermare?
NS-3 è un simulatore di eventi discreti (DE). In un tale simulatore, ogni evento è associato
con il suo tempo di esecuzione, e la simulazione procede eseguendo eventi nel tempo
ordine del tempo di simulazione. Gli eventi possono causare la pianificazione di eventi futuri (ad esempio, a
il timer può riprogrammarsi per scadere all'intervallo successivo).

Gli eventi iniziali vengono solitamente attivati ​​da ciascun oggetto, ad es. IPv6 pianificherà il router
Annunci pubblicitari, richieste di vicinato, ecc., Un'applicazione pianifica il primo pacchetto
invio evento, ecc.

Quando un evento viene elaborato, può generare zero, uno o più eventi. Come una simulazione
viene eseguito, gli eventi vengono consumati, ma possono (o meno) essere generati più eventi. Il
la simulazione si interromperà automaticamente quando non ci sono altri eventi nella coda degli eventi o quando
viene trovato un evento Stop speciale. L'evento Stop viene creato tramite il Simulatore::Stop
(tempo di stop); funzione.

C'è un caso tipico in cui Simulatore::Stop è assolutamente necessario fermare il
simulazione: quando c'è un evento autosufficiente. Eventi autosufficienti (o ricorrenti)
sono eventi che si riprogrammano sempre. Di conseguenza, mantengono sempre l'evento
coda non vuota.

Esistono molti protocolli e moduli contenenti eventi ricorrenti, ad esempio:

· FlowMonitor - controllo periodico dei pacchetti persi

· RIPng - trasmissione periodica dell'aggiornamento delle tabelle di routing

· eccetera.

In questi casi, Simulatore::Stop è necessario per interrompere con garbo la simulazione. In
inoltre, quando NS-3 è in modalità di emulazione, il Simulatore in tempo reale è usato per mantenere il
orologio di simulazione allineato con l'orologio della macchina, e Simulatore::Stop è necessario fermarsi
il processo.

Molti dei programmi di simulazione nel tutorial non chiamano esplicitamente Simulatore::Stop,
poiché la coda degli eventi esaurirà automaticamente gli eventi. Tuttavia, questi programmi lo faranno
accetta anche una chiamata a Simulatore::Stop. Ad esempio, la seguente istruzione aggiuntiva in
il primo programma di esempio pianificherà uno stop esplicito a 11 secondi:

+ Simulatore::Stop (secondi (11.0));
Simulatore::Esegui ();
Simulatore::Distruggi ();
0 ritorno;
}

Quanto sopra non cambierà effettivamente il comportamento di questo programma, poiché questo particolare
la simulazione termina naturalmente dopo 10 secondi. Ma se dovessi cambiare l'ora della fermata in
l'affermazione di cui sopra da 11 secondi a 1 secondo, noteresti che la simulazione
si ferma prima che qualsiasi output venga stampato sullo schermo (poiché l'output si verifica intorno al tempo 2
secondi di tempo di simulazione).

È importante chiamare Simulatore::Stop prima chiamata Simulatore::Esegui; altrimenti,
Simulatore::Esegui potrebbe non restituire mai il controllo al programma principale per eseguire lo stop!

Costruzione Trasferimento da aeroporto a Sharm Copione
Abbiamo reso banale costruire i tuoi semplici script. Tutto quello che devi fare è lasciar cadere il tuo
script nella directory scratch e verrà creato automaticamente se esegui Waf.
Proviamolo. copia esempi/tutorial/first.cc nella graffiare directory dopo la modifica
torna nella directory di livello superiore.

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

Ora crea il tuo primo script di esempio usando waf:

$ ./waf

Dovresti vedere i messaggi che segnalano che il tuo il mio primo esempio è stato creato con successo.

Waf: entrare nella directory `/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: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (2.357s)

Ora puoi eseguire l'esempio (nota che se crei il tuo programma nella directory scratch
devi eseguirlo dalla directory scratch):

$ ./waf --run scratch/myfirst

Dovresti vedere un output:

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.418s)
Inviati 1024 byte a 10.1.1.2
Ricevuto 1024 byte da 10.1.1.1
Ricevuto 1024 byte da 10.1.1.2

Qui puoi vedere che il sistema di compilazione controlla per assicurarsi che il file sia stato compilato e
poi lo esegue. Vedete che il componente di registrazione sul client echo indica che è stato inviato
un pacchetto da 1024 byte all'Echo Server il 10.1.1.2. Vedi anche il componente di registrazione
sul server echo dire che ha ricevuto i 1024 byte da 10.1.1.1. Il server di eco
fa eco silenziosamente al pacchetto e vedi il registro del client echo che ha ricevuto il suo pacchetto
ritorno dal server.

Ns-3 Fonte Code
Ora che hai usato un po' di NS-3 aiutanti potresti voler dare un'occhiata ad alcuni dei
codice sorgente che implementa tale funzionalità. Il codice più recente può essere sfogliato su
il nostro web server al seguente link: http://code.nsnam.org/ns-3-dev. Ecco, vedrai
la pagina di riepilogo di Mercurial per il nostro NS-3 albero di sviluppo.

Nella parte superiore della pagina, vedrai una serie di link,

riassunto | shortlog | registro modifiche | grafico | tag | File

Vai avanti e seleziona il file collegamento. Questo è ciò che il livello più alto della maggior parte dei nostri
repository guarderà:

drwxr-xr-x [su]
drwxr-xr-x associazioni file python
drwxr-xr-x file doc
drwxr-xr-x file di esempio
drwxr-xr-x file ns3
file di scratch drwxr-xr-x
drwxr-xr-x file src
drwxr-xr-x file di utilità
-rw-r--r-- 2009/07/01 12:47 +0200 560 .hgignore file | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 1886 file .hgtags | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 1276 AUTORI file | revisioni | annotare
-rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html file | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 17987 File LICENZA | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 3742 File LEGGIMI | revisioni | annotare
-rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES file | revisioni | annotare
-rw-r--r-- 2009-07-01 12:47 +0200 6 VERSIONE file | revisioni | annotare
-rwxr-xr-x 2009/07/01 12:47 +0200 88110 file waf | revisioni | annotare
-rwxr-xr-x 2009/07/01 12:47 +0200 28 file waf.bat | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 35395 wscript file | revisioni | annotare
-rw-r--r-- 2009/07/01 12:47 +0200 7673 file wutils.py | revisioni | annotare

I nostri script di esempio sono in Esempi directory. Se fai clic su Esempi si vedrà
un elenco di sottodirectory. Uno dei file in lezione la sottodirectory è prima.cc. Se si
cliccare su prima.cc troverai il codice che hai appena attraversato.

Il codice sorgente è principalmente nel src directory. Puoi visualizzare il codice sorgente tramite
cliccando sul nome della directory o cliccando sul file link a destra del
nome della directory. Se fai clic su src directory, verrai indirizzato all'elenco di
, il src sottodirectory. Se poi fai clic su core sottodirectory, troverai un elenco di
File. Il primo file che troverai (al momento della stesura di questo documento) è interrompi.h. Se si fa clic sul
interrompi.h collegamento, verrai inviato al file sorgente per interrompi.h che contiene utili macro
per uscire dagli script se vengono rilevate condizioni anomale.

Il codice sorgente per gli helper che abbiamo usato in questo capitolo può essere trovato in
src/applicazioni/helper directory. Sentiti libero di curiosare nell'albero delle directory per ottenere
una sensazione per quello che c'è e lo stile di NS-3 programmi.

OTTIMIZZAZIONE


utilizzando , il Registrazione Moduli
Abbiamo già dato una breve occhiata al NS-3 modulo di registrazione durante l'esame del
prima.cc sceneggiatura. Ora daremo un'occhiata più da vicino e vedremo che tipo di casi d'uso il
sottosistema di registrazione è stato progettato per coprire.

Registrazione Panoramica
Molti sistemi di grandi dimensioni supportano un qualche tipo di funzione di registrazione dei messaggi e NS-3 non è un
eccezione. In alcuni casi, solo i messaggi di errore vengono registrati nella "console operatore" (che
è in genere stderr nei sistemi basati su Unix). In altri sistemi, i messaggi di avviso potrebbero essere
output e messaggi informativi più dettagliati. In alcuni casi, strutture di registrazione
vengono utilizzati per inviare messaggi di debug che possono trasformare rapidamente l'output in una sfocatura.

NS-3 ritiene che tutti questi livelli di verbosità siano utili e forniamo a
approccio selezionabile e multilivello alla registrazione dei messaggi. La registrazione può essere disabilitata completamente,
abilitato su base componente per componente o abilitato globalmente; e fornisce selezionabile
livelli di verbosità. Il NS-3 log fornisce un semplice, relativamente facile da usare
modo per ottenere informazioni utili dalla simulazione.

Dovresti capire che forniamo un meccanismo di uso generale --- tracciamento --- per
ottenere i dati dai tuoi modelli che dovrebbero essere preferiti per l'output della simulazione (vedi il
sezione tutorial Utilizzo del sistema di tracciamento per maggiori dettagli sul nostro sistema di tracciamento).
La registrazione dovrebbe essere preferita per il debug di informazioni, avvisi, messaggi di errore o altro
volta in cui desideri ottenere facilmente un messaggio rapido dai tuoi script o modelli.

Ci sono attualmente sette livelli di messaggi di log di verbosità crescente definiti nel
.

· LOG_ERROR --- Registra i messaggi di errore (macro associata: NS_LOG_ERROR);

· LOG_WARN --- Registra i messaggi di avviso (macro associata: NS_LOG_WARN);

· LOG_DEBUG --- Registra messaggi di debug ad hoc relativamente rari (macro associata:
NS_LOG_DEBUG);

· LOG_INFO --- Registra i messaggi informativi sull'avanzamento del programma (macro associata:
NS_LOG_INFO);

· LOG_FUNCTION --- Registra un messaggio che descrive ogni funzione chiamata (due macro associate:
NS_LOG_FUNCTION, utilizzato per le funzioni membro e NS_LOG_FUNCTION_NOARGS, utilizzato per le funzioni statiche
funzioni);

· LOG_LOGIC -- Registra i messaggi che descrivono il flusso logico all'interno di una funzione (macro associata:
NS_LOG_LOGICA);

· LOG_ALL --- Registra tutto quanto menzionato sopra (nessuna macro associata).

Per ogni LOG_TYPE è presente anche LOG_LEVEL_TYPE che, se utilizzato, abilita il logging di tutte le
livelli sopra di esso oltre al suo livello. (Di conseguenza, LOG_ERROR e
LOG_LEVEL_ERROR e anche LOG_ALL e LOG_LEVEL_ALL sono funzionalmente equivalenti.) Per
esempio, l'abilitazione di LOG_INFO abiliterà solo i messaggi forniti dalla macro NS_LOG_INFO, mentre
l'abilitazione di LOG_LEVEL_INFO abiliterà anche i messaggi forniti da NS_LOG_DEBUG, NS_LOG_WARN
e macro NS_LOG_ERROR.

Forniamo anche una macro di registrazione incondizionata che viene sempre visualizzata, indipendentemente da
livelli di registrazione o selezione dei componenti.

· NS_LOG_UNCOND -- Registra il messaggio associato incondizionatamente (nessun livello di registro associato).

Ogni livello può essere richiesto singolarmente o cumulativamente; e la registrazione può essere impostata utilizzando a
variabile di ambiente shell (NS_LOG) o registrando la chiamata alla funzione di sistema. Come si è visto
in precedenza nel tutorial, il sistema di registrazione ha la documentazione Doxygen e ora sarebbe a
è un buon momento per esaminare la documentazione del modulo di registrazione se non l'hai fatto.

Ora che hai letto la documentazione in modo molto dettagliato, usiamo un po' di quella conoscenza
per ottenere alcune informazioni interessanti dal gratta/ilmioprimo.cc script di esempio che hai
già costruito.

Abilitare Registrazione
Usiamo la variabile d'ambiente NS_LOG per attivare un po' più di registrazione, ma prima, solo per
orientati, vai avanti ed esegui l'ultimo script proprio come hai fatto in precedenza,

$ ./waf --run scratch/myfirst

Dovresti vedere l'output ormai familiare del primo NS-3 programma di esempio

$ Waf: inserimento nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.413s)
Inviati 1024 byte a 10.1.1.2
Ricevuto 1024 byte da 10.1.1.1
Ricevuto 1024 byte da 10.1.1.2

Si scopre che i messaggi "Inviato" e "Ricevuto" che vedi sopra stanno effettivamente registrando
messaggi dal Applicazione UdpEchoClient che a UdpEchoServerApplicazione. Possiamo chiedere a
applicazione client, ad esempio, per stampare più informazioni impostandone il livello di registrazione
tramite la variabile di ambiente NS_LOG.

Presumo da qui in poi che tu stia usando una shell simile a sh che usa
la sintassi "VARIABILE=valore". Se stai usando una shell simile a csh, allora dovrai
converti i miei esempi nella sintassi "setenv VARIABLE value" richiesta da quelle shell.

In questo momento, l'applicazione client echo UDP sta rispondendo alla seguente riga di codice in
gratta/ilmioprimo.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Questa riga di codice abilita il LOG_LEVEL_INFO livello di registrazione. Quando passiamo una registrazione
flag di livello, stiamo effettivamente abilitando il livello dato e tutti i livelli inferiori. In questo caso,
abbiamo abilitato NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN che a NS_LOG_ERRORE. possiamo aumentare
il livello di registrazione e ottenere maggiori informazioni senza modificare lo script e ricompilare con
impostando la variabile d'ambiente NS_LOG in questo modo:

$ export NS_LOG=UdpEchoClientApplication=level_all

Questo imposta la variabile d'ambiente della shell NS_LOG alla corda,

UdpEchoClientApplication=livello_tutto

Il lato sinistro dell'assegnazione è il nome del componente di registrazione che vogliamo impostare,
e il lato destro è la bandiera che vogliamo usare. In questo caso, stiamo per accendere
tutti i livelli di debug per l'applicazione. Se esegui lo script con NS_LOG impostato
in questo modo, il NS-3 il sistema di registrazione rileverà la modifica e dovresti vedere quanto segue
produzione:

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.404s)
UdpEchoClientApplicazione:UdpEchoClient()
Applicazione UdpEchoClient:Imposta dimensione dati(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Invia()
Inviati 1024 byte a 10.1.1.2
Ricevuto 1024 byte da 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Ricevuto 1024 byte da 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
Applicazione UdpEchoClient:~UdpEchoClient()

Le informazioni di debug aggiuntive fornite dall'applicazione provengono da NS_LOG_FUNCTION
livello. Questo mostra ogni volta che viene chiamata una funzione nell'applicazione durante lo script
esecuzione. Generalmente, l'uso di (almeno) NS_LOG_FUNCTION(this) nelle funzioni membro è
preferito. Usa NS_LOG_FUNCTION_NOARGS() solo nelle funzioni statiche. Nota, tuttavia, che
non ci sono requisiti nel NS-3 sistema che i modelli devono supportare qualsiasi particolare
funzionalità di registrazione. La decisione su quante informazioni vengono registrate è lasciata a
lo sviluppatore del modello individuale. Nel caso delle applicazioni echo, una buona dose di log
l'uscita è disponibile.

È ora possibile visualizzare un registro delle chiamate di funzione effettuate all'applicazione. Se tu
guarda da vicino noterai un singolo due punti tra la stringa Applicazione UdpEchoClient
e il nome del metodo in cui ti saresti aspettato un operatore di ambito C++ (::). Questo è
intenzionale.

Il nome non è in realtà un nome di classe, è un nome di componente di registrazione. Quando c'è un
corrispondenza biunivoca tra un file sorgente e una classe, questa sarà generalmente la
nome della classe ma dovresti capire che in realtà non è un nome di classe, e c'è un
due punti singoli invece di due punti doppi per ricordarti in un modo relativamente sottile di
separare concettualmente il nome del componente di registrazione dal nome della classe.

Si scopre che in alcuni casi può essere difficile determinare quale metodo effettivamente
genera un messaggio di registro. Se guardi nel testo sopra, potresti chiederti dove si trova la stringa
"ricevuto 1024 bytes da 10.1.1.2" viene da. Puoi risolverlo facendo OR su
prefisso_funzione livello nella NS_LOG variabile d'ambiente. Prova a fare quanto segue,

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Nota che le virgolette sono obbligatorie poiché la barra verticale che usiamo per indicare un OR
operazione è anche un connettore per tubi Unix.

Ora, se esegui lo script vedrai che il sistema di registrazione si assicura che ogni
messaggio dal componente di log specificato è preceduto dal nome del componente.

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.417s)
UdpEchoClientApplicazione:UdpEchoClient()
Applicazione UdpEchoClient:Imposta dimensione dati(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Invia()
UdpEchoClientApplication:Send(): ha inviato 1024 byte a 10.1.1.2
Ricevuto 1024 byte da 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
Applicazione UdpEchoClient:~UdpEchoClient()

Ora puoi vedere tutti i messaggi provenienti dall'applicazione client echo UDP sono
identificato come tale. Il messaggio "Ricevuto 1024 byte da 10.1.1.2" è ora chiaramente
identificato come proveniente dall'applicazione client echo. Il messaggio rimanente deve essere
proveniente dall'applicazione server echo UDP. Possiamo abilitare quel componente inserendo a
elenco di componenti separati da due punti nella variabile di ambiente NS_LOG.

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

Avvertenza: sarà necessario rimuovere la nuova riga dopo il : nel testo di esempio sopra che
è presente solo per scopi di formattazione del documento.

Ora, se esegui lo script vedrai tutti i messaggi di registro da entrambi i client echo
e applicazioni server. Potresti vedere che questo può essere molto utile nel debug dei problemi.

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.406s)
Applicazione UdpEchoServer:UdpEchoServer()
UdpEchoClientApplicazione:UdpEchoClient()
Applicazione UdpEchoClient:Imposta dimensione dati(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Invia()
UdpEchoClientApplication:Send(): ha inviato 1024 byte a 10.1.1.2
UdpEchoServerApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.1
UdpEchoServerApplication:HandleRead(): Echo pacchetto
UdpEchoClientApplicazione:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
Applicazione UdpEchoClient:~UdpEchoClient()
Applicazione UdpEchoServer:~UdpEchoServer()

A volte è anche utile poter vedere l'ora della simulazione in cui un messaggio di registro
è generato. Puoi farlo eseguendo un OR nel bit prefix_time.

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

Ancora una volta, dovrai rimuovere la nuova riga sopra. Se esegui lo script ora, dovresti
vedere il seguente output:

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.418s)
0s UdpEchoServerApplicazione:UdpEchoServer()
0s UdpEchoClientApplicazione:UdpEchoClient()
0s UdpEchoClientApplicazione:Imposta dimensione dati(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): ha inviato 1024 byte a 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echo pacchetto
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
Applicazione UdpEchoClient:~UdpEchoClient()
Applicazione UdpEchoServer:~UdpEchoServer()

Puoi vedere che il costruttore per UdpEchoServer è stato chiamato in un momento di simulazione di
0 secondi. Questo in realtà sta accadendo prima che inizi la simulazione, ma il momento è
visualizzato come zero secondi. Lo stesso vale per il messaggio del costruttore UdpEchoClient.

Ricordiamo che il graffio/primo.cc script ha avviato l'applicazione del server echo in un secondo
nella simulazione. Ora puoi vedere che il AvviaApplicazione il metodo del server è,
infatti, chiamato in un secondo. Puoi anche vedere che l'applicazione client echo è
è iniziato con un tempo di simulazione di due secondi come richiesto nello script.

Ora puoi seguire l'andamento della simulazione dal ProgrammaTrasmissione chiamare in
cliente che chiama Invia ai ManigliaLeggi richiamata nell'applicazione del server echo. Nota
che il tempo trascorso per l'invio del pacchetto attraverso il collegamento punto-punto è 3.69
millisecondi. Vedi il server echo che registra un messaggio che ti dice che ha echo
il pacchetto e poi, dopo un altro ritardo di canale, vedi che il client echo riceve il
pacchetto eco nel suo ManigliaLeggi metodo.

C'è molto che sta accadendo sotto le coperte in questa simulazione che tu non sei
anche vedere. Puoi facilmente seguire l'intero processo attivando tutti i
componenti di registrazione nel sistema. Prova a impostare il NS_LOG variabile al seguente,

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

L'asterisco sopra è il carattere jolly del componente di registrazione. Questo attiverà tutti i
l'accesso a tutti i componenti utilizzati nella simulazione. Non riprodurrò l'output
qui (al momento della stesura di questo documento produce 1265 linee di output per l'eco del singolo pacchetto) ma
puoi reindirizzare queste informazioni in un file e sfogliarlo con il tuo preferito
editore se vuoi,

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

Personalmente uso questa versione estremamente dettagliata della registrazione quando mi viene presentato un
problema e non ho idea di dove le cose stiano andando storte. Posso seguire l'andamento del
codice abbastanza facilmente senza dover impostare punti di interruzione e passare attraverso il codice in un debugger.
Posso semplicemente modificare l'output nel mio editor preferito e cercare in giro le cose che mi aspetto,
e vedere accadere cose che non mi aspetto. Quando ho un'idea generale di cosa sia
andando male, passo a un debugger per un esame approfondito del problema.
Questo tipo di output può essere particolarmente utile quando il tuo script fa qualcosa completamente
inaspettato. Se stai utilizzando un debugger potresti perdere un'escursione inaspettata
completamente. La registrazione dell'escursione la rende rapidamente visibile.

Aggiunta Registrazione a il tuo Code
Puoi aggiungere nuovi log alle tue simulazioni effettuando chiamate al componente log tramite
diverse macro. Facciamolo nel mioprimo.cc script che abbiamo in graffiare directory.

Ricordiamo che abbiamo definito un componente di registrazione in quello script:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Ora sai che puoi abilitare tutte le registrazioni per questo componente impostando il
NS_LOG ambiente variabile ai vari livelli. Andiamo avanti e aggiungiamo un po' di registrazione a
il copione. La macro utilizzata per aggiungere un messaggio di registro a livello informativo è NS_LOG_INFO. Partire
avanti e aggiungine uno (appena prima di iniziare a creare i nodi) che ti dice che lo script
è "Creazione della topologia". Questo viene fatto come in questo frammento di codice,

Apri gratta/ilmioprimo.cc nel tuo editor preferito e aggiungi la riga,

NS_LOG_INFO ("Creazione della topologia");

proprio prima delle righe,

nodi NodeContainer;
nodi.Crea (2);

Ora crea lo script usando waf e cancella il NS_LOG variabile per disattivare il torrent
logging che abbiamo precedentemente abilitato:

$ ./waf
$ esportazione NS_LOG=

Ora, se esegui lo script,

$ ./waf --run scratch/myfirst

si non è un vedere il tuo nuovo messaggio dal suo componente di registrazione associato
(FirstScriptEsempio) non è stato abilitato. Per vedere il tuo messaggio dovrai
abilitare il FirstScriptEsempio componente di registrazione con un livello maggiore o uguale a
NS_LOG_INFO. Se vuoi solo vedere questo particolare livello di registrazione, puoi abilitarlo
di,

$ export NS_LOG=FirstScriptExample=info

Se ora esegui lo script vedrai il tuo nuovo messaggio di registro "Creazione della topologia",

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.404s)
Creazione della topologia
Inviati 1024 byte a 10.1.1.2
Ricevuto 1024 byte da 10.1.1.1
Ricevuto 1024 byte da 10.1.1.2

utilizzando Comando linea argomenti
Override Predefinito Attributi
Un altro modo per cambiare il modo NS-3 gli script si comportano senza modifiche e la costruzione è via
command linea argomenti. Forniamo un meccanismo per analizzare gli argomenti della riga di comando e
imposta automaticamente le variabili locali e globali in base a tali argomenti.

Il primo passo nell'uso del sistema di argomenti della riga di comando è dichiarare la riga di comando
analizzatore. Questo è fatto abbastanza semplicemente (nel tuo programma principale) come nel seguente codice,

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

Riga di comando cmd;
cmd.Parse (argc, argv);

...
}

Questo semplice frammento di due righe è in realtà molto utile da solo. Apre la porta al
NS-3 variabile globale e Attributo sistemi. Vai avanti e aggiungi quelle due righe di codice a
, il gratta/ilmioprimo.cc sceneggiatura all'inizio di principale. Vai avanti e crea lo script ed esegui
esso, ma chiedi aiuto allo script nel modo seguente,

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

Questo chiederà a Waf di eseguire il graffio/il mio primo script e passare l'argomento della riga di comando
--Aiuto per la stampa alla sceneggiatura. Le virgolette sono necessarie per stabilire quale programma ottiene quale
discussione. Il parser della riga di comando ora vedrà il --Aiuto per la stampa argomentare e rispondere con,

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.413s)
Protocollo TcpL4: TcpStateMachine()
CommandLine:HandleArgument(): gestisce nome argomento=valore PrintHelp=
--PrintHelp: stampa questo messaggio di aiuto.
--PrintGroups: stampa l'elenco dei gruppi.
--PrintTypeIds: stampa tutti i TypeId.
--PrintGroup=[group]: stampa tutti i TypeId del gruppo.
--PrintAttributes=[typeid]: stampa tutti gli attributi di typeid.
--PrintGlobals: stampa l'elenco dei globali.

Concentriamoci sul --Stampa attributi opzione. Abbiamo già accennato al NS-3 Attributo
sistema mentre si cammina attraverso il prima.cc sceneggiatura. Abbiamo guardato le seguenti righe di
codice,

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

e lo ha menzionato Velocità dati era in realtà un Attributo di Dispositivo PointToPointNet. andiamo
usa il parser di argomenti della riga di comando per dare un'occhiata a Attributi di
Dispositivo PointToPointNet. L'elenco di aiuto dice che dovremmo fornire a ID tipo. Questo
corrisponde al nome della classe alla quale il Attributi appartenere. In questo caso
lo sarà ns3::PointToPointNetDevice. Andiamo avanti e digitiamo,

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

Il sistema stamperà tutte le Attributi di questo tipo di dispositivo di rete. Tra i
Attributi vedrai elencato è,

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
La velocità dati predefinita per i collegamenti punto a punto

Questo è il valore predefinito che verrà utilizzato quando a Dispositivo PointToPointNet viene creato nel
sistema. Abbiamo sovrascritto questa impostazione predefinita con il Attributo impostazione in PuntoAPuntoHelper
sopra. Usiamo i valori predefiniti per i dispositivi punto-punto e i canali di
eliminando il file Imposta attributo dispositivo chiamare e il SetChannelAttribute chiama dal mioprimo.cc
abbiamo nella directory scratch.

Il tuo script ora dovrebbe semplicemente dichiarare il PuntoAPuntoHelper e non fare niente set operazioni
come nel seguente esempio,

...

nodi NodeContainer;
nodi.Crea (2);

PuntoToPuntoHelper puntoToPunto;

dispositivi NetDeviceContainer;
dispositivi = pointToPoint.Install (nodi);

...

Vai avanti e crea il nuovo script con Waf (./waf) e torniamo indietro e attiviamone un po'
l'accesso dall'applicazione server echo UDP e attivare il prefisso dell'ora.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Se esegui lo script, ora dovresti vedere il seguente output,

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.405s)
0s UdpEchoServerApplicazione:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Inviati 1024 byte a 10.1.1.2
2.25732s Ricevuti 1024 byte da 10.1.1.1
2.25732s Pacchetto eco
Ricevuto 1024 byte da 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
Applicazione UdpEchoServer:~UdpEchoServer()

Ricordiamo che l'ultima volta che abbiamo esaminato il tempo di simulazione in cui si trovava il pacchetto
ricevuto dal server echo, era a 2.00369 secondi.

2.00369s UdpEchoServerApplication:HandleRead(): ricevuti 1024 byte da 10.1.1.1

Ora sta ricevendo il pacchetto a 2.25732 secondi. Questo perché abbiamo appena lasciato cadere il
velocità dati del Dispositivo PointToPointNet fino al valore predefinito di 32768 bit al secondo da
cinque megabit al secondo.

Se dovessimo fornire un nuovo Velocità dati usando la riga di comando, potremmo velocizzare la nostra simulazione
su di nuovo. Lo facciamo nel modo seguente, secondo la formula implicita nell'aiuto
articolo:

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

Questo imposterà il valore predefinito di Velocità dati Attributo torna a cinque megabit per
secondo. Sei sorpreso dal risultato? Si scopre che per ottenere l'originale
comportamento dello script indietro, dovremo impostare il ritardo della velocità della luce del canale
anche. Possiamo chiedere al sistema della riga di comando di stampare il Attributi del canale
proprio come abbiamo fatto per il dispositivo di rete:

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

Scopriamo il Ritardo Attributo del canale è impostato nel modo seguente:

--ns3::PointToPointChannel::Ritardo=[0ns]:
Ritardo di trasmissione attraverso il canale

Possiamo quindi impostare entrambi questi valori predefiniti tramite il sistema a riga di comando,

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

in tal caso recuperiamo i tempi che avevamo quando abbiamo impostato esplicitamente il Velocità dati che a Ritardo
nello script:

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.417s)
0s UdpEchoServerApplicazione:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Inviati 1024 byte a 10.1.1.2
2.00369s Ricevuti 1024 byte da 10.1.1.1
2.00369s Pacchetto eco
Ricevuto 1024 byte da 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
Applicazione UdpEchoServer:~UdpEchoServer()

Si noti che il pacchetto viene nuovamente ricevuto dal server a 2.00369 secondi. Potremmo
effettivamente impostare uno dei Attributi utilizzato nello script in questo modo. In particolare potremmo
impostare il UdpEchoClient Attributo MaxPackets a un valore diverso da uno.

Come andresti a riguardo? Provaci. Ricorda che devi commentare il posto
sovrascriviamo l'impostazione predefinita Attributo e impostare esplicitamente MaxPackets nella sceneggiatura. Allora lei
devo ricostruire lo script Dovrai anche trovare la sintassi per l'impostazione effettiva
il nuovo valore dell'attributo predefinito utilizzando la funzione di aiuto della riga di comando. Una volta che hai questo
ho capito che dovresti essere in grado di controllare il numero di pacchetti echeggiati dal comando
linea. Dato che siamo brave persone, ti diremo che la tua riga di comando dovrebbe finire per guardare
qualcosa di simile a,

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

aggancio Trasferimento da aeroporto a Sharm Proprio Valori
Puoi anche aggiungere i tuoi hook al sistema della riga di comando. Questo è fatto semplicemente da
usando il Aggiungere valore metodo al parser della riga di comando.

Usiamo questa funzione per specificare il numero di pacchetti di cui eseguire l'eco in un modo completamente diverso
modo. Aggiungiamo una variabile locale chiamata nPacchetti ai principale funzione. inizializzeremo
esso a uno per abbinare il nostro comportamento predefinito precedente. Per consentire al parser della riga di comando di
cambia questo valore, dobbiamo agganciare il valore al parser. Lo facciamo aggiungendo una chiamata
a Aggiungere valore. Vai avanti e cambia il gratta/ilmioprimo.cc script per iniziare con il
seguente codice,

int
principale (int argc, char *argv[])
{
uint32_t nPacchetti = 1;

Riga di comando cmd;
cmd.AddValue("nPackets", "Numero di pacchetti da echo", nPackets);
cmd.Parse (argc, argv);

...

Scorri verso il basso fino al punto dello script in cui impostiamo il MaxPackets Attributo e cambialo
in modo che sia impostato sulla variabile nPacchetti invece della costante 1 come mostrato di seguito.

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

Ora, se esegui lo script e fornisci il --Aiuto per la stampa argomento, dovresti vedere il tuo nuovo
Utente Argomento elencati nella schermata della guida.

Provare,

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

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.403s)
--PrintHelp: stampa questo messaggio di aiuto.
--PrintGroups: stampa l'elenco dei gruppi.
--PrintTypeIds: stampa tutti i TypeId.
--PrintGroup=[group]: stampa tutti i TypeId del gruppo.
--PrintAttributes=[typeid]: stampa tutti gli attributi di typeid.
--PrintGlobals: stampa l'elenco dei globali.
Argomenti dell'utente:
--nPacchetti: numero di pacchetti di cui eseguire l'eco

Se vuoi specificare il numero di pacchetti di cui eseguire l'eco, ora puoi farlo impostando il pulsante
--nPacchetti argomento nella riga di comando,

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

Dovresti vedere ora

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.404s)
0s UdpEchoServerApplicazione:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Inviati 1024 byte a 10.1.1.2
2.25732s Ricevuti 1024 byte da 10.1.1.1
2.25732s Pacchetto eco
Ricevuto 1024 byte da 10.1.1.2
Inviati 1024 byte a 10.1.1.2
3.25732s Ricevuti 1024 byte da 10.1.1.1
3.25732s Pacchetto eco
Ricevuto 1024 byte da 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
Applicazione UdpEchoServer:~UdpEchoServer()

Ora hai echeggiato due pacchetti. Abbastanza facile, non è vero?

Puoi vedere che se sei un NS-3 utente, è possibile utilizzare il sistema di argomenti della riga di comando per
controllare i valori globali e Attributi. Se sei un autore di modelli, puoi aggiungerne di nuovi
Attributi alla tua Oggetti e saranno automaticamente disponibili per l'impostazione da parte tua
utenti tramite il sistema a riga di comando. Se sei un autore di script, puoi aggiungerne di nuovi
variabili ai tuoi script e collegarli al sistema della riga di comando in modo abbastanza indolore.

utilizzando , il Tracciato Sistema
Il punto centrale della simulazione è generare output per ulteriori studi e il NS-3
il sistema di tracciamento è un meccanismo primario per questo. Da quando NS-3 è un programma C++, standard
potrebbero essere utilizzate le strutture per generare output da programmi C++:

#includere
...
intero principale ()
{
...
std::cout << "Il valore di x è " << x << std::endl;
...
}

Potresti anche usare il modulo di registrazione per aggiungere una piccola struttura alla tua soluzione. Là
sono molti noti problemi generati da tali approcci e quindi abbiamo fornito un
sottosistema generico di tracciamento degli eventi per affrontare i problemi che ritenevamo importanti.

Gli obiettivi fondamentali del NS-3 sistema di tracciamento sono:

· Per le attività di base, il sistema di tracciamento dovrebbe consentire all'utente di generare tracciati standard
per le fonti di tracciamento più diffuse e per personalizzare gli oggetti che generano la traccia;

· Gli utenti intermedi devono essere in grado di estendere il sistema di tracciamento per modificare il formato di output
generato, o per inserire nuove fonti di tracciamento, senza modificare il nucleo del
simulatore;

· Gli utenti avanzati possono modificare il core del simulatore per aggiungere nuove fonti di tracciamento e sink.

Le NS-3 sistema di tracciamento è costruito sui concetti di fonti di tracciamento indipendenti e
tracciamento dei lavandini e un meccanismo uniforme per collegare le sorgenti ai lavandini. Le fonti di traccia sono
entità che possono segnalare eventi che accadono in una simulazione e fornire accesso a
dati di fondo interessanti. Ad esempio, una fonte di traccia potrebbe indicare quando un pacchetto è
ricevuto da un dispositivo di rete e fornire accesso al contenuto del pacchetto per la traccia interessata
lavandini.

Le fonti di traccia non sono utili da sole, devono essere "collegate" ad altri pezzi di
codice che effettivamente fa qualcosa di utile con le informazioni fornite dal sink. Traccia
i sink sono consumatori degli eventi e dei dati forniti dalle origini di traccia. Per esempio,
si potrebbe creare un sink di traccia che (quando connesso alla sorgente di traccia del
esempio precedente) stampare parti interessanti del pacchetto ricevuto.

La logica di questa divisione esplicita è quella di consentire agli utenti di collegare nuovi tipi di lavelli a
fonti di tracciamento esistenti, senza richiedere la modifica e la ricompilazione del nucleo del
simulatore. Quindi, nell'esempio sopra, un utente potrebbe definire un nuovo sink di tracciamento in lei
script e collegarlo a una sorgente di traccia esistente definita nel core di simulazione da
modificando solo lo script utente.

In questo tutorial, esamineremo alcune sorgenti e sink predefiniti e mostreremo come
possono essere personalizzati con poco sforzo da parte dell'utente. Vedere il manuale ns-3 o le sezioni how-to
per informazioni sulla configurazione avanzata della traccia, inclusa l'estensione della traccia
spazio dei nomi e la creazione di nuove origini di traccia.

ASCII Tracciato
NS-3 fornisce funzionalità di supporto che avvolgono il sistema di tracciamento di basso livello per aiutarti
con i dettagli coinvolti nella configurazione di alcune tracce di pacchetti facilmente comprensibili. Se tu
abilita questa funzionalità, vedrai l'output in un file ASCII --- quindi il nome. Per
chi ha familiarità con NS-2 uscita, questo tipo di traccia è analogo al fuori.tr generato
da molti script.

Facciamo un salto e aggiungiamo un po 'di output di tracciamento ASCII al nostro gratta/ilmioprimo.cc
sceneggiatura. Subito prima della chiamata a Simulatore::Esegui (), aggiungi le seguenti righe di codice:

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

Come in tanti altri NS-3 idiomi, questo codice utilizza un oggetto di supporto per aiutare a creare ASCII
tracce. La seconda riga contiene due chiamate di metodo annidate. Il metodo "dentro",
CreaFileStream() usa un idioma di oggetto senza nome per creare un oggetto flusso di file sul
stack (senza un nome di oggetto) e passarlo al metodo chiamato. Entriamo in questo
più in futuro, ma tutto quello che devi sapere a questo punto è che stai creando un
oggetto che rappresenta un file chiamato "myfirst.tr" e lo passa dentro NS-3. stai dicendo
NS-3 per affrontare i problemi di durata dell'oggetto creato e anche per affrontare i problemi
causato da una limitazione poco nota (intenzionale) del C++ degli oggetti di flusso relativi alla copia
costruttori.

La chiamata esterna, a AbilitaAsciiTutto(), dice all'helper che vuoi abilitare ASCII
tracciamento su tutti i dispositivi punto-punto nella simulazione; e vuoi il (fornito)
trace sink per scrivere informazioni sullo spostamento dei pacchetti in formato ASCII.

Per chi ha familiarità con NS-2, gli eventi tracciati sono equivalenti ai popolari punti traccia
che registrano gli eventi "+", "-", "d" e "r".

Ora puoi creare lo script ed eseguirlo dalla riga di comando:

$ ./waf --run scratch/myfirst

Proprio come hai visto molte volte prima, vedrai alcuni messaggi da Waf e poi
"'build' è terminato con successo" con un certo numero di messaggi dal programma in esecuzione.

Quando è stato eseguito, il programma avrà creato un file denominato il mio primo.tr. A causa del modo
che Waf funzioni, il file non viene creato nella directory locale, viene creato al
directory di primo livello del repository per impostazione predefinita. Se vuoi controllare dove si trovano le tracce
sono salvati è possibile utilizzare il --cwd opzione di Waf per specificarlo. Non lo abbiamo fatto, quindi
dobbiamo passare alla directory di primo livello del nostro repository e dare un'occhiata all'ASCII
file di traccia il mio primo.tr nel tuo editor preferito.

parsing Ascii tracce
Ci sono molte informazioni lì in una forma piuttosto densa, ma la prima cosa da notare
è che ci sono un certo numero di righe distinte in questo file. Potrebbe essere difficile da vedere
questo chiaramente a meno che non allarghi considerevolmente la finestra.

Ogni riga nel file corrisponde a a tracciare evento. In questo caso stiamo tracciando gli eventi su
, il trasmettere fare la coda presente in ogni dispositivo di rete punto-punto nella simulazione. Il
la coda di trasmissione è una coda attraverso la quale ogni pacchetto destinato a un canale punto-punto
deve passare. Nota che ogni riga nel file di traccia inizia con un carattere solitario (ha un
spazio dopo di esso). Questo carattere avrà il seguente significato:

· +: si è verificata un'operazione di accodamento sulla coda del dispositivo;

· -: si è verificata un'operazione di rimozione dalla coda sulla coda del dispositivo;

· d: un pacchetto è stato eliminato, in genere perché la coda era piena;

· r: Un pacchetto è stato ricevuto dal dispositivo di rete.

Diamo una visione più dettagliata della prima riga nel file di traccia. lo spezzerò
in sezioni (indentate per chiarezza) con un numero di riferimento sul lato sinistro:

+
2
/ElencoNodi/0/ElencoDispositivi/0/$ns3::DispositivoRetePuntoAPunto/TxQueue/Enqueue
ns3::PppHeader (
Protocollo punto-punto: IP (0x0021))
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 protocollo 17 offset 0 flag [nessuno]
lunghezza: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
lunghezza: 1032 49153 > 9)
Carico utile (dimensioni = 1024)

La prima sezione di questo evento di traccia espanso (numero di riferimento 0) è l'operazione. Noi
hanno + carattere, quindi questo corrisponde ad an enqueue operazione sulla coda di trasmissione.
La seconda sezione (riferimento 1) è il tempo di simulazione espresso in secondi. Potresti
ricordiamo che abbiamo chiesto al Applicazione UdpEchoClient per avviare l'invio dei pacchetti dopo due secondi.
Qui vediamo la conferma che questo sta effettivamente accadendo.

La sezione successiva della traccia di esempio (riferimento 2) ci dice quale fonte di traccia ha avuto origine
questo evento (espresso nello spazio dei nomi di traccia). Puoi pensare allo spazio dei nomi di tracciamento
un po' come faresti con uno spazio dei nomi del filesystem. La radice dello spazio dei nomi è il
Elenco dei nodi. Corrisponde a un contenitore gestito nel NS-3 codice principale che contiene tutto
dei nodi che vengono creati in uno script. Proprio come un filesystem può avere directory
sotto la radice, potremmo avere numeri di nodo nel Elenco dei nodi. La stringa /Elenco nodi/0
si riferisce quindi al nodo zero nel Elenco dei nodi che in genere pensiamo come "nodo
0". In ogni nodo c'è un elenco di dispositivi che sono stati installati. Appare questo elenco
successivo nello spazio dei nomi. Puoi vedere che questo evento di traccia viene da Elenco dispositivi/0 che è
il dispositivo zero installato nel nodo.

La stringa successiva, $ns3::DispositivoPointToPointNet ti dice che tipo di dispositivo è nel
posizione zero della lista dei dispositivi per il nodo zero. Ricordiamo che l'operazione + Trovato a
riferimento 00 significava che si è verificata un'operazione di accodamento sulla coda di trasmissione del dispositivo.
Ciò si riflette nei segmenti finali del "percorso della traccia" che sono TxCoda/accodamento.

Le sezioni rimanenti nella traccia dovrebbero essere abbastanza intuitive. I riferimenti 3-4 indicano
che il pacchetto è incapsulato nel protocollo point-to-point. I riferimenti 5-7 mostrano che
il pacchetto ha un'intestazione IP versione quattro e ha avuto origine dall'indirizzo IP 10.1.1.1 e
è destinato al 10.1.1.2. I riferimenti 8-9 mostrano che questo pacchetto ha un'intestazione UDP e,
infine, il riferimento 10 mostra che il carico utile è i 1024 byte previsti.

La riga successiva nel file di traccia mostra lo stesso pacchetto che viene rimosso dalla coda dalla trasmissione
coda sullo stesso nodo.

La terza riga nel file di traccia mostra il pacchetto ricevuto dal dispositivo di rete sul
nodo con il server echo. Ho riprodotto quell'evento di seguito.

r
2.25732
/ElencoNodi/1/ElencoDispositivi/0/$ns3::DispositivoRetePuntoAPunto/MacRx
ns3::Ipv4Header (
tos 0x0 ttl 64 id 0 protocollo 17 offset 0 flag [nessuno]
lunghezza: 1052 10.1.1.1 > 10.1.1.2)
ns3::UdpHeader (
lunghezza: 1032 49153 > 9)
Carico utile (dimensioni = 1024)

Notare che l'operazione di traccia è ora r e il tempo di simulazione è aumentato a 2.25732
secondi. Se hai seguito da vicino i passaggi del tutorial, significa che hai
lasciato il Velocità dati dei dispositivi di rete e del canale Ritardo impostati sui loro valori predefiniti.
Questa volta dovrebbe essere familiare come l'hai vista prima in una sezione precedente.

La voce dello spazio dei nomi di origine della traccia (riferimento 02) è stata modificata per riflettere che questo evento è
proveniente dal nodo 1 (/Elenco nodi/1) e l'origine della traccia di ricezione dei pacchetti (/MacRx). è
dovrebbe essere abbastanza facile per te seguire l'andamento del pacchetto attraverso la topologia di
guardando il resto delle tracce nel file.

PCAP Tracciato
Le NS-3 gli helper del dispositivo possono essere utilizzati anche per creare file di traccia nel .pcap formato. Il
l'acronimo pcap (di solito scritto in minuscolo) sta per packet capture, ed è in realtà an
API che include la definizione di a .pcap formato del file. Il programma più popolare che
può leggere e visualizzare questo formato è Wireshark (precedentemente chiamato Ethereal). Tuttavia, c'è
ci sono molti analizzatori di tracce di traffico che utilizzano questo formato di pacchetto. Incoraggiamo gli utenti a
sfruttare i numerosi strumenti disponibili per analizzare le tracce di pcap. In questo tutorial, noi
concentrati sulla visualizzazione delle tracce di pcap con tcpdump.

Il codice utilizzato per abilitare la traccia di pcap è a una riga.

pointToPoint.EnablePcapAll ("il mio primo");

Vai avanti e inserisci questa riga di codice dopo il codice di tracciamento ASCII che abbiamo appena aggiunto
gratta/ilmioprimo.cc. Nota che abbiamo passato solo la stringa "myfirst" e not
"myfirst.pcap" o qualcosa di simile. Questo perché il parametro è un prefisso, non un
nome completo del file. L'helper creerà effettivamente un file di traccia per ogni punto a punto
dispositivo nella simulazione. I nomi dei file verranno creati utilizzando il prefisso, il numero di nodo,
il numero del dispositivo e un suffisso ".pcap".

Nel nostro script di esempio, alla fine vedremo file denominati "myfirst-0-0.pcap" e
"myfirst-1-0.pcap" che sono le tracce pcap per il nodo 0-dispositivo 0 e il nodo 1-dispositivo 0,
rispettivamente.

Dopo aver aggiunto la riga di codice per abilitare la traccia di pcap, puoi eseguire lo script nel
modo solito:

$ ./waf --run scratch/myfirst

Se guardi la directory di primo livello della tua distribuzione, ora dovresti vedere tre log
File: il mio primo.tr è il file di traccia ASCII che abbiamo esaminato in precedenza. mioprimo-0-0.pcap
che a mioprimo-1-0.pcap sono i nuovi file pcap che abbiamo appena generato.

Lettura produzione con tcpdump
La cosa più semplice da fare a questo punto sarà usare tcpdump guardare il pcap File.

$ tcpdump -nn -tt -r mioprimo-0-0.pcap
lettura dal file myfirst-0-0.pcap, PPP di tipo collegamento (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, lunghezza 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, lunghezza 1024

tcpdump -nn -tt -r mioprimo-1-0.pcap
lettura dal file myfirst-1-0.pcap, PPP di tipo collegamento (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, lunghezza 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Puoi vedere nella discarica di mioprimo-0-0.pcap (il dispositivo client) che il pacchetto echo è
inviato a 2 secondi dall'inizio della simulazione. Se guardi il secondo dump (mioprimo-1-0.pcap)
puoi vedere che il pacchetto viene ricevuto a 2.257324 secondi. Vedi che il pacchetto è
ha fatto eco a 2.257324 secondi nel secondo dump e, infine, vedi il pacchetto essere
ricevuto al client nel primo dump a 2.514648 secondi.

Lettura produzione con Wireshark
Se non hai familiarità con Wireshark, è disponibile un sito web da cui puoi
scarica programmi e documentazione: http://www.wireshark.org/.

Wireshark è un'interfaccia utente grafica che può essere utilizzata per visualizzare queste tracce
File. Se disponi di Wireshark, puoi aprire ciascuno dei file di traccia e visualizzarlo
il contenuto come se avessi catturato i pacchetti usando a pacchetto sniffer.

EDILIZIA TOPOLOGIE


Costruzione a L'Autobus Network NetPoulSafe Topologia
In questa sezione andremo ad espandere la nostra padronanza di NS-3 dispositivi di rete e canali per
coprire un esempio di una rete di autobus. NS-3 fornisce un dispositivo di rete e un canale che chiamiamo CSMA
(Accesso multiplo per il rilevamento dell'operatore).

Le NS-3 Il dispositivo CSMA modella una rete semplice nello spirito di Ethernet. Una vera Ethernet
utilizza lo schema CSMA/CD (Carrier Sense Multiple Access with Collision Detection) con
backoff esponenzialmente crescente per contendersi il mezzo di trasmissione condiviso. Il NS-3
Il dispositivo CSMA e i modelli di canale sono solo un sottoinsieme di questo.

Proprio come abbiamo visto gli oggetti helper della topologia punto-punto durante la costruzione
topologie punto-punto, in questa sezione verranno visualizzati gli helper per la topologia CSMA equivalenti.
L'aspetto e il funzionamento di questi aiutanti dovrebbero sembrarti abbastanza familiari.

Forniamo uno script di esempio nella nostra directory esempi/tutorial}. Questo script si basa su
, il prima.cc script e aggiunge una rete CSMA alla simulazione punto-punto che abbiamo già
considerato. Vai avanti e apri esempi/tutorial/secondo.cc nel tuo editor preferito. Voi
avrà già visto abbastanza NS-3 codice per capire la maggior parte di cosa sta succedendo in questo
esempio, ma esamineremo l'intero script ed esamineremo parte dell'output.

Proprio come nel prima.cc esempio (e in tutti gli esempi ns-3) il file inizia con un emacs
mode line e alcuni boilerplate GPL.

Il codice effettivo inizia caricando i file del modulo include proprio come è stato fatto nel prima.cc
esempio.

#include "ns3/core-module.h"
#include "ns3/modulo-rete.h"
#include "ns3/csma-module.h"
#include "ns3/internet-module.h"
#include "ns3/punto-punto-modulo.h"
#include "ns3/applications-module.h"
#include "ns3/ipv4-global-routing-helper.h"

Una cosa che può essere sorprendentemente utile è un po' di arte ASCII che mostra un cartone animato
della topologia di rete costruita nell'esempio. Troverai un "disegno" simile in
la maggior parte dei nostri esempi.

In questo caso, puoi vedere che estenderemo il nostro esempio point-to-point (il link
tra i nodi n0 e n1 sotto) appendendo una rete di bus dal lato destro. Avviso
che questa è la topologia di rete predefinita poiché puoi effettivamente variare il numero di nodi
creato sulla LAN. Se imposti nCsma su uno, ci saranno un totale di due nodi sul
LAN (canale CSMA) --- un nodo richiesto e un nodo "extra". Di default ce ne sono tre
nodi "extra" come mostrato di seguito:

// Topologia di rete predefinita
//
// 10.1.1.0
// n0 -------------- n1 n2 n3 n4
// da punto a punto | | | |
// ==================
// LAN 10.1.2.0

Quindi lo spazio dei nomi ns-3 è utilizzato e viene definito un componente di registrazione. Tutto questo è proprio come
era dentro prima.cc, quindi non c'è ancora nulla di nuovo.

usando lo spazio dei nomi ns3;

NS_LOG_COMPONENT_DEFINE ("SecondScriptExample");

Il programma principale inizia con una svolta leggermente diversa. Usiamo un flag verboso per
determinare se il Applicazione UdpEchoClient che a UdpEchoServerApplicazione registrazione
i componenti sono abilitati. Questo flag è impostato su true (i componenti di registrazione sono abilitati)
ma ci consente di disattivare la registrazione durante i test di regressione di questo esempio.

Vedrai un codice familiare che ti permetterà di cambiare il numero di dispositivi sul
Rete CSMA tramite argomento della riga di comando. Abbiamo fatto qualcosa di simile quando abbiamo permesso il
numero di pacchetti inviati da modificare nella sezione sugli argomenti della riga di comando. L'ultimo
line si assicura di avere almeno un nodo "extra".

Il codice è costituito da variazioni dell'API precedentemente coperta, quindi dovresti essere completamente
a mio agio con il seguente codice a questo punto del tutorial.

bool verbose = vero;
uint32_t nCsma = 3;

Riga di comando cmd;
cmd.AddValue ("nCsma", "Numero di nodi/dispositivi CSMA \"extra\", nCsma);
cmd.AddValue ("verbose", "Di' alle applicazioni echo di accedere se è vero", verbose);

cmd.Parse (argc, argv);

se (verboso)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

nCsma = nCsma == 0 ? 1: nCsma;

Il prossimo passo è creare due nodi che collegheremo tramite il collegamento punto-punto.
Le NodoContenitore è usato per fare questo proprio come è stato fatto in prima.cc.

NodeContenitore p2pNodes;
p2pNodes.Crea (2);

Successivamente, ne dichiariamo un altro NodoContenitore per contenere i nodi che faranno parte del bus
rete (CSMA). Innanzitutto, istanziamo semplicemente l'oggetto contenitore stesso.

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

La prossima riga di codice Ottiene il primo nodo (come nell'avere un indice di uno) dal
contenitore di nodi punto-punto e lo aggiunge al contenitore di nodi che otterranno CSMA
dispositivi. Il nodo in questione finirà con un dispositivo punto-punto che a un CSMA
dispositivo. Creiamo quindi una serie di nodi "extra" che compongono il resto del CSMA
Rete. Poiché abbiamo già un nodo nella rete CSMA, quello che avrà
sia un dispositivo di rete punto-punto che CSMA, il numero di nodi "extra" significa il numero
nodi desiderati nella sezione CSMA meno uno.

Il prossimo pezzo di codice dovrebbe essere abbastanza familiare ormai. Istanziamo a PuntoAPuntoHelper
e imposta il valore predefinito associato Attributi in modo da creare cinque megabit al secondo
trasmettitore sui dispositivi creati utilizzando l'helper e un ritardo di due millisecondi sui canali
creato dall'aiutante.

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

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

Quindi istanziamo a NetDeviceContenitore per tenere traccia dei dispositivi di rete punto-punto
e noi Installazione dispositivi sui nodi punto-punto.

Abbiamo menzionato sopra che avresti visto un helper per dispositivi e canali CSMA e
le righe successive le introducono. Il CsmaHelper funziona proprio come un PuntoAPuntoHelper, ma
crea e collega dispositivi e canali CSMA. Nel caso di un dispositivo CSMA e
coppia di canali, notare che la velocità dei dati è specificata da a canale Attributo invece di a
dispositivo Attributo. Questo perché una vera rete CSMA non consente di mischiarsi, per
esempio, dispositivi 10Base-T e 100Base-T su un determinato canale. Per prima cosa impostiamo la velocità dei dati su
100 megabit al secondo, quindi impostare il ritardo della velocità della luce del canale su 6560
nanosecondi (scelto arbitrariamente come 1 nanosecondo per piede su un segmento di 100 metri).
Nota che puoi impostare un Attributo utilizzando il suo tipo di dati nativo.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

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

Proprio come abbiamo creato un NetDeviceContenitore per contenere i dispositivi creati dal
PuntoAPuntoHelper creiamo un file NetDeviceContenitore per contenere i dispositivi creati dal nostro
CsmaHelper. chiamiamo il Installazione metodo del CsmaHelper per installare i dispositivi nel
nodi di csmaNodi NodoContenitore.

Ora abbiamo i nostri nodi, dispositivi e canali creati, ma non abbiamo stack di protocollo
regalo. Proprio come nel prima.cc script, useremo il Internet StackHelper installare
queste pile.

Stack di InternetStackHelper;
stack.Install (p2pNodes.Get (0));
stack.Install (csmaNodes);

Ricordiamo che abbiamo preso uno dei nodi dal p2pNodi contenitore e lo aggiunse al
csmaNodi contenitore. Quindi abbiamo solo bisogno di installare gli stack sui restanti p2pNodi
nodo e tutti i nodi nel csmaNodi contenitore per coprire tutti i nodi nel
simulazione.

Proprio come nel prima.cc script di esempio, useremo il IPv4AddressHelper a
assegnare indirizzi IP alle interfacce dei nostri dispositivi. Per prima cosa usiamo la rete 10.1.1.0 per creare
i due indirizzi necessari per i nostri due dispositivi punto-punto.

Ipv4AddressIndirizzo dell'assistente;
indirizzo.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContenitore p2pInterfaces;
p2pInterfaces = indirizzo.Assign (p2pDevices);

Ricordiamo che salviamo le interfacce create in un contenitore per facilitarne l'estrazione
indirizzare le informazioni in un secondo momento da utilizzare nella configurazione delle applicazioni.

Ora dobbiamo assegnare gli indirizzi IP alle nostre interfacce del dispositivo CSMA. L'operazione funziona
proprio come ha fatto per il caso punto-punto, tranne per il fatto che ora stiamo eseguendo l'operazione su
un contenitore che ha un numero variabile di dispositivi CSMA --- ricorda che abbiamo fatto il numero di
Dispositivi CSMA modificabili tramite l'argomento della riga di comando. I dispositivi CSMA saranno associati
con indirizzi IP dal numero di rete 10.1.2.0 in questo caso, come mostrato di seguito.

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

Ora abbiamo creato una topologia, ma abbiamo bisogno di applicazioni. Questa sezione sarà
fondamentalmente simile alla sezione delle applicazioni di prima.cc ma stiamo per
istanziare il server su uno dei nodi che ha un dispositivo CSMA e il client sul
nodo avente solo un dispositivo punto-punto.

Per prima cosa, impostiamo il server echo. Creiamo un UdpEchoServerHelper e fornire una richiesta
Attributo valore al costruttore che è il numero di porta del server. Ricordiamo che questo porto
può essere modificato in seguito utilizzando il Imposta attributo metodo se lo si desidera, ma è necessario che sia
fornito al costruttore.

UdpEchoServerHelper echoServer (9);

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

Ricordiamo che il csmaNodi NodoContenitore contiene uno dei nodi creati per il
rete punto-punto e nCsma nodi "aggiuntivi". Quello a cui vogliamo arrivare è l'ultimo dei
nodi "aggiuntivi". L'entrata zero del csmaNodi il contenitore sarà il punto-punto
nodo. Il modo più semplice per pensare a questo, quindi, è se creiamo un nodo CSMA "extra", allora esso
sarà all'indice uno dei csmaNodi contenitore. Per induzione, se creiamo nCsma "extra"
nodi l'ultimo sarà all'indice nCsma. Lo vedi esposto nel Ottieni del primo
riga di codice.

L'applicazione client è impostata esattamente come abbiamo fatto in prima.cc sceneggiatura di esempio. Ancora,
forniamo richiesto Attributi ai UdpEchoClientHelper nel costruttore (in questo caso
l'indirizzo remoto e la porta). Diciamo al client di inviare i pacchetti al server che abbiamo appena
installato sull'ultimo dei nodi CSMA "extra". Installiamo il client più a sinistra
nodo punto-punto visto nell'illustrazione della topologia.

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

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

Dal momento che abbiamo effettivamente costruito un'internetwork qui, abbiamo bisogno di una qualche forma di internetwork
di routing. NS-3 fornisce ciò che chiamiamo routing globale per aiutarti. Il routing globale richiede
vantaggio del fatto che l'intera internetwork è accessibile nella simulazione e
attraversa tutti i nodi creati per la simulazione --- fa il duro lavoro di
impostare il routing per te senza dover configurare i router.

Fondamentalmente, ciò che accade è che ogni nodo si comporta come se fosse un router OSPF che
comunica istantaneamente e magicamente con tutti gli altri router dietro le quinte. Ogni nodo
genera annunci di collegamento e li comunica direttamente a un route manager globale
che utilizza queste informazioni globali per costruire le tabelle di instradamento per ogni nodo. Collocamento
questa forma di routing è una riga:

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Quindi abilitiamo la traccia di pcap. La prima riga di codice per abilitare la traccia di pcap nel
l'helper point-to-point dovrebbe esserti familiare ormai. La seconda riga abilita pcap
traccia nell'helper CSMA e c'è un parametro extra che non hai ancora incontrato.

pointToPoint.EnablePcapAll ("secondo");
csma.EnablePcap ("secondo", csmaDevices.Get (1), vero);

La rete CSMA è una rete multi-point-to-point. Ciò significa che possono (e sono in
questo caso) più endpoint su un supporto condiviso. Ciascuno di questi endpoint ha una rete
dispositivo ad esso associato. Ci sono due alternative di base alla raccolta di tracce
informazioni da tale rete. Un modo è creare un file di traccia per ogni dispositivo di rete
e memorizzare solo i pacchetti emessi o consumati da quel dispositivo di rete. Un altro modo
è scegliere uno dei dispositivi e metterlo in modalità promiscua. Quel singolo dispositivo allora
"sniffa" la rete per tutti i pacchetti e li memorizza in un singolo file pcap. Questo è come
tcpdump, per esempio, funziona. Questo parametro finale dice all'helper CSMA se farlo o no
organizzare la cattura dei pacchetti in modalità promiscua.

In questo esempio, selezioneremo uno dei dispositivi sulla rete CSMA e lo chiederemo
eseguire un'annusata promiscua della rete, emulando così ciò che tcpdump farebbe.
Se fossi su una macchina Linux potresti fare qualcosa del genere tcpdump -i eth0 prendere il
traccia. In questo caso, specifichiamo il dispositivo usando csmaDevices.Get(1), che seleziona il
primo dispositivo nel contenitore. L'impostazione del parametro finale su true abilita promiscua
catture.

L'ultima sezione del codice viene eseguita e ripulisce la simulazione proprio come la prima.cc
esempio.

Simulatore::Esegui ();
Simulatore::Distruggi ();
0 ritorno;
}

Per eseguire questo esempio, copiare il file secondo.cc script di esempio nella directory scratch
e usa waf per costruire proprio come hai fatto con il prima.cc esempio. Se sei nel
directory di primo livello del repository appena digitato,

$ cp esempi/tutorial/secondo.cc scratch/miosecondo.cc
$ ./waf

Attenzione: usiamo il file secondo.cc come uno dei nostri test di regressione per verificare che funzioni
esattamente come pensiamo che dovrebbe per rendere positiva la tua esperienza di tutorial.
Ciò significa che un eseguibile denominato secondo esiste già nel progetto. Per evitare qualsiasi
confusione su ciò che stai eseguendo, per favore rinominalo in miosecondo.cc suggerimenti
sopra.

Se stai seguendo religiosamente il tutorial (lo sei, non è vero) lo avrai comunque
la variabile NS_LOG impostata, quindi vai avanti e cancella quella variabile ed esegui il programma.

$ esportazione NS_LOG=
$ ./waf --run scratch/miosecondo

Dal momento che abbiamo impostato le applicazioni echo UDP per l'accesso proprio come abbiamo fatto noi prima.cc,
vedere un output simile quando si esegue lo script.

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.415s)
Inviati 1024 byte a 10.1.2.4
Ricevuto 1024 byte da 10.1.1.1
Ricevuto 1024 byte da 10.1.2.4

Ricordiamo che il primo messaggio, "Inviati 1024 bytes a 10.1.2.4," è il client echo UDP
inviare un pacchetto al server. In questo caso, il server si trova su una rete diversa
(10.1.2.0). Il secondo messaggio, "ricevuto 1024 bytes da 10.1.1.1," proviene dall'eco UDP
server, generato quando riceve il pacchetto echo. Il messaggio finale, "ricevuto 1024
bytes da 10.1.2.4," proviene dal client echo, indicando che ha ricevuto il suo echo
ritorno dal server.

Se ora vai a cercare nella directory di primo livello, troverai tre file di traccia:

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

Prendiamoci un momento per dare un'occhiata alla denominazione di questi file. Hanno tutti la stessa forma,
- - .pcap. Ad esempio, il primo file nell'elenco è
secondo-0-0.pcap che è la traccia pcap dal nodo zero, dispositivo zero. Questo è il
dispositivo di rete punto-punto sul nodo zero. Il file secondo-1-0.pcap è la traccia pcap per
dispositivo zero sul nodo uno, anch'esso dispositivo di rete punto-punto; e il file secondo-2-0.pcap is
la traccia pcap per il dispositivo zero sul nodo due.

Se fai riferimento all'illustrazione della topologia all'inizio della sezione, vedrai
quel nodo zero è il nodo più a sinistra del collegamento punto-punto e il nodo uno è il nodo
che ha sia un dispositivo punto-punto che un dispositivo CSMA. Vedrai che il nodo due è
il primo nodo "extra" sulla rete CSMA e il suo dispositivo zero è stato selezionato come dispositivo
per catturare la traccia in modalità promiscua.

Ora, seguiamo il pacchetto echo attraverso la rete. Per prima cosa, esegui un tcpdump di
file di traccia per il nodo punto-punto più a sinistra --- nodo zero.

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

Dovresti vedere il contenuto del file pcap visualizzato:

lettura dal file second-0-0.pcap, PPP di tipo collegamento (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

La prima riga del dump indica che il tipo di collegamento è PPP (point-to-point) che noi
aspettarsi. Quindi vedi il pacchetto echo che lascia il nodo zero tramite il dispositivo associato all'IP
indirizzo 10.1.1.1 per indirizzo IP 10.1.2.4 (il nodo CSMA più a destra). Questo pacchetto
si sposterà sul collegamento punto-punto e sarà ricevuto dal dispositivo di rete punto-punto acceso
nodo uno. Diamo un'occhiata:

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

Ora dovresti vedere l'output di traccia pcap dell'altro lato del collegamento punto-punto:

lettura dal file second-1-0.pcap, PPP di tipo collegamento (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Qui vediamo che anche il tipo di collegamento è PPP come ci aspetteremmo. Vedi il pacchetto dall'IP
indirizzo 10.1.1.1 (che è stato inviato a 2.000000 secondi) diretto verso l'indirizzo IP 10.1.2.4
appaiono su questa interfaccia. Ora, internamente a questo nodo, il pacchetto verrà inoltrato a
l'interfaccia CSMA e dovremmo vederlo apparire su quel dispositivo per il suo ultimo
destinazione.

Ricorda che abbiamo selezionato il nodo 2 come nodo sniffer promiscuo per la rete CSMA, quindi
diamo quindi un'occhiata a second-2-0.pcap e vediamo se c'è.

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

Ora dovresti vedere il dump promiscuo del nodo due, dispositivo zero:

lettura dal file second-2-0.pcap, tipo collegamento EN10MB (Ethernet)
2.007698 ARP, Richiedi chi-ha 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, lunghezza 50
2.007710 ARP, risposta 10.1.2.4 è alle 00:00:00:00:00:06, lunghezza 50
2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.013815 ARP, Richiedi chi-ha 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, lunghezza 50
2.013828 ARP, risposta 10.1.2.1 è alle 00:00:00:00:00:03, lunghezza 50
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Come puoi vedere, il tipo di collegamento ora è "Ethernet". Qualcosa di nuovo è apparso, però. Il
esigenze della rete di autobus ARP, il Protocollo di risoluzione degli indirizzi. Il nodo uno sa che deve inviare
il pacchetto all'indirizzo IP 10.1.2.4, ma non conosce l'indirizzo MAC del
nodo corrispondente. Trasmette sulla rete CSMA (ff:ff:ff:ff:ff:ff) chiedendo il
dispositivo con indirizzo IP 10.1.2.4. In questo caso, il nodo più a destra risponde dicendolo
è all'indirizzo MAC 00:00:00:00:00:06. Nota che il nodo due non è direttamente coinvolto in questo
exchange, ma sta annusando la rete e segnalando tutto il traffico che vede.

Questo scambio è visto nelle righe seguenti,

2.007698 ARP, Richiedi chi-ha 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, lunghezza 50
2.007710 ARP, risposta 10.1.2.4 è alle 00:00:00:00:00:06, lunghezza 50

Quindi il nodo uno, il dispositivo uno va avanti e invia il pacchetto echo al server echo UDP a
Indirizzo IP 10.1.2.4.

2.007803 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024

Il server riceve la richiesta di eco e gira il pacchetto cercando di rispedirlo a
la fonte. Il server sa che questo indirizzo si trova su un'altra rete che raggiunge tramite
Indirizzo IP 10.1.2.1. Questo perché abbiamo inizializzato il routing globale e ha capito tutto
di questo fuori per noi. Ma il nodo del server echo non conosce l'indirizzo MAC del primo
nodo CSMA, quindi deve eseguire l'ARP proprio come doveva fare il primo nodo CSMA.

2.013815 ARP, Richiedi chi-ha 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, lunghezza 50
2.013828 ARP, risposta 10.1.2.1 è alle 00:00:00:00:00:03, lunghezza 50

Il server quindi invia l'eco al nodo di inoltro.

2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Guardando indietro al nodo più a destra del collegamento punto-punto,

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

Ora puoi vedere il pacchetto echo che ritorna sul collegamento punto-punto come l'ultimo
riga del dump della traccia.

lettura dal file second-1-0.pcap, PPP di tipo collegamento (PPP)
2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.013921 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Infine, puoi guardare indietro al nodo che ha originato l'eco

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

e vedere che il pacchetto echo ritorna alla sorgente a 2.007602 secondi,

lettura dal file second-0-0.pcap, PPP di tipo collegamento (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.017607 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Ricordiamo infine che abbiamo aggiunto la possibilità di controllare il numero di dispositivi CSMA nel
simulazione per argomento della riga di comando. Puoi cambiare questo argomento allo stesso modo di quando
abbiamo esaminato la modifica del numero di pacchetti echeggiati nel prima.cc esempio. prova a correre
il programma con il numero di dispositivi "extra" impostato su quattro:

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

ora dovresti vedere,

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.405s)
Al momento il client 2s ha inviato 1024 byte alla porta 10.1.2.5 9
Al momento il server 2.0118s ha ricevuto 1024 byte dalla porta 10.1.1.1 49153
Al momento il server 2.0118s ha inviato 1024 byte alla porta 10.1.1.1 49153
Al momento il client 2.02461s ha ricevuto 1024 byte dalla porta 10.1.2.5 9

Notare che il server echo è stato ora riposizionato nell'ultimo dei nodi CSMA, che è
10.1.2.5 invece del caso predefinito, 10.1.2.4.

È possibile che tu non sia soddisfatto di un file di traccia generato da un passante in
la rete CSMA. Potresti voler davvero ottenere una traccia da un singolo dispositivo e potresti non farlo
essere interessato a qualsiasi altro traffico sulla rete. Puoi farlo abbastanza facilmente.

Diamo un'occhiata a scratch/miosecondo.cc e aggiungi quel codice che ci permette di essere di più
specifica. NS-3 gli helper forniscono metodi che accettano un numero di nodo e un numero di dispositivo come
parametri. Vai avanti e sostituisci il AbilitaPcap chiamate con le chiamate sottostanti.

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

Sappiamo che vogliamo creare un file pcap con il nome base "second" e sappiamo anche
che il dispositivo di interesse in entrambi i casi sarà zero, quindi quei parametri non lo sono
molto interessante.

Per ottenere il numero di nodo, hai due scelte: primo, i nodi sono numerati in a
moda monotona crescente partendo da zero nell'ordine in cui l'hai creata
loro. Un modo per ottenere un numero di nodo è capire questo numero "manualmente" con
contemplando l'ordine di creazione del nodo. Se dai un'occhiata alla topologia della rete
illustrazione all'inizio del file, l'abbiamo fatto per te e puoi vedere che
l'ultimo nodo CSMA sarà il numero di nodo nCsma + 1. Questo approccio può diventare fastidioso
difficile in simulazioni più grandi.

Un modo alternativo, che usiamo qui, è rendersi conto che il NodeContainer contenere
puntatori a NS-3 Nodo Oggetti. Il Nodo L'oggetto ha un metodo chiamato Ottieni ID che sarà
restituire l'ID di quel nodo, che è il numero di nodo che cerchiamo. Andiamo a dare un'occhiata al
Dossigeno per il Nodo e individuare quel metodo, che è più in basso nel NS-3 codice di base
di quanto abbiamo visto finora; ma a volte devi cercare diligentemente cose utili.

Vai alla documentazione Doxygen per la tua versione (ricorda che puoi trovarla sul
sito web del progetto). Puoi arrivare al Nodo documentazione guardando attraverso il
scheda "Classi" e scorrendo verso il basso l'"Elenco classi" fino a trovare ns3::Nodo. Selezionare
ns3::Nodo e verrai portato alla documentazione per il Nodo classe. Se ora
scorrere fino a Ottieni ID metodo e selezionalo, verrai indirizzato ai dettagli
documentazione per il metodo. Usando il Ottieni ID il metodo può determinare i numeri dei nodi
molto più facile in topologie complesse.

Cancelliamo i vecchi file di traccia dalla directory di primo livello per evitare confusione su
cosa sta succedendo,

$rm *.pcap
$rm *.tr

Se crei il nuovo script ed esegui l'impostazione di simulazione nCsma a 100,

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

vedrai il seguente output:

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.407s)
Al momento il client 2s ha inviato 1024 byte alla porta 10.1.2.101 9
Al momento il server 2.0068s ha ricevuto 1024 byte dalla porta 10.1.1.1 49153
Al momento il server 2.0068s ha inviato 1024 byte alla porta 10.1.1.1 49153
Al momento il client 2.01761s ha ricevuto 1024 byte dalla porta 10.1.2.101 9

Nota che il server echo ora si trova a 10.1.2.101 che corrisponde ad avere 100
nodi CSMA "extra" con il server echo sull'ultimo. Se elenchi i file pcap in
la directory di primo livello che vedrai,

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

Il file di traccia secondo-0-0.pcap è il dispositivo punto-punto "più a sinistra" che è l'eco
sorgente del pacchetto Il file secondo-101-0.pcap corrisponde al dispositivo CSMA più a destra che
è dove risiede il server echo. Potresti aver notato che il parametro finale sul
la chiamata per abilitare la traccia pcap sul nodo del server echo era falsa. Ciò significa che la traccia
raccolti su quel nodo era in modalità non promiscua.

Per illustrare la differenza tra tracce promiscue e non promiscue, abbiamo anche
ha richiesto una traccia non promiscua per il penultimo nodo. Vai avanti e dai un'occhiata
, il tcpdump per secondo-100-0.pcap.

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

Ora puoi vedere che il nodo 100 è davvero uno spettatore nello scambio di echi. Il solo
i pacchetti che riceve sono le richieste ARP che vengono trasmesse all'intero CSMA
rete.

lettura dal file second-100-0.pcap, tipo collegamento EN10MB (Ethernet)
2.006698 ARP, Richiedi chi-ha 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, lunghezza 50
2.013815 ARP, Richiedi chi-ha 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, lunghezza 50

Ora dai un'occhiata al file tcpdump per secondo-101-0.pcap.

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

Ora puoi vedere che il nodo 101 è davvero il partecipante allo scambio di echi.

lettura dal file second-101-0.pcap, tipo collegamento EN10MB (Ethernet)
2.006698 ARP, Richiedi chi-ha 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, lunghezza 50
2.006698 ARP, risposta 10.1.2.101 è alle 00:00:00:00:00:67, lunghezza 50
2.006803 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, lunghezza 1024
2.013803 ARP, Richiedi chi-ha 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101, lunghezza 50
2.013828 ARP, risposta 10.1.2.1 è alle 00:00:00:00:00:03, lunghezza 50
2.013828 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, lunghezza 1024

Modelli, Attributi che a Realtà
Questo è un posto conveniente per fare una piccola escursione e fare un punto importante. Esso può
o potrebbe non essere ovvio per te, ma ogni volta che si utilizza una simulazione, è importante
capire esattamente cosa viene modellato e cosa no. Si è tentati, ad esempio, di
pensa ai dispositivi e ai canali CSMA utilizzati nella sezione precedente come se fossero reali
dispositivi ethernet; e aspettarsi che un risultato della simulazione rifletta direttamente ciò che accadrà
in una vera Ethernet. Questo non è il caso.

Un modello è, per definizione, un'astrazione della realtà. Alla fine è la responsabilità
dell'autore dello script di simulazione per determinare il cosiddetto "intervallo di precisione" e "dominio
di applicabilità" della simulazione nel suo insieme, e quindi delle sue parti costitutive.

In alcuni casi, come Csm, può essere abbastanza facile determinare cos'è non è un modellato. Di
leggendo la descrizione del modello (csma.h) puoi scoprire che non c'è il rilevamento delle collisioni
nel modello CSMA e decidi quanto sarà applicabile il suo utilizzo nella tua simulazione o cosa
avvertenze che potresti voler includere nei risultati. In altri casi, può essere abbastanza facile
per configurare comportamenti che potrebbero non essere d'accordo con nessuna realtà puoi uscire e comprare. Esso
risulterà utile dedicare un po' di tempo a indagare su alcuni di questi casi, e come
facilmente puoi sterzare fuori dai confini della realtà nelle tue simulazioni.

Come hai visto NS-3 fornisce Attributi che un utente può facilmente impostare per cambiare modello
comportamento. Considera due dei Attributi di Dispositivo CsmaNet: Mtu che a
Modalità di incapsulamento. Mtu attributo indica l'Unità di Trasmissione Massima al
dispositivo. Questa è la dimensione della più grande Protocol Data Unit (PDU) che il dispositivo può
inviare.

L'MTU è predefinito su 1500 byte nel Dispositivo CsmaNet. Questo valore predefinito corrisponde a un numero
trovato in RFC 894, "Uno standard per la trasmissione di datagrammi IP su Ethernet
Reti." Il numero è in realtà derivato dalla dimensione massima del pacchetto per 10Base5
(Ethernet full-spec) -- 1518 byte. Se sottrai l'incapsulamento DIX
sovraccarico per i pacchetti Ethernet (18 byte) ti ritroverai con una dimensione massima possibile dei dati
(MTU) di 1500 byte. Si può anche scoprire che il MTU per le reti IEEE 802.3 è 1492
byte. Questo perché l'incapsulamento LLC/SNAP aggiunge altri otto byte di sovraccarico a
il pacchetto. In entrambi i casi, l'hardware sottostante può inviare solo 1518 byte, ma i dati
la dimensione è diversa.

Per impostare la modalità di incapsulamento, il Dispositivo CsmaNet fornisce un Attributo detto
Modalità di incapsulamento che può assumere i valori Dix or lc. Questi corrispondono a Ethernet
e l'inquadratura LLC/SNAP rispettivamente.

Se uno lascia il Mtu a 1500 byte e cambia la modalità di incapsulamento in lc, il risultato
sarà una rete che incapsula 1500 byte PDU con framing LLC/SNAP risultante in
pacchetti di 1526 byte, il che sarebbe illegale in molte reti, poiché possono trasmettere a
massimo di 1518 byte per pacchetto. Ciò comporterebbe molto probabilmente una simulazione che
abbastanza sottilmente non riflette la realtà che potresti aspettarti.

Giusto per complicare il quadro, esistono jumbo frame (1500 < MTU <= 9000 byte) e
frame super-jumbo (MTU > 9000 byte) che non sono ufficialmente sanzionati da IEEE ma lo sono
disponibile in alcune reti ad alta velocità (Gigabit) e NIC. Si potrebbe lasciare il
modalità di incapsulamento impostata su Dixe imposta il file Mtu Attributo su una Dispositivo CsmaNet a 64000 byte
-- anche se un associato Canale Csma Velocità dati è stato fissato a 10 megabit al secondo. Questo
essenzialmente modellerebbe uno switch Ethernet realizzato con 1980Base10 . in stile anni '5 sfruttato dai vampiri
reti che supportano datagrammi super-jumbo. Questo non è certamente qualcosa che era
mai realizzato, né è probabile che venga mai realizzato, ma è abbastanza facile da configurare.

Nell'esempio precedente, hai utilizzato la riga di comando per creare una simulazione con 100
Csm nodi. Avresti potuto facilmente creare una simulazione con 500 nodi. Se tu
stavano effettivamente modellando quella rete 10Base5 di vampiri, la lunghezza massima di una specifica completa
Il cavo Ethernet è di 500 metri, con una distanza minima tra le prese di 2.5 metri. Ciò significa che c'è
potrebbero essere solo 200 tap su una rete reale. Avresti potuto facilmente costruire un illegale
rete anche in questo modo. Ciò può o non può risultare in una simulazione significativa
dipende da cosa stai cercando di modellare.

Situazioni simili possono verificarsi in molti luoghi in NS-3 e in qualsiasi simulatore. Per esempio,
potresti essere in grado di posizionare i nodi in modo tale che occupino lo stesso spazio al
stesso tempo, oppure potresti essere in grado di configurare amplificatori o livelli di rumore che violano il
leggi fondamentali della fisica.

NS-3 generalmente favorisce la flessibilità e molti modelli permetteranno di impostare liberamente Attributi
senza cercare di imporre una coerenza arbitraria o una specifica specifica sottostante.

La cosa da portare a casa da questo è che NS-3 fornirà una base super flessibile
per farti sperimentare. Sta a te capire cosa chiedi al sistema
da fare e per assicurarti che le simulazioni che crei abbiano un significato e un po'
connessione con una realtà definita da te.

Costruzione a Wireless Network NetPoulSafe Topologia
In questa sezione andremo ad ampliare ulteriormente la nostra conoscenza di NS-3 dispositivi di rete e
canali per coprire un esempio di rete wireless. NS-3 fornisce una serie di modelli 802.11
che tentano di fornire un'accurata implementazione a livello MAC della specifica 802.11
e un modello di livello PHY "non così lento" della specifica 802.11a.

Proprio come abbiamo visto sia gli oggetti di supporto della topologia punto-punto che CSMA quando
costruendo topologie punto-punto, vedremo equivalenti Wifi aiutanti di topologia in
questa sezione. L'aspetto e il funzionamento di questi aiutanti dovrebbero sembrare abbastanza familiari a
te.

Forniamo uno script di esempio nel nostro esempi/tutorial directory. Questo script si basa su
, il secondo.cc script e aggiunge una rete Wi-Fi. Vai avanti e apri
esempi/tutorial/terzi.cc nel tuo editor preferito. Avrai già visto abbastanza
NS-3 codice per capire la maggior parte di ciò che sta accadendo in questo esempio, ma ci sono alcune novità
cose, quindi esamineremo l'intero script ed esamineremo parte dell'output.

Proprio come nel secondo.cc esempio (e in tutto NS-3 esempi) il file inizia con un emacs
mode line e alcuni boilerplate GPL.

Dai un'occhiata all'arte ASCII (riprodotta di seguito) che mostra la topologia di rete predefinita
costruito nell'esempio. Puoi vedere che estenderemo ulteriormente il nostro esempio
appendendo una rete wireless dal lato sinistro. Nota che questa è una rete predefinita
topologia poiché puoi effettivamente variare il numero di nodi creati sul cablato e sul wireless
reti. Proprio come nel secondo.cc caso di script, se cambi nCsma, ti darà un
numero di nodi CSMA "extra". Allo stesso modo, puoi impostare Wi-Fi per controllare quanti S
(stazione) i nodi vengono creati nella simulazione. Ce ne sarà sempre uno AP (punto di accesso)
nodo sulla rete wireless. Per impostazione predefinita ci sono tre nodi CSMA "extra" e tre
senza fili S i nodi.

Il codice inizia caricando i file del modulo include proprio come è stato fatto nel secondo.cc esempio.
Ci sono un paio di nuove inclusioni corrispondenti al modulo Wifi e alla mobilità
modulo di cui parleremo di seguito.

#include "ns3/core-module.h"
#include "ns3/punto-punto-modulo.h"
#include "ns3/modulo-rete.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"

L'illustrazione della topologia di rete segue:

// Topologia di rete predefinita
//
// Wi-Fi 10.1.3.0
//AP
// * * * *
//| | | | 10.1.1.0
// n5 n6 n7 n0 -------------- n1 n2 n3 n4
// da punto a punto | | | |
// ==================
// LAN 10.1.2.0

Puoi vedere che stiamo aggiungendo un nuovo dispositivo di rete al nodo sul lato sinistro del
collegamento punto-punto che diventa il punto di accesso per la rete wireless. Un numero di
i nodi STA wireless vengono creati per compilare la nuova rete 10.1.3.0 come mostrato a sinistra
lato dell'illustrazione.

Dopo l'illustrazione, il NS-3 lo spazio dei nomi è utilizzato e viene definito un componente di registrazione.
Tutto questo dovrebbe essere abbastanza familiare ormai.

usando lo spazio dei nomi ns3;

NS_LOG_COMPONENT_DEFINE ("Esempio di terzo script");

Il programma principale inizia proprio come secondo.cc aggiungendo alcuni parametri della riga di comando per
abilitare o disabilitare i componenti di registrazione e per modificare il numero di dispositivi creati.

bool verbose = vero;
uint32_t nCsma = 3;
uint32_t nWiFi = 3;

Riga di comando cmd;
cmd.AddValue ("nCsma", "Numero di nodi/dispositivi CSMA \"extra\", nCsma);
cmd.AddValue ("nWifi", "Numero di dispositivi STA wifi", nWifi);
cmd.AddValue ("verbose", "Di' alle applicazioni echo di accedere se è vero", verbose);

cmd.Parse (argc,argv);

se (verboso)
{
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
}

Proprio come in tutti gli esempi precedenti, il prossimo passo è creare due nodi che faremo
connettersi tramite il collegamento punto-punto.

NodeContenitore p2pNodes;
p2pNodes.Crea (2);

Successivamente, vediamo un vecchio amico. Istanziamo a PuntoAPuntoHelper e impostare l'associato
difetto Attributi in modo da creare un trasmettitore da cinque megabit al secondo sui dispositivi
creato utilizzando l'helper e un ritardo di due millisecondi sui canali creati dall'helper.
Poi installazione i dispositivi sui nodi e il canale tra di essi.

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

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

Successivamente, ne dichiariamo un altro NodoContenitore per contenere i nodi che faranno parte del bus
rete (CSMA).

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

La prossima riga di codice Ottiene il primo nodo (come nell'avere un indice di uno) dal
contenitore di nodi punto-punto e lo aggiunge al contenitore di nodi che otterranno CSMA
dispositivi. Il nodo in questione finirà con un dispositivo punto-punto e un CSMA
dispositivo. Creiamo quindi una serie di nodi "extra" che compongono il resto del CSMA
rete.

Quindi istanziamo a CsmaHelper e impostare il suo Attributi come abbiamo fatto nell'esempio precedente.
Creiamo un file NetDeviceContenitore per tenere traccia dei dispositivi di rete CSMA creati e quindi
Installazione Dispositivi CSMA sui nodi selezionati.

CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps"));
csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560)));

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

Successivamente, creeremo i nodi che faranno parte della rete Wifi. Siamo
andando a creare un numero di nodi "stazione" come specificato dall'argomento della riga di comando, e
useremo il nodo "più a sinistra" del collegamento punto-punto come nodo per il
punto di accesso.

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

Il prossimo bit di codice costruisce i dispositivi wifi e il canale di interconnessione tra
questi nodi wifi. Innanzitutto, configuriamo il PHY e gli helper del canale:

Canale YansWifiChannelHelper = YansWifiChannelHelper::Default ();
YansWifiPhyHelper phy = YansWifiPhyHelper::Predefinito ();

Per semplicità, questo codice utilizza la configurazione del livello PHY predefinita e i modelli di canale
che sono documentati nella documentazione API doxygen per il
YansWifiChannelHelper::Predefinito che a YansWifiPhyHelper::Predefinito metodi. Una volta che questi oggetti
vengono creati, creiamo un oggetto canale e lo associamo al nostro gestore di oggetti del livello PHY
per assicurarsi che tutti gli oggetti del livello PHY creati dal YansWifiPhyHelper parti del
stesso canale sottostante, ovvero condividono lo stesso supporto wireless e possono
comunicazione e interferire:

phy.SetChannel (canale.Create ());

Una volta configurato l'helper PHY, possiamo concentrarci sul livello MAC. Qui scegliamo di lavorare
con MAC non Qos, quindi utilizziamo un oggetto NqosWifiMacHelper per impostare i parametri MAC.

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

NqosWifiMacHelper mac = NqosWifiMacHelper::Default ();

Le Imposta RemoteStation Manager Il metodo indica all'assistente il tipo di algoritmo di controllo della velocità da
uso. Qui, chiede all'helper di usare l'algoritmo AARF --- i dettagli sono, ovviamente,
disponibile in Doxygen.

Successivamente, configuriamo il tipo di MAC, l'SSID della rete dell'infrastruttura che vogliamo
configurare e assicurarsi che le nostre stazioni non eseguano sondaggi attivi:

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

Questo codice crea prima un oggetto identificatore del set di servizi 802.11 (SSID) che verrà utilizzato
per impostare il valore di "Ssid" Attributo dell'implementazione del livello MAC. Il particolare
il tipo di livello MAC che verrà creato dall'helper è specificato da Attributo come essere di
il tipo "ns3::StaWifiMac". L'impiego di NqosWifiMacHelper farà in modo che il file
"QosSupportato" Attributo per gli oggetti MAC creati è impostato su false. La combinazione di questi
due configurazioni significa che l'istanza MAC creata successivamente sarà un non-QoS non-AP
stazione (STA) in un BSS infrastrutturale (cioè un BSS con un AP). Infine, il
"Sondaggio attivo" Attributo è impostato su falso. Ciò significa che le richieste di sonda non saranno
inviato dai MAC creati da questo aiutante.

Una volta che tutti i parametri specifici della stazione sono completamente configurati, sia su MAC che su PHY
layer, possiamo invocare il nostro ormai familiare Installazione metodo per creare i dispositivi wifi di questi
stazioni:

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

Abbiamo configurato il Wifi per tutti i nostri nodi STA e ora dobbiamo configurare l'AP
(punto di accesso) nodo. Iniziamo questo processo modificando l'impostazione predefinita Attributi di
NqosWifiMacHelper per riflettere i requisiti dell'AP.

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

In questo caso, il NqosWifiMacHelper creerà i livelli MAC di "ns3::ApWifiMac",
quest'ultimo specificando che deve essere creata un'istanza MAC configurata come AP, con il
tipo di supporto che implica che "QosSupported" Attributo dovrebbe essere impostato su false - disabilitando
Supporto QoS in stile 802.11e/WMM sugli AP creati.

Le righe successive creano il singolo AP che condivide lo stesso set di livelli PHY Attributi (E
canale) come le stazioni:

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

Ora aggiungeremo modelli di mobilità. Vogliamo che i nodi STA siano mobili, erranti
all'interno di un riquadro di delimitazione e vogliamo rendere stazionario il nodo AP. Noi usiamo il
Aiuto per la mobilità per rendere questo facile per noi. Innanzitutto, istanziamo a Aiuto per la mobilità oggetto
e metti un po' Attributi il controllo della funzionalità "rilevatore di posizione".

MobilitàAiutante mobilità;

mobilità.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"));

Questo codice dice all'assistente di mobilità di utilizzare una griglia bidimensionale per posizionare inizialmente il
nodi STA. Sentiti libero di esplorare il Doxygen per la classe ns3::GridPositionAllocator da vedere
esattamente cosa si sta facendo.

Abbiamo disposto i nostri nodi su una griglia iniziale, ma ora dobbiamo dire loro come muoversi.
Scegliamo il Modello di mobilità RandomWalk2d che ha i nodi che si muovono in una direzione casuale a
una velocità casuale all'interno di un riquadro di delimitazione.

mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel",
"Bounds", RectangleValue (Rettangolo (-50, 50, -50, 50)));

Ora diciamo il Aiuto per la mobilità per installare i modelli di mobilità sui nodi STA.

mobilità.Installa (wifiStaNodes);

Vogliamo che il punto di accesso rimanga in una posizione fissa durante la simulazione. Noi
realizzare ciò impostando il modello di mobilità per questo nodo come il
ns3::ConstantPositionMobilityModel:

mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
mobilità.Installa (wifiApNode);

Ora abbiamo i nostri nodi, dispositivi e canali creati e modelli di mobilità scelti per il
Nodi Wi-Fi, ma non sono presenti stack di protocollo. Proprio come abbiamo fatto in precedenza molti
volte, useremo il Internet StackHelper per installare questi stack.

Stack di InternetStackHelper;
stack.Install (csmaNodes);
stack.Install (wifiApNode);
stack.Install (wifiStaNodes);

Proprio come nel secondo.cc script di esempio, useremo il IPv4AddressHelper a
assegnare indirizzi IP alle interfacce dei nostri dispositivi. Per prima cosa usiamo la rete 10.1.1.0 per creare
i due indirizzi necessari per i nostri due dispositivi punto-punto. Quindi usiamo la rete 10.1.2.0
per assegnare indirizzi alla rete CSMA e quindi assegniamo indirizzi dalla rete 10.1.3.0
sia ai dispositivi STA che all'AP sulla rete wireless.

Ipv4AddressIndirizzo dell'assistente;

indirizzo.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContenitore p2pInterfaces;
p2pInterfaces = indirizzo.Assign (p2pDevices);

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

indirizzo.SetBase ("10.1.3.0", "255.255.255.0");
indirizzo.Assegna (staDevices);
indirizzo.Assegna (apDevices);

Mettiamo il server echo sul nodo "più a destra" nell'illustrazione all'inizio del
file. Lo abbiamo già fatto.

UdpEchoServerHelper echoServer (9);

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

E mettiamo il client echo sull'ultimo nodo STA che abbiamo creato, puntandolo al server su
la rete CSMA. Abbiamo anche visto operazioni simili prima.

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

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

Dato che qui abbiamo costruito una rete, dobbiamo abilitare il routing della rete proprio come
abbiamo fatto nel secondo.cc sceneggiatura di esempio.

Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

Una cosa che può sorprendere alcuni utenti è il fatto che la simulazione che abbiamo appena creato
non si fermerà mai "naturalmente". Questo perché abbiamo chiesto al punto di accesso wireless di
generare beacon. Genererà beacon per sempre e questo si tradurrà in un simulatore
eventi programmati nel futuro a tempo indeterminato, quindi dobbiamo dire al simulatore di fermarsi
anche se potrebbe avere eventi di generazione beacon programmati. La seguente riga di codice
dice al simulatore di fermarsi in modo da non simulare i beacon per sempre e inserire ciò che è
essenzialmente un ciclo infinito.

Simulatore::Stop (secondi (10.0));

Creiamo una traccia sufficiente per coprire tutte e tre le reti:

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

Queste tre righe di codice avvieranno il tracciamento di pcap su entrambi i nodi punto-punto che
funge da spina dorsale, avvierà una traccia in modalità promiscua (monitoraggio) sulla rete Wi-Fi,
e avvierà una traccia promiscua sulla rete CSMA. Questo ci permetterà di vedere tutti i
traffico con un numero minimo di file di traccia.

Infine, eseguiamo effettivamente la simulazione, ripuliamo e quindi usciamo dal programma.

Simulatore::Esegui ();
Simulatore::Distruggi ();
0 ritorno;
}

Per eseguire questo esempio, devi copiare il file terzo.cc script di esempio in
gratta la directory e usa Waf per costruire proprio come hai fatto con il secondo.cc esempio. Se tu
si trovano nella directory di primo livello del repository che digiteresti,

$ cp esempi/tutorial/terzo.cc scratch/mioterzo.cc
$ ./waf
$ ./waf --run scratch/mioterzo

Ancora una volta, dal momento che abbiamo impostato le applicazioni echo UDP proprio come abbiamo fatto nel secondo.cc
script, vedrai un output simile.

Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: lasciare la directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' è terminato con successo (0.407s)
Al momento il client 2s ha inviato 1024 byte alla porta 10.1.2.4 9
Al momento il server 2.01796s ha ricevuto 1024 byte dalla porta 10.1.3.3 49153
Al momento il server 2.01796s ha inviato 1024 byte alla porta 10.1.3.3 49153
Al momento il client 2.03364s ha ricevuto 1024 byte dalla porta 10.1.2.4 9

Ricordiamo che il primo messaggio, Inviati 1024 bytes a 10.1.2.4," è il client echo UDP
inviare un pacchetto al server. In questo caso, il client è sulla rete wireless
(10.1.3.0). Il secondo messaggio, "ricevuto 1024 bytes da 10.1.3.3," proviene dall'eco UDP
server, generato quando riceve il pacchetto echo. Il messaggio finale, "ricevuto 1024
bytes da 10.1.2.4," proviene dal client echo, indicando che ha ricevuto il suo echo
ritorno dal server.

Se ora vai a cercare nella directory di livello superiore, troverai quattro file di traccia da
questa simulazione, due dal nodo zero e due dal nodo uno:

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

Il file "terzo-0-0.pcap" corrisponde al dispositivo punto-punto sul nodo zero -- il
lato sinistro della "spina dorsale". Il file "terzo-1-0.pcap" corrisponde al punto-punto
dispositivo sul nodo uno, il lato destro della "spina dorsale". Il file "terzo-0-1.pcap" sarà
la traccia promiscua (modalità monitor) dalla rete Wifi e il file "terzo-1-1.pcap"
sarà la traccia promiscua della rete CSMA. Puoi verificarlo ispezionando?
il codice?

Poiché il client echo è sulla rete Wifi, iniziamo da lì. Diamo un'occhiata al
traccia promiscua (modalità monitor) che abbiamo catturato su quella rete.

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

Dovresti vedere alcuni contenuti dall'aspetto wifi che non hai mai visto qui prima:

lettura dal file terzo-0-1.pcap, tipo collegamento 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 Richiesta Assoc (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 Risposta Assoc AIUTI(0) :: Successo
0.000546 Acknowledgment RA:00:00:00:00:00:0a
0.000721 Richiesta Assoc (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 Risposta Assoc AIUTI(0) :: Successo
0.000968 Acknowledgment RA:00:00:00:00:00:0a
0.001134 Richiesta Assoc (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 Risposta Assoc AIUTI(0) :: Successo
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

Puoi vedere che il tipo di collegamento ora è 802.11 come ti aspetteresti. probabilmente puoi
capire cosa sta succedendo e trovare la richiesta di eco IP e i pacchetti di risposta in questo
traccia. Lasciamo come esercizio l'analisi completa del dump della traccia.

Ora, guarda il file pcap del lato destro del collegamento punto-punto,

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

Di nuovo, dovresti vedere alcuni contenuti dall'aspetto familiare:

lettura dal file third-0-0.pcap, PPP di tipo collegamento (PPP)
2.008151 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.026758 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lunghezza 1024

Questo è il pacchetto di eco che va da sinistra a destra (da Wifi a CSMA) e viceversa
il collegamento punto-punto.

Ora, guarda il file pcap del lato destro del collegamento punto-punto,

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

Di nuovo, dovresti vedere alcuni contenuti dall'aspetto familiare:

lettura dal file third-1-0.pcap, PPP di tipo collegamento (PPP)
2.011837 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lunghezza 1024

Questo è anche il pacchetto di eco che va da sinistra a destra (da Wifi a CSMA) e viceversa
attraverso il collegamento da punto a punto con tempi leggermente diversi come ci si potrebbe aspettare.

Il server echo è sulla rete CSMA, diamo un'occhiata alla traccia promiscua lì:

$ tcpdump -nn -tt -r terzo-1-1.pcap

Dovresti vedere alcuni contenuti dall'aspetto familiare:

lettura dal file terzo-1-1.pcap, tipo di collegamento EN10MB (Ethernet)
2.017837 ARP, Richiedi chi-ha 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1, lunghezza 50
2.017861 ARP, risposta 10.1.2.4 è alle 00:00:00:00:00:06, lunghezza 50
2.017861 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, lunghezza 1024
2.022966 ARP, Richiedi chi-ha 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4, lunghezza 50
2.022966 ARP, risposta 10.1.2.1 è alle 00:00:00:00:00:03, lunghezza 50
2.023072 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, lunghezza 1024

Questo dovrebbe essere facilmente comprensibile. Se l'hai dimenticato torna indietro e guarda la discussione
in secondo.cc. Questa è la stessa sequenza.

Ora, abbiamo passato molto tempo a configurare modelli di mobilità per la rete wireless e quindi
sarebbe un peccato finire senza nemmeno mostrare che i nodi STA si stanno effettivamente muovendo
intorno durante la simulazione. Facciamolo agganciandoci al Modello di mobilità corso
modificare la sorgente della traccia. Questa è solo una sbirciatina nella sezione di tracciamento dettagliata che è
in arrivo, ma questo sembra un posto molto carino in cui dare un esempio.

Come menzionato nella sezione "Modifica ns-3", il NS-3 il sistema di tracciamento è diviso in traccia
source e trace sink e forniamo funzioni per connettere i due. Useremo il
modello di mobilità predefinito sorgente di traccia del cambio di rotta per originare gli eventi di traccia. Noi
sarà necessario scrivere un sink di traccia per connettersi a quella fonte che mostrerà qualcosa di carino
informazioni per noi. Nonostante la sua reputazione di essere difficile, è davvero molto semplice.
Poco prima del programma principale del scratch/mioterzo.cc script (cioè, subito dopo il
NS_LOG_COMPONENT_DEFINE istruzione), aggiungere la seguente funzione:

nulla
CourseChange (std::string context, Ptr modello)
{
Posizione del vettore = modello->GetPosition ();
NS_LOG_UNCOND (contesto <
" x = " << posizione.x << ", y = " << posizione.y);
}

Questo codice estrae solo le informazioni sulla posizione dal modello di mobilità e incondizionatamente
registra la posizione xey del nodo. Faremo in modo che questa funzione sia
chiamato ogni volta che il nodo wireless con il client echo cambia posizione. noi lo facciamo
usando il Config::Connetti funzione. Aggiungi solo le seguenti righe di codice allo script
prima di Simulatore::Esegui chiamata.

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

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

Quello che facciamo qui è creare una stringa contenente il percorso dello spazio dei nomi di tracciamento dell'evento
a cui vogliamo connetterci. Per prima cosa, dobbiamo capire quale nodo vogliamo usare
, il Ottieni ID metodo come descritto in precedenza. Nel caso del numero predefinito di CSMA e
nodi wireless, questo risulta essere il nodo sette e il percorso dello spazio dei nomi di tracciamento per il
modello di mobilità sarebbe simile,

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

In base alla discussione nella sezione di tracciamento, potresti dedurre che questo percorso di traccia
fa riferimento al settimo nodo nella NodeList globale. Specifica ciò che viene chiamato an
oggetto aggregato di tipo ns3::Modello di mobilità. Il prefisso del simbolo del dollaro implica che il
MobilityModel è aggregato al nodo sette. L'ultima componente del percorso significa che noi
si stanno agganciando all'evento "CourseChange" di quel modello.

Effettuiamo una connessione tra la sorgente di traccia nel nodo sette con il nostro sink di traccia chiamando
Config::Connetti e passando questo percorso dello spazio dei nomi. Una volta fatto questo, ogni cambio di rotta
l'evento sul nodo sette sarà collegato al nostro sink di traccia, che a sua volta stamperà il
nuova posizione.

Se ora esegui la simulazione, vedrai le modifiche al corso visualizzate man mano che si verificano.

'build' è terminato con successo (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
Al momento il client 2s ha inviato 1024 byte alla porta 10.1.2.4 9
Al momento il server 2.01796s ha ricevuto 1024 byte dalla porta 10.1.3.3 49153
Al momento il server 2.01796s ha inviato 1024 byte alla porta 10.1.3.3 49153
Al momento il client 2.03364s ha ricevuto 1024 byte dalla porta 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

TRACCIARE


sfondo
Come menzionato in UsingTracingSystem, l'intero punto di esecuzione di un NS-3 la simulazione è
generare output per lo studio. Hai due strategie di base per ottenere risultati da NS-3:
utilizzando meccanismi di output di massa predefiniti generici e analizzando il loro contenuto per l'estrazione
informazione interessante; o in qualche modo sviluppando un meccanismo di output che trasmette esattamente
(e forse solo) l'informazione voluta.

L'utilizzo di meccanismi di output di massa predefiniti ha il vantaggio di non richiedere alcuna modifica a
NS-3, ma potrebbe richiedere la scrittura di script per analizzare e filtrare i dati di interesse. Spesso,
PCAP o NS_LOG i messaggi di output vengono raccolti durante le esecuzioni di simulazione ed eseguiti separatamente
attraverso script che usano grep, sete or awk per analizzare i messaggi e ridurre e trasformare
i dati in una forma gestibile. I programmi devono essere scritti per eseguire la trasformazione, quindi questo
non viene gratis. NS_LOG l'output non è considerato parte del NS-3 API e può
cambiare senza preavviso tra le versioni. Inoltre, NS_LOG l'uscita è disponibile solo in
debug build, quindi fare affidamento su di esso impone una penalizzazione delle prestazioni. Naturalmente, se il
le informazioni di interesse non esistono in nessuno dei meccanismi di output predefiniti, questo
approccio fallisce.

Se hai bisogno di aggiungere qualche informazione ai meccanismi di massa predefiniti, questo può
certamente essere fatto; e se usi uno dei NS-3 meccanismi, potresti ottenere il tuo codice aggiunto
come contributo.

NS-3 fornisce un altro meccanismo, chiamato Tracing, che evita alcuni dei problemi inerenti
nei meccanismi di produzione di massa. Ha diversi vantaggi importanti. Per prima cosa, puoi
riduci la quantità di dati che devi gestire tracciando solo gli eventi di tuo interesse
(per grandi simulazioni, scaricare tutto su disco per la post-elaborazione può creare I/O
colli di bottiglia). In secondo luogo, se usi questo metodo, puoi controllare il formato dell'output
direttamente in modo da evitare la fase di post-elaborazione con sete, awk, perl or python script. Se
desideri, il tuo output può essere formattato direttamente in una forma accettabile da gnuplot, per
esempio (vedi anche GnuplotHelper). Puoi aggiungere ganci nel nucleo che possono quindi essere
accessibili da altri utenti, ma che non produrranno alcuna informazione se non esplicitamente richiesto di
fare così. Per questi motivi, riteniamo che il NS-3 il sistema di tracciamento è il modo migliore per ottenere
informazioni da una simulazione ed è quindi anche uno dei meccanismi più importanti
per capire NS-3.

Blunt Strumenti
Ci sono molti modi per ottenere informazioni da un programma. Il modo più semplice è
per stampare le informazioni direttamente sullo standard output, come in:

#includere
...
nulla
SomeFunction (nulla)
{
uint32_t x = QUALCHE VALORE_INTERESSANTE;
...
std::cout << "Il valore di x è " << x << std::endl;
...
}

Nessuno ti impedirà di andare in profondità nel nucleo di NS-3 e aggiungendo la stampa
dichiarazioni. Questo è incredibilmente facile da fare e, dopo tutto, hai il controllo completo del tuo
proprio NS-3 ramo. Questo probabilmente non si rivelerà molto soddisfacente a lungo
termine, però.

Man mano che il numero di istruzioni di stampa aumenta nei tuoi programmi, il compito di gestire il
un gran numero di uscite diventerà sempre più complicato. Alla fine, potresti sentirti
la necessità di controllare in qualche modo quali informazioni vengono stampate, magari accendendole
e fuori determinate categorie di stampe, o aumentando o diminuendo la quantità di
informazioni che desideri. Se continui su questa strada potresti scoprire di averlo fatto
re-implementato il NS_LOG meccanismo (vedere Utilizzo della registrazione). Per evitarlo, uno dei
la prima cosa che potresti considerare è l'utilizzo NS_LOG stessa.

Abbiamo menzionato sopra che un modo per ottenere informazioni da NS-3 è analizzare l'esistente NS_LOG
uscita per informazioni interessanti. Se scopri che qualche bocconcino di informazioni tu
la necessità non è presente nell'output del registro esistente, è possibile modificare il nucleo di NS-3 e aggiungi semplicemente
le tue informazioni interessanti nel flusso di output. Ora, questo è sicuramente meglio di
aggiungendo le tue dichiarazioni di stampa poiché segue NS-3 convenzioni di codifica e potrebbe
essere potenzialmente utile ad altre persone come patch al core esistente.

Prendiamo un esempio casuale. Se si desidera aggiungere più registrazione al file NS-3 socket TCP
(tcp-socket-base.cc) potresti semplicemente aggiungere un nuovo messaggio nell'implementazione. Avviso
quello dentro TcpSocketBase::ReceivedAck() non è presente alcun messaggio di registro per il caso no ACK. Voi
potrebbe semplicemente aggiungerne uno, cambiando il codice. Ecco l'originale:

/** Elabora il nuovo ACK ricevuto */
nulla
TcpSocketBase::ReceivedAck (Ptr pacchetto, const TcpHeader e tcpHeader)
{
NS_LOG_FUNCTION (questo << tcpHeader);

// Ricevuto ACK. Confronta il numero ACK con il seqno non ancora più alto
if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignora se nessun flag ACK
}
...

Per registrare il caso senza ACK, puoi aggiungerne uno nuovo NS_LOG_LOGICA nel if corpo di dichiarazione:

/** Elabora il nuovo ACK ricevuto */
nulla
TcpSocketBase::ReceivedAck (Ptr pacchetto, const TcpHeader e tcpHeader)
{
NS_LOG_FUNCTION (questo << tcpHeader);

// Ricevuto ACK. Confronta il numero ACK con il seqno non ancora più alto
if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK))
{ // Ignora se nessun flag ACK
NS_LOG_LOGIC ("TcpSocketBase " << questo << " nessun flag ACK");
}
...

Questo può sembrare abbastanza semplice e soddisfacente a prima vista, ma qualcosa da considerare lo è
che scriverai il codice da aggiungere NS_LOG dichiarazioni e dovrai anche scrivere
codice (come in grep, sete or awk scripts) per analizzare l'output del log in modo da isolare il file
informazione. Questo perché anche se hai un certo controllo su ciò che viene emesso dal file
sistema di registrazione, hai solo il controllo fino al livello del componente del registro, che in genere è
un intero file di codice sorgente.

Se stai aggiungendo codice a un modulo esistente, dovrai anche convivere con l'output
che ogni altro sviluppatore ha trovato interessante. Potresti trovarlo per ottenere il
piccola quantità di informazioni di cui hai bisogno, potresti dover guadare enormi quantità di
messaggi estranei che non ti interessano. Potresti essere costretto a salvare un registro enorme
file su disco ed elaborarli fino a poche righe ogni volta che vuoi fare qualsiasi cosa.

Dal momento che non ci sono garanzie in NS-3 sulla stabilità di NS_LOG output, potresti anche
scopri che i pezzi di output del registro da cui dipendi scompaiono o cambiano tra
rilasci. Se dipendi dalla struttura dell'output, potresti trovare altri messaggi in corso
aggiunti o eliminati che potrebbero influire sul codice di analisi.

Infine, NS_LOG l'output è disponibile solo nelle build di debug, non è possibile ottenere l'output del registro da
build ottimizzate, che funzionano circa il doppio della velocità. Contare su NS_LOG impone una prestazione
pena.

Per questi motivi, consideriamo le stampe a std::out che a NS_LOG messaggi per essere veloce e
modi sporchi per ottenere più informazioni NS-3, ma non adatto per lavori seri.

È auspicabile disporre di una struttura stabile che utilizzi API stabili che consentano di accedere
il sistema centrale e ottenere solo le informazioni richieste. È auspicabile essere in grado di fare
questo senza dover modificare e ricompilare il sistema principale. Ancora meglio sarebbe un
sistema che notificava il codice utente quando un elemento di interesse è cambiato o un evento interessante
è successo in modo che l'utente non debba curiosare attivamente nel sistema alla ricerca
cose.

Le NS-3 il sistema di tracciamento è progettato per funzionare lungo queste linee ed è ben integrato con
l'attributo e Config sottosistemi che consentono scenari di utilizzo relativamente semplici.

Panoramica
Le NS-3 sistema di tracciamento è costruito sui concetti di fonti di tracciamento indipendenti e
tracciatura dei pozzi, insieme a un meccanismo uniforme per il collegamento delle sorgenti ai pozzi.

Le sorgenti di traccia sono entità che possono segnalare eventi che accadono in una simulazione e fornire
accesso a dati sottostanti interessanti. Ad esempio, un'origine di traccia potrebbe indicare quando a
il pacchetto viene ricevuto da un dispositivo di rete e fornisce l'accesso al contenuto del pacchetto per
la traccia interessata sprofonda. Una fonte di traccia potrebbe anche indicare quando uno stato interessante
il cambiamento avviene in un modello. Ad esempio, la finestra di congestione di un modello TCP è un numero primo
candidato per una fonte di traccia. Ogni volta che la finestra di congestione cambia traccia connessa
i lavelli sono notificati con il vecchio e il nuovo valore.

Le fonti di traccia non sono utili da sole; devono essere collegati ad altri pezzi di codice
che effettivamente fanno qualcosa di utile con le informazioni fornite dalla fonte. Il
le entità che consumano informazioni di traccia sono chiamate sink di traccia. Le fonti di traccia lo sono
i generatori di dati e i sink di traccia sono consumatori. Questa divisione esplicita consente grandi
numero di fonti di traccia da spargere nel sistema in luoghi che modellano gli autori
credo possa essere utile. L'inserimento di sorgenti di traccia introduce un'esecuzione molto ridotta
in testa.

Possono esserci zero o più consumatori di eventi di traccia generati da un'origine di traccia. Uno può
pensa a una fonte di traccia come a una sorta di collegamento informativo da punto a multipunto. Il tuo codice
la ricerca di eventi di traccia da un particolare pezzo di codice principale potrebbe felicemente coesistere con
altro codice che fa qualcosa di completamente diverso dalle stesse informazioni.

A meno che un utente non colleghi un sink di traccia a una di queste origini, non viene emesso nulla. Usando
il sistema di tracciamento, sia tu che altre persone collegate alla stessa fonte di traccia state ricevendo
esattamente quello che vogliono e solo quello che vogliono dal sistema. Nessuno di voi due lo è
influenzando qualsiasi altro utente modificando le informazioni emesse dal sistema. Se tu
capita di aggiungere una fonte di traccia, il tuo lavoro da buon cittadino open source potrebbe consentirne altre
agli utenti di fornire nuove utilità forse nel complesso molto utili, senza crearne
cambia al NS-3 nucleo.

Semplice Esempio
Prendiamoci qualche minuto ed esaminiamo un semplice esempio di tracciamento. Avremo bisogno
un piccolo background sui callback per capire cosa sta succedendo nell'esempio, quindi noi
bisogna fare subito una piccola deviazione.

callback
L'obiettivo del sistema di richiamata in NS-3 è consentire a un pezzo di codice di chiamare una funzione
(o metodo in C++) senza alcuna dipendenza specifica tra i moduli. Questo alla fine significa
hai bisogno di una sorta di indirizzamento: tratti l'indirizzo della funzione chiamata come a
variabile. Questa variabile è chiamata variabile da puntatore a funzione. Il rapporto
tra funzione e puntatore a funzione non è in realtà diverso da quello di oggetto e
puntatore a oggetto.

In C l'esempio canonico di puntatore a funzione è a
pointer-to-function-returning-integer (PFI). Per un PFI che ne prende uno int parametro, questo
potrebbe essere dichiarato come,

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

(Ma leggi il Domande frequenti su C++ Sezione 33 prima di scrivere codice come questo!) Cosa ottieni da questo
è una variabile denominata semplicemente PFI che viene inizializzato al valore 0. Se lo si desidera
inizializza questo puntatore a qualcosa di significativo, devi avere una funzione con a
firma corrispondente. In questo caso, potresti fornire una funzione simile a:

int MiaFunzione (int arg) {}

Se hai questo obiettivo, puoi inizializzare la variabile in modo che punti alla tua funzione:

pfi = MiaFunzione;

Puoi quindi chiamare MyFunction indirettamente utilizzando la forma più suggestiva della chiamata:

int risultato = (*pfi) (1234);

Questo è suggestivo poiché sembra che tu stia dereferenziando solo il puntatore alla funzione
come dereferenziare qualsiasi puntatore. In genere, tuttavia, le persone approfittano del
fatto che il compilatore sa cosa sta succedendo e utilizzerà solo una forma più breve:

int risultato = pfi (1234);

Sembra che tu stia chiamando una funzione denominata PFI, ma il compilatore è abbastanza intelligente da farlo
sapere per chiamare tramite la variabile PFI indirettamente alla funzione La mia funzione.

Concettualmente, questo è quasi esattamente il modo in cui funziona il sistema di tracciamento. Insomma, una traccia
Lavello is una richiamata. Quando un sink di traccia esprime interesse a ricevere eventi di traccia, esso
si aggiunge come Callback a un elenco di Callback tenuti internamente dall'origine di traccia.
Quando si verifica un evento interessante, l'origine della traccia richiama il suo operatore(...) fornitura
zero o più argomenti. Il operatore(...) alla fine vaga nel sistema e
fa qualcosa di notevolmente simile alla chiamata indiretta che hai appena visto, fornendo zero o più
parametri, proprio come la chiamata a PFI sopra passato un parametro alla funzione di destinazione
La mia funzione.

L'importante differenza che aggiunge il sistema di tracciamento è che per ogni sorgente di traccia presente
è un elenco interno di richiamate. Invece di fare solo una chiamata indiretta, una traccia
source può richiamare più callback. Quando un trace sink esprime interesse per
notifiche da una fonte di traccia, in pratica si limita ad aggiungere la propria funzione
l'elenco delle richiamate.

Se sei interessato a maggiori dettagli su come questo è effettivamente organizzato NS-3, sentire
libero di esaminare la sezione Richiamata del NS-3 Manuale.

Procedura dettagliata: quarto.cc
Abbiamo fornito del codice per implementare quello che è davvero l'esempio più semplice di traccia
che può essere assemblato. Puoi trovare questo codice nella directory del tutorial come quarto.cc.
Esaminiamolo:

/* -*- Modalità:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Questo programma è un software gratuito; puoi ridistribuirlo e/o modificarlo
* secondo i termini della GNU General Public License versione 2 as
* pubblicato dalla Free Software Foundation;
*
* Questo programma è distribuito nella speranza che possa essere utile,
* ma SENZA ALCUNA GARANZIA; senza nemmeno la garanzia implicita di
* COMMERCIABILITÀ o IDONEITÀ PER UN PARTICOLARE SCOPO. Vedi il
* GNU General Public License per maggiori dettagli.
*
* Dovresti aver ricevuto una copia della GNU General Public License
* insieme a questo programma; in caso contrario, scrivi al Software Libero
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 Stati Uniti
*/

#include "ns3/object.h"
#include "ns3/uinteger.h"
#include "ns3/valore-tracciato.h"
#include "ns3/trace-source-accessor.h"

#includere

usando lo spazio dei nomi ns3;

La maggior parte di questo codice dovrebbe esserti abbastanza familiare. Come accennato in precedenza, il sistema di traccia
fa un uso massiccio dei sistemi Object e Attribute, quindi dovrai includerli.
I primi due include sopra riportano esplicitamente le dichiarazioni per quei sistemi. Voi
potrebbe usare l'intestazione del modulo principale per ottenere tutto in una volta, ma facciamo le inclusioni
esplicitamente qui per illustrare quanto sia semplice tutto questo.

Il file, valore-tracciato.h apporta le dichiarazioni richieste per la tracciabilità dei dati che
obbedisce alla semantica dei valori. In generale, la semantica del valore significa solo che puoi passare il
oggetto stesso in giro, invece di passare l'indirizzo dell'oggetto. Che cosa tutto questo davvero
significa che sarai in grado di tracciare tutte le modifiche apportate a un TracedValue in un attimo
modo semplice.

Poiché il sistema di tracciamento è integrato con gli attributi e gli attributi funzionano con gli oggetti,
ci deve essere un NS-3 Oggetto in cui risiedere l'origine della traccia. Il prossimo frammento di codice
dichiara e definisce un semplice Oggetto con cui possiamo lavorare.

classe MyObject : oggetto pubblico
{
pubblico:
statico TypeId GetTypeId (vuoto)
{
statico TypeId tid = TypeId ("MyObject")
.SetParent (Oggetto::GetTypeId ())
.Aggiungi costruttore ()
.AddTraceSource ("MyInteger",
"Un valore intero da tracciare.",
MakeTraceSourceAccessor (&MyObject::m_myInt),
"ns3::Tracciato::Valore::Int32Callback")
;
ritorno a mare;
}

MioOggetto () {}
Valore tracciato m_mioInt;
};

Le due righe di codice importanti, sopra, rispetto al tracciamento sono le .AddTraceSource
e le Valore tracciato dichiarazione di m_mioInt.

Le .AddTraceSource fornisce i "ganci" utilizzati per connettere la sorgente di traccia al file
mondo esterno attraverso il sistema di configurazione. Il primo argomento è un nome per questa traccia
sorgente, che lo rende visibile nel sistema di configurazione. Il secondo argomento è una stringa di aiuto.
Ora guarda il terzo argomento, in effetti concentrati sul argomento del terzo argomento:
&MioOggetto::m_mioInt. Questo è il TracedValue che viene aggiunto alla classe; è
sempre un membro dei dati di classe. (L'argomento finale è il nome di a typedef per l'
TracedValue, come stringa. Questo viene utilizzato per generare la documentazione per il corretto
Firma della funzione di callback, utile soprattutto per tipi più generali di
richiamate.)

Le Valore tracciato<> dichiarazione fornisce l'infrastruttura che guida il callback
processi. Ogni volta che il valore sottostante viene modificato, il meccanismo TracedValue lo fornirà
sia il vecchio che il nuovo valore di quella variabile, in questo caso an int32_t valore. La traccia
la funzione sink per questo TracedValue avrà bisogno della firma

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

Tutti i sink di traccia che collegano questa origine di traccia devono avere questa firma. Discuteremo di seguito
come determinare la firma di richiamata richiesta in altri casi.

Abbastanza sicuro, continuando quarto.cc vediamo:

nulla
IntTrace (int32_t vecchioValore, int32_t nuovoValore)
{
std::cout << "Tracciato" << oldValue << " to " << newValue << std::endl;
}

Questa è la definizione di un sink di traccia corrispondente. Corrisponde direttamente alla richiamata
firma della funzione. Una volta connesso, questa funzione verrà richiamata ogni volta che il
Valore tracciato modifiche.

Ora abbiamo visto l'origine della traccia e il sink di traccia. Quello che resta è il codice per connettere il
sorgente al lavandino, che accade in principale:

int
principale (int argc, char *argv[])
{
pt mioOggetto = CreaOggetto ();
myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace));

mioOggetto->m_mioInt = 1234;
}

Qui creiamo prima l'istanza MyObject in cui risiede l'origine della traccia.

Il prossimo passo, il TraceConnectWithoutContext, costituisce il collegamento tra la traccia
sorgente e il sink di traccia. Il primo argomento è solo il nome dell'origine della traccia "MyInteger"
abbiamo visto sopra. Notare il Effettua una richiamata funzione modello. Questa funzione fa la magia
necessario per creare il sottostante NS-3 Richiamare l'oggetto e associarlo alla funzione
IntTrace. Trace Connect effettua l'associazione tra la funzione fornita e
stracarico operatore() nella variabile tracciata a cui fa riferimento l'attributo "MyInteger".
Dopo aver eseguito questa associazione, l'origine di traccia "attiverà" la richiamata fornita
funzione.

Il codice per far sì che tutto ciò accada, ovviamente, non è banale, ma l'essenza è quella
stai organizzando qualcosa che assomigli a pfi() esempio sopra per essere chiamato
dalla fonte di traccia. La dichiarazione del Valore tracciato m_mioInt; nell'Oggetto
esso stesso esegue la magia necessaria per fornire gli operatori di assegnazione sovraccaricati che lo faranno
Usa il operatore() per richiamare effettivamente la richiamata con i parametri desiderati. Il
.AddTraceSource esegue la magia per connettere la richiamata al sistema di configurazione e
TraceConnectWithoutContext esegue la magia per collegare la tua funzione alla traccia
sorgente, che è specificata da Nome attributo.

Ignoriamo la parte relativa al contesto per ora.

Infine, la riga che assegna un valore a m_mioInt:

mioOggetto->m_mioInt = 1234;

deve essere interpretato come un'invocazione di operatore= sulla variabile membro m_mioInt con
l'intero 1234 passato come parametro.

Dal m_mioInt è un Valore tracciato, questo operatore è definito per eseguire un callback che
restituisce void e accetta due valori interi come parametri --- un vecchio valore e un nuovo valore
per il numero intero in questione. Questa è esattamente la firma della funzione per la richiamata
funzione che abbiamo fornito --- IntTrace.

Per riassumere, un'origine di traccia è, in sostanza, una variabile che contiene un elenco di callback. UN
trace sink è una funzione utilizzata come destinazione di un callback. L'attributo e il tipo di oggetto
i sistemi informativi vengono utilizzati per fornire un modo per collegare le origini di traccia ai sink di traccia.
L'atto di "colpire" una sorgente di traccia sta eseguendo un operatore sulla sorgente di traccia che
attiva le richiamate. Ciò si traduce nei callback del sink di traccia che registrano l'interesse per il
sorgente chiamata con i parametri forniti dalla sorgente.

Se ora crei ed esegui questo esempio,

$ ./waf --esegui quarto

vedrai l'output di IntTrace la funzione viene eseguita non appena l'origine della traccia è
colpire:

Tracciato da 0 a 1234

Quando abbiamo eseguito il codice, mioOggetto->m_mioInt = 1234;, la fonte di traccia è stata attivata e
ha fornito automaticamente i valori prima e dopo al sink di traccia. La funzione
IntTrace quindi stampato sull'output standard.

Collaborazioni con Config
Le TraceConnectWithoutContext la chiamata mostrata sopra nel semplice esempio è in realtà molto
usato raramente nel sistema. Più tipicamente, il Config il sottosistema viene utilizzato per selezionare una traccia
sorgente nel sistema utilizzando ciò che viene chiamato a Config sentiero. Abbiamo visto un esempio di questo nel
sezione precedente in cui abbiamo agganciato l'evento "CourseChange" mentre stavamo sperimentando
terzo.cc.

Ricordiamo che abbiamo definito un sink di traccia per stampare le informazioni sul cambio di rotta dalla mobilità
modelli della nostra simulazione. Ora dovrebbe esserti molto più chiaro quale sia questa funzione
facendo:

nulla
CourseChange (std::string context, Ptr modello)
{
Posizione del vettore = modello->GetPosition ();
NS_LOG_UNCOND (contesto <
" x = " << posizione.x << ", y = " << posizione.y);
}

Quando abbiamo collegato la sorgente di traccia "CourseChange" al sink di traccia sopra, abbiamo usato a
Percorso di configurazione per specificare l'origine quando abbiamo organizzato una connessione tra il predefinito
trace source e il nuovo sink di traccia:

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

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

Proviamo a dare un senso a quello che a volte è considerato un codice relativamente misterioso.
Ai fini della discussione, si supponga che il numero di Nodo restituito dal OttieniId() is
"7". In questo caso, il percorso sopra risulta essere

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

L'ultimo segmento di un percorso di configurazione deve essere an Attributo di Oggetto. In effetti, se l'avessi fatto
un puntatore al Oggetto che ha il "CourseChange" Attributo a portata di mano, potresti scrivere questo
proprio come abbiamo fatto nell'esempio precedente. Sai ormai che di solito immagazziniamo
indicazioni al ns Nodes in un NodeContainer. Nel terzo.cc esempio, i Nodi di interesse
sono memorizzati nel file wifiStaNodi NodeContainer. Infatti, mentre si mette insieme il percorso,
abbiamo usato questo contenitore per ottenere un Ptr che chiamavamo OttieniId(). Potremmo avere
usato questo Ptr per chiamare direttamente un metodo Connect:

pt theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange));

Nel terzo.cc ad esempio, in realtà volevamo che un ulteriore "contesto" fosse distribuito insieme
con i parametri Callback (che verranno spiegati di seguito) in modo da poter effettivamente utilizzare il
seguente codice equivalente:

pt theObject = wifiStaNodes.Get (nWifi - 1);
theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange));

Si scopre che il codice interno per Configurazione::ConnectWithoutContext che a Config::Connetti
effettivamente trovare un pt e chiamare l'appropriato Trace Connect metodo al minimo
livello.

Le Config le funzioni prendono un percorso che rappresenta una catena di Oggetto puntatori. Ogni segmento
di un percorso corrisponde a un attributo oggetto. L'ultimo segmento è l'attributo di
interesse e i segmenti precedenti devono essere digitati per contenere o trovare oggetti. Il Config codice
analizza e "percorre" questo percorso fino a raggiungere il segmento finale del percorso. Allora
interpreta l'ultimo segmento come un Attributo sull'ultimo oggetto trovato mentre si camminava
sentiero. Il Config funzioni quindi chiamare l'appropriato Trace Connect or
TraceConnectWithoutContext metodo sull'oggetto finale. Vediamo cosa succede tra un po'
maggiori dettagli quando si percorre il percorso di cui sopra.

Il carattere "/" iniziale nel percorso si riferisce a un cosiddetto spazio dei nomi. Uno di
lo spazio dei nomi predefinito nel sistema di configurazione è "NodeList" che è un elenco di tutti i
nodi nella simulazione. Gli elementi nell'elenco sono indicati da indici nell'elenco, quindi
"/NodeList/7" si riferisce all'ottavo nodo nell'elenco dei nodi creato durante la simulazione
(gli indici di richiamo iniziano a 0 '). Si riferimento is effettivamente a ``Ptr ` e così è un
sottoclasse di an ns3::Oggetto.

Come descritto nella sezione Modello a oggetti del NS-3 Manuale, di cui facciamo largo uso
aggregazione di oggetti. Questo ci permette di formare un'associazione tra diversi Oggetti
senza costruire un albero di eredità complicato o decidere quali oggetti faranno parte
di un Nodo. Ogni Oggetto in un'Aggregazione può essere raggiunto dagli altri Oggetti.

Nel nostro esempio il prossimo segmento di percorso da percorrere inizia con il carattere "$". Questo
indica al sistema di configurazione che il segmento è il nome di un tipo di oggetto, quindi a
OttieniOggetto la chiamata dovrebbe essere effettuata cercando quel tipo. Si scopre che il Aiuto per la mobilità
utilizzato in terzo.cc dispone di Aggregare, o associare, un modello di mobilità a ciascuno dei
senza fili Nodes. Quando aggiungi "$" stai chiedendo un altro oggetto che ha
presumibilmente precedentemente aggregato. Puoi pensare a questo come passare i puntatori da
l'originale Ptr come specificato da "/NodeList/7" al modello di mobilità associato ---
che è di tipo ns3::Modello di mobilità. Se conosci OttieniOggetto, abbiamo chiesto
il sistema per eseguire le seguenti operazioni:

pt mobilityModel = nodo->GetObject ()

Siamo ora all'ultimo Oggetto nel percorso, quindi rivolgiamo la nostra attenzione agli Attributi di
quell'Oggetto. Il Modello di mobilità class definisce un attributo chiamato "CourseChange". Puoi
guarda questo guardando il codice sorgente in src/mobility/model/mobility-model.cc che a
cercando "CourseChange" nel tuo editor preferito. Dovresti trovare

.AddTraceSource ("CourseChange",
"Il valore del vettore di posizione e/o velocità è cambiato",
MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace),
"ns3::MobilityModel::CourseChangeCallback")

che dovrebbe sembrare molto familiare a questo punto.

Se cerchi la dichiarazione corrispondente della variabile tracciata sottostante in
modello-mobilità.h troverai

Richiamata tracciata > m_courseChangeTrace;

La dichiarazione del tipo Richiamata tracciata identifica m_courseChangeTrace come un elenco speciale di
Callback che possono essere agganciati utilizzando le funzioni di configurazione sopra descritte. Il typedef per
la firma della funzione di callback è definita anche nel file di intestazione:

typedef void (* CourseChangeCallback)(Ptr * modello);

Le Modello di mobilità class è progettato per essere una classe base che fornisce un'interfaccia comune per
tutte le sottoclassi specifiche. Se cerchi fino alla fine del file, vedrai a
metodo definito chiamato NotificaCourseChange():

nulla
MobilityModel::NotifyCourseChange (void) const
{
m_courseChangeTrace(questo);
}

Le classi derivate richiameranno questo metodo ogni volta che effettuano un cambio di corso per supportare
tracciare. Questo metodo richiama operatore() sul sottostante m_courseChangeTrace, quale
a sua volta, invocherà tutti i callback registrati, chiamando tutti i sink di traccia che
hanno registrato interesse per l'origine della traccia chiamando una funzione di configurazione.

Quindi, nel terzo.cc esempio che abbiamo esaminato, ogni volta che viene effettuato un cambio di rotta in uno dei
Modello di mobilità RandomWalk2d istanze installate, ci sarà un NotificaCourseChange() chiamata
che richiama nel Modello di mobilità classe base. Come visto sopra, questo invoca operatore()
on m_courseChangeTrace, che a sua volta chiama tutti i sink di traccia registrati. Nell'esempio,
l'unico codice che registrava un interesse era il codice che forniva il percorso di configurazione.
quindi, il Cambio di corso la funzione che è stata agganciata dal nodo numero sette sarà la
solo richiamata chiamata.

L'ultimo pezzo del puzzle è il "contesto". Ricordiamo che abbiamo visto un output in cerca
qualcosa come il seguente da terzo.cc:

/NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y =
2.22677

La prima parte dell'output è il contesto. È semplicemente il percorso attraverso il quale il
il codice di configurazione ha individuato l'origine della traccia. Nel caso che abbiamo esaminato ci può essere
qualsiasi numero di sorgenti di traccia nel sistema corrispondente a qualsiasi numero di nodi con
modelli di mobilità. Ci deve essere un modo per identificare quale origine di traccia sia effettivamente
quello che ha sparato la richiamata. Il modo più semplice è connettersi con Config::Connetti, invece
of Configurazione::ConnectWithoutContext.

Trovare fonti
La prima domanda che inevitabilmente si pone ai nuovi utenti del sistema Tracing è: "Va bene,
I sapere che ci devono obbligatoriamente: be tracciare fonti in , il simulazione nucleo, ma come do I Find su che cosa
tracciare fonti sono disponibile a me?"

La seconda domanda è "Va bene, I essere trovato a tracciare fonte, come do I figura su , il Config sentiero
a uso quando I collegano a esso?"

La terza domanda è "Va bene, I essere trovato a tracciare source che a , il Config sentiero, come do I figura
su che cosa , il ritorno Digitare che a formale argomenti of my richiama funzione bisogno a essere?"

La quarta domanda è "Va bene, I digitato che contro tutti i in che a ha ottenuto questo incredibilmente bizzarro errore
Messaggio, che cosa in , il mondo effettua it significare?"

Affronteremo ciascuno di questi a turno.

Disponibile fonti
Va bene, I sapere che ci devono obbligatoriamente: be tracciare fonti in , il simulazione nucleo, ma come do I Find
su che cosa tracciare fonti sono disponibile a me?

La risposta alla prima domanda si trova nella NS-3 Documentazione API. Se vai al
sito web del progetto, NS-3 progetto, troverai un link alla "Documentazione" nella navigazione
sbarra. Se selezioni questo link, verrai indirizzato alla nostra pagina della documentazione. C'è un
link a "Latest Release" che ti porterà alla documentazione per l'ultima stable
rilascio di NS-3. Se selezioni il link "Documentazione API", verrai indirizzato al
NS-3 Pagina della documentazione dell'API.

Nella barra laterale dovresti vedere una gerarchia che inizia

·ns-3

· ns-3 Documentazione

· Tutti i TraceSources

· Tutti gli attributi

· Tutti i valori globali

L'elenco che ci interessa qui è "All TraceSources". Vai avanti e seleziona quel link.
Vedrai, forse non troppo sorprendentemente, un elenco di tutte le fonti di traccia disponibili
in NS-3.

Ad esempio, scorri verso il basso fino a ns3::Modello di mobilità. Troverai una voce per

CourseChange: il valore della posizione e/o del vettore di velocità è cambiato

Dovresti riconoscere questa come la fonte di traccia che abbiamo usato in terzo.cc esempio. Sfogliando
questo elenco sarà utile.

Config Percorsi
Va bene, I essere trovato a tracciare fonte, come do I figura su , il Config sentiero a uso quando I collegano a
vero?

Se sai quale oggetto ti interessa, la sezione "Descrizione dettagliata" per il
la classe elencherà tutte le origini di traccia disponibili. Ad esempio, partendo dall'elenco di "Tutti
TraceSources", fare clic su ns3::Modello di mobilità link, che ti porterà al
documentazione per il Modello di mobilità classe. Quasi in cima alla pagina c'è una riga
breve descrizione della classe, che termina con un link "Altro...". Fare clic su questo collegamento per saltare
il riepilogo API e vai alla "Descrizione dettagliata" della classe. Alla fine di
la descrizione sarà (fino a) tre elenchi:

· Config Percorsi: un elenco di percorsi di configurazione tipici per questa classe.

· Attributi: un elenco di tutti gli attributi forniti da questa classe.

· TraceSource: un elenco di tutti i TraceSource disponibili da questa classe.

Per prima cosa discuteremo i percorsi di configurazione.

Si supponga di aver appena trovato l'origine di traccia "CourseChange" in "All
TraceSources" e vuoi capire come connetterti ad esso. Sai che lo sei
utilizzando (di nuovo, dal terzo.cc esempio) an ns3::RandomWalk2dMobilityModel. quindi neanche
fai clic sul nome della classe nell'elenco "All TraceSources" o trova
ns3::RandomWalk2dMobilityModel nell'"Elenco classi". In ogni caso ora dovresti cercare
alla pagina "ns3::RandomWalk2dMobilityModel Class Reference".

Se ora scorri verso il basso fino alla sezione "Descrizione dettagliata", dopo l'elenco riepilogativo di
metodi e attributi della classe (o semplicemente fare clic sul collegamento "Altro..." alla fine della classe
breve descrizione nella parte superiore della pagina) vedrai la documentazione generale per il
classe. Continuando a scorrere verso il basso, trova l'elenco "Percorsi di configurazione":
Config Percorsi

ns3::RandomWalk2dMobilityModel è accessibile attraverso i seguenti percorsi con
Config::Imposta che a Config::Connetti:

· "/NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel"

La documentazione ti dice come raggiungere il Modello di mobilità RandomWalk2d Oggetto. Confrontare
la stringa sopra con la stringa che abbiamo effettivamente utilizzato nel codice di esempio:

"/NodeList/7/$ns3::MobilityModel"

La differenza è dovuta al fatto che due OttieniOggetto le chiamate sono implicite nella stringa trovata
nella documentazione. Il primo, per $ns3::Modello di mobilità interrogherà l'aggregazione per
la classe base. Il secondo implicava OttieniOggetto chiamare, per $ns3::RandomWalk2dMobilityModel,
viene utilizzato per eseguire il cast della classe base nella classe di implementazione concreta. La documentazione
mostra entrambe queste operazioni per te. Si scopre che la vera fonte di traccia sei tu
cercando si trova nella classe base.

Guarda più in basso nella sezione "Descrizione dettagliata" per l'elenco delle origini di traccia.
Troverai
Nessun TraceSource è definito per questo tipo.

TraceSource definito in genitore classe ``ns3::MobilityModel``

· Cambio di corso: Il valore del vettore di posizione e/o velocità è cambiato.

Firma di richiamata: ns3::MobilityModel::CourseChangeCallback

Questo è esattamente ciò che devi sapere. La traccia fonte di interesse si trova in
ns3::Modello di mobilità (che comunque sapevi). La cosa interessante è questo bit di API
La documentazione ti dice che non hai bisogno di quel cast extra nel percorso di configurazione sopra a
arrivare alla classe concrete, poiché l'origine della traccia è effettivamente nella classe base.
Pertanto l'addizionale OttieniOggetto non è richiesto e si utilizza semplicemente il percorso:

"/NodeList/[i]/$ns3::MobilityModel"

che corrisponde perfettamente al percorso di esempio:

"/NodeList/7/$ns3::MobilityModel"

Per inciso, un altro modo per trovare il percorso di configurazione è grep in giro nel NS-3 codebase
per qualcuno che l'ha già capito. Dovresti sempre provare a copiare quello di qualcun altro
codice funzionante prima di iniziare a scrivere il tuo. Prova qualcosa come:

$ trova. -nome '*.cc' | xargs grep Cambia corso | grep Connetti

e potresti trovare la tua risposta insieme al codice funzionante. Ad esempio, in questo caso,
src/mobility/examples/main-random-topology.cc ha qualcosa che aspetta solo che tu possa usare:

Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange",
MakeCallback (&CourseChange));

Torneremo su questo esempio tra un momento.

Richiamata firme
Va bene, I essere trovato a tracciare source che a , il Config sentiero, come do I figura su che cosa , il ritorno Digitare
che a formale argomenti of my richiama funzione bisogno a essere?

Il modo più semplice consiste nell'esaminare la firma di richiamata typedef, che è riportato nel
"Firma di richiamata" dell'origine di traccia nella "Descrizione dettagliata" per la classe, come
sopra riportati.

Ripetere la voce di origine della traccia "CourseChange" da ns3::RandomWalk2dMobilityModel we
avere:

· Cambio di corso: Il valore del vettore di posizione e/o velocità è cambiato.

Firma di richiamata: ns3::MobilityModel::CourseChangeCallback

La firma di richiamata viene fornita come collegamento al relativo typedef, dove troviamo
typedef nulla (* CourseChangeCallback)(cost std::stringa contesto, pt
Modello di mobilità> * modello);

Richiamata tracciata firma per le notifiche di cambio di corso.

Se la richiamata è connessa utilizzando Connetti senza contesto ometti il contesto argomento da
la firma.

parametri:
[in] context La stringa di contesto fornita dall'origine di traccia.
[in] model Il MobilityModel che sta cambiando rotta.

Come sopra, per vederlo in uso grep in giro nel NS-3 codebase per un esempio. L'esempio
sopra, da src/mobility/examples/main-random-topology.cc, collega il "CourseChange"
tracciare la fonte al Cambio di corso funzione nello stesso file:

vuoto statico
CourseChange (std::string context, Ptr modello)
{
...
}

Si noti che questa funzione:

· Accetta un argomento stringa "contesto", che descriveremo tra un minuto. (Se la richiamata
è collegato tramite il Connetti senza contesto funzione il contesto argomento sarà
omesso.)

· Ha il Modello di mobilità fornito come ultimo argomento (o solo argomento se
Connetti senza contesto viene usato).

· Ritorna nulla.

Se, per caso, la firma della richiamata non è stata documentata e non ci sono esempi per farlo
lavorare da, determinare la giusta firma della funzione di callback può essere, beh, difficile
effettivamente capire dal codice sorgente.

Prima di intraprendere una procedura dettagliata del codice, sarò gentile e ti dirò semplicemente un modo semplice
per capirlo: il valore di ritorno della tua richiamata sarà sempre nulla. Il formale
elenco dei parametri per a Richiamata tracciata può essere trovato dall'elenco dei parametri del modello in
dichiarazione. Ricordiamo che per il nostro esempio attuale, questo è in modello-mobilità.h, dove noi
hanno precedentemente trovato:

Richiamata tracciata > m_courseChangeTrace;

Esiste una corrispondenza uno a uno tra l'elenco dei parametri del modello nel file
dichiarazione e gli argomenti formali della funzione di callback. Ecco, ce n'è uno
parametro modello, che è a pt Modello di mobilità>. Questo ti dice che hai bisogno di un
funzione che restituisce void e accetta a pt Modello di mobilità>. Per esempio:

nulla
CourseChange (Ptr modello)
{
...
}

Questo è tutto ciò di cui hai bisogno se vuoi Configurazione::ConnectWithoutContext. Se vuoi un contesto,
è necessario Config::Connetti e quindi utilizzare una funzione di callback che accetta un contesto di stringa
gli argomenti del modello:

nulla
CourseChange (const std::string context, Ptr modello)
{
...
}

Se vuoi assicurarti che il tuo Richiamata CourseChange la funzione è visibile solo nel tuo
local file, puoi aggiungere la parola chiave statico e vieni con:

vuoto statico
CourseChange (const std::string path, Ptr modello)
{
...
}

che è esattamente quello che abbiamo usato in terzo.cc esempio.

Implementazione/Attuazione
Questa sezione è del tutto facoltativa. Sarà un viaggio accidentato, soprattutto per quelli
non ha familiarità con i dettagli dei modelli. Tuttavia, se superi questo, lo avrai
un'ottima maniglia su molti dei NS-3 idiomi di basso livello.

Quindi, ancora una volta, scopriamo quale firma della funzione di callback è richiesta per il
Sorgente di traccia "CourseChange". Sarà doloroso, ma devi solo farlo
una volta. Dopo aver superato questo, sarai in grado di guardare solo a Richiamata tracciata che a
capiscilo.

La prima cosa che dobbiamo guardare è la dichiarazione della sorgente della traccia. Richiama questo
questo è dentro modello-mobilità.h, dove abbiamo precedentemente trovato:

Richiamata tracciata > m_courseChangeTrace;

Questa dichiarazione è per un modello. Il parametro del modello è all'interno delle parentesi angolari,
quindi siamo davvero interessati a scoprire di cosa si tratta Richiamata tracciata<> è. Se hai
assolutamente nessuna idea di dove questo potrebbe essere trovato, grep è tuo amico.

Probabilmente saremo interessati a una sorta di dichiarazione nel NS-3 fonte, quindi
primo cambio nel src directory. Quindi, sappiamo che questa dichiarazione dovrà
essere in una specie di file di intestazione, quindi basta grep per esso usando:

$ trova. -nome '*.h' | xargs grep TracedCallback

Vedrai 303 linee volare via (l'ho trasmesso wc per vedere quanto era brutto). Sebbene
può sembrare molto, non è davvero molto. Basta convogliare l'output Scopri di più che a
inizia a scansionarlo. Nella prima pagina, ne vedrai alcuni in modo molto sospetto
roba dall'aspetto modello.

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 ...

Si scopre che tutto questo proviene dal file di intestazione tracciato-callback.h che suona
molto promettente. Puoi quindi dare un'occhiata modello-mobilità.h e vedere che c'è una linea
che conferma questa impressione:

#include "ns3/traced-callback.h"

Certo, avresti potuto andare dall'altra direzione e iniziare guardando
il include in modello-mobilità.h e notando l'inclusione di tracciato-callback.h che a
deducendo che questo deve essere il file desiderato.

In entrambi i casi, il passo successivo è dare un'occhiata src/core/model/traced-callback.h in
il tuo editor preferito per vedere cosa sta succedendo.

Vedrai un commento nella parte superiore del file che dovrebbe essere confortante:
Un ns3::TracedCallback ha quasi esattamente la stessa API di un normale ns3::Callback ma
invece di inoltrare le chiamate a una singola funzione (come fa normalmente un ns3::Callback),
inoltra le chiamate a una catena di ns3::Callback.

Questo dovrebbe suonare molto familiare e farti sapere che sei sulla strada giusta.

Subito dopo questo commento, troverai

modello
typename T3 = vuoto, typename T4 = vuoto,
typename T5 = vuoto, typename T6 = vuoto,
typename T7 = vuoto, typename T8 = vuoto>
classe TracedCallback
{
...

Questo ti dice che TracedCallback è una classe basata su modelli. Ha otto tipi possibili
parametri con valori di default. Torna indietro e confronta questo con la dichiarazione che sei
cercando di capire:

Richiamata tracciata > m_courseChangeTrace;

Le nome del tipo T1 nella dichiarazione di classe basata su modelli corrisponde a pt
Modello di mobilità> nella dichiarazione di cui sopra. Tutti gli altri parametri di tipo vengono lasciati come
impostazioni predefinite. Guardare il costruttore in realtà non ti dice molto. L'unico posto dove
hai visto che è stata stabilita una connessione tra la tua funzione di richiamata e il sistema di tracciamento
nel Collaborazioni che a Connetti senza contesto funzioni. Se scorri verso il basso, vedrai a
Connetti senza contesto metodo qui:

modello
nome del tipo T3, nome del tipo T4,
nome del tipo T5, nome del tipo T6,
nometipo T7, nometipo T8>
nulla
TracedCallback<T1,T2,T3,T4,T5,T6,T7,T8>::ConnectWithoutContext ...
{
Callback<void,T1,T2,T3,T4,T5,T6,T7,T8> cb;
cb.Assegna (richiamata);
m_callbackList.push_back (cb);
}

Ora sei nel ventre della bestia. Quando viene creata un'istanza del modello per il
dichiarazione precedente, il compilatore sostituirà T1 con pt Modello di mobilità>.

nulla
Richiamata tracciata ::ConnectWithoutContext ... cb
{
Richiama > cb;
cb.Assegna (richiamata);
m_callbackList.push_back (cb);
}

Ora puoi vedere l'implementazione di tutto ciò di cui abbiamo parlato. Il codice
crea una richiamata del tipo corretto e le assegna la tua funzione. Questo è il
equivalente di PFI = La mia funzione abbiamo discusso all'inizio di questa sezione. Il codice
quindi aggiunge la richiamata all'elenco delle richiamate per questa origine. L'unica cosa rimasta è
per esaminare la definizione di Callback. Usando lo stesso grep trucco come eravamo abituati a trovare
Richiamata tracciata, sarai in grado di trovare che il file ./core/richiamata.h è quello che noi
bisogno di guardare.

Se guardi in basso attraverso il file, vedrai molte cose probabilmente quasi incomprensibili
codice modello. Alla fine arriverai alla documentazione API per la richiamata
classe modello, però. Per fortuna c'è un po' di inglese:
Richiamata classe modello.

Questo modello di classe implementa il Functor Design Pattern. Si usa per dichiarare il
tipo di a Richiamata:

· il primo argomento del modello non facoltativo rappresenta il tipo restituito del callback.

· gli argomenti del template rimanenti (opzionali) rappresentano il tipo del successivo
argomenti per la richiamata.

· Sono supportati fino a nove argomenti.

Stiamo cercando di capire qual è il

Richiama > cb;

dichiarazione significa. Ora siamo in grado di capire che il primo (non facoltativo)
argomento modello, nulla, rappresenta il tipo restituito della richiamata. Il secondo
(facoltativo) argomento del modello, pt Modello di mobilità> rappresenta il tipo del primo
argomento alla richiamata.

Il Callback in questione è la tua funzione per ricevere gli eventi di traccia. Da questo puoi
dedurre che hai bisogno di una funzione che restituisce nulla e prende un pt Modello di mobilità>.
Per esempio,

nulla
CourseChangeCallback (Ptr modello)
{
...
}

Questo è tutto ciò di cui hai bisogno se vuoi Configurazione::ConnectWithoutContext. Se vuoi un contesto,
è necessario Config::Connetti e usa una funzione di callback che accetta un contesto di stringa. Questo
è perché il Collaborazioni la funzione fornirà il contesto per te. Avrai bisogno:

nulla
CourseChangeCallback (std::string context, Ptr modello)
{
...
}

Se vuoi assicurarti che il tuo Richiamata CourseChange è visibile solo nel tuo file locale,
puoi aggiungere la parola chiave statico e vieni con:

vuoto statico
CourseChangeCallback (std::percorso stringa, Ptr modello)
{
...
}

che è esattamente quello che abbiamo usato in terzo.cc esempio. Forse ora dovresti tornare indietro e
rileggi la sezione precedente (Prendi la mia parola per essa).

Se sei interessato a maggiori dettagli sull'implementazione dei callback, sentiti libero
per dare un'occhiata al NS-3 Manuale. Sono uno dei costrutti più utilizzati in
le parti di basso livello di NS-3. È, secondo me, una cosa abbastanza elegante.

Valori tracciati
In precedenza in questa sezione, abbiamo presentato un semplice pezzo di codice che utilizzava a
Valore tracciato per dimostrare le basi del codice di traccia. Abbiamo appena sorvolato
il cos'è veramente un TracedValue e come trovare il tipo restituito e gli argomenti formali per
la richiamata.

Come accennato, il file, valore-tracciato.h porta le dichiarazioni richieste per la tracciabilità
di dati che obbedisce alla semantica dei valori. In generale, la semantica dei valori significa semplicemente che puoi
passa l'oggetto stesso, invece di passare l'indirizzo dell'oggetto. Estendiamo
tale requisito per includere l'intero set di operatori in stile assegnazione che sono
predefinito per i tipi di dati normali (POD):

┌────────────────────────────────┬─────────────────────────
operatore= (incarico) │ │
├──────────────────────────────────────────┼──────────────────────────
operatore*=operatore/=
├──────────────────────────────────────────┼──────────────────────────
operatore+=operatore-=
├──────────────────────────────────────────┼──────────────────────────
operatore++ (sia prefisso che │ │
│postfisso) │ │
├──────────────────────────────────────────┼──────────────────────────
operatore-- (sia prefisso che │ │
│postfisso) │ │
├──────────────────────────────────────────┼──────────────────────────
operatore<<=operatore >>=
├──────────────────────────────────────────┼──────────────────────────
operatore&=operatore|=
├──────────────────────────────────────────┼──────────────────────────
operatore%=operatore^=
└───────────────────────────────────────────────────────────────

Tutto ciò significa davvero che sarai in grado di tracciare tutte le modifiche apportate utilizzando quelle
operatori a un oggetto C++ che ha una semantica di valore.

Le Valore tracciato<> la dichiarazione che abbiamo visto sopra fornisce l'infrastruttura che sovraccarica il file
operatori sopra menzionati e guida il processo di callback. Sull'uso di uno qualsiasi degli operatori
sopra con a Valore tracciato fornirà sia il vecchio che il nuovo valore di quella variabile,
in questo caso un int32_t valore. Con l'ispezione del Valore tracciato dichiarazione, sappiamo il
La funzione sink di traccia avrà argomenti (constata int32_t vecchio valore, const int32_t nuovo valore).
Il tipo di ritorno per a Valore tracciato la funzione di richiamata è sempre nulla, quindi il previsto
la firma di richiamata sarà:

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

Le .AddTraceSource nel Ottieni IDTipo Il metodo fornisce i "ganci" utilizzati per collegare il
tracciare la sorgente nel mondo esterno attraverso il sistema Config. Abbiamo già discusso del
primi tre agrumenti a Aggiungi TraceSource: il nome dell'attributo per il sistema di configurazione, un aiuto
string e l'indirizzo del membro dati della classe TracedValue.

L'argomento della stringa finale, "ns3::Traced::Value::Int32" nell'esempio, è il nome di un
typedef per la firma della funzione di richiamata. Richiediamo che queste firme siano definite,
e assegna il nome del tipo completo a Aggiungi TraceSource, quindi la documentazione dell'API può
collegare una sorgente di traccia alla firma della funzione. Per TracedValue la firma è
semplice; per TracedCallbacks abbiamo già visto che i documenti API sono davvero utili.

Real Esempio
Facciamo un esempio tratto da uno dei libri più noti sul TCP in circolazione. "TCP/IP
Illustrated, Volume 1: The Protocols," di W. Richard Stevens è un classico. Ho appena girato
il libro si è aperto e ha attraversato una bella trama sia della finestra di congestione che della sequenza
numeri contro il tempo a pagina 366. Stevens lo chiama "Figura 21.10. Valore di cwnd e
invia il numero di sequenza durante la trasmissione dei dati." Ricreiamo semplicemente la parte cwnd
di quella trama in NS-3 utilizzando il sistema di tracciamento e gnplot.

Disponibile fonti
La prima cosa a cui pensare è come vogliamo far uscire i dati. Cos'è che noi
devi tracciare? Quindi consultiamo l'elenco "Tutte le sorgenti di traccia" per vedere cosa dobbiamo lavorare
con. Ricordiamo che questo si trova nel NS-3 Documentazione API. Se scorri il
lista, alla fine troverai:
ns3::TcpNewReno

· Finestra di congestione: la finestra di congestione della connessione TCP

· Soglia di avvio lento: soglia di avvio lento TCP (byte)

Si scopre che il NS-3 L'implementazione del TCP risiede (principalmente) nel file
src/internet/modello/tcp-socket-base.cc mentre le varianti di controllo della congestione sono in file tali
as src/internet/model/tcp-newreno.cc. Se non lo sai a priori, è possibile utilizzare il comando
ricorsiva grep trucco:

$ trova. -nome '*.cc' | xargs grep -i tcp

Troverai pagina dopo pagina di istanze di tcp che ti indirizzano a quel file.

Visualizzazione della documentazione di classe per TcpNew Reno e saltando all'elenco di
TraceSources troverai
TraceSource

· Finestra di congestione: la finestra di congestione della connessione TCP

Firma di richiamata: ns3::Tracciato::Valore::Uint322Richiamata

Cliccando sulla richiamata typedef link vediamo la firma che ora sai aspettarti:

typedef void(* ns3::Traced::Value::Int32Callback)(const int32_t oldValue, const int32_t newValue)

Ora dovresti capire completamente questo codice. Se abbiamo un puntatore al TcpNew Reno,
noi possiamo Trace Connect alla fonte di traccia "CongestionWindow" se forniamo un'appropriata
destinazione della richiamata. Questo è lo stesso tipo di fonte di traccia che abbiamo visto nel semplice esempio
all'inizio di questa sezione, tranne di cui stiamo parlando uint32_t invece di
int32_t. E sappiamo che dobbiamo fornire una funzione di callback con quella firma.

Trovare Esempi
È sempre meglio provare a trovare codice funzionante in giro che puoi modificare, piuttosto
che partire da zero. Quindi il primo compito ora è trovare del codice che
aggancia già la fonte di traccia "CongestionWindow" e vediamo se possiamo modificarla. Come di solito,
grep È tuo amico:

$ trova. -nome '*.cc' | xargs grep CongestionWindow

Questo indicherà un paio di candidati promettenti: esempi/tcp/tcp-large-transfer.cc
che a src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc.

Non abbiamo ancora visitato nessuno dei codici di test, quindi diamo un'occhiata lì. Desideri
in genere trovo che il codice di test sia abbastanza minimo, quindi questa è probabilmente un'ottima scommessa.
Apri src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc nel tuo editor preferito e cerca
"Finestra di congestione". Troverai,

ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, questo));

Questo dovrebbe sembrarti molto familiare. Abbiamo detto sopra che se avessimo un puntatore al
TcpNew Reno, potremmo Trace Connect alla fonte di traccia "CongestionWindow". Questo è esattamente
quello che abbiamo qui; quindi risulta che questa riga di codice fa esattamente quello che vogliamo.
Andiamo avanti ed estraiamo il codice di cui abbiamo bisogno da questa funzione (Ns3TcpCwndTestCase1::DoRun
(vuoto)). Se guardi questa funzione, scoprirai che sembra proprio un NS-3
sceneggiatura. Si scopre che è esattamente quello che è. È uno script eseguito dal test
framework, quindi possiamo semplicemente estrarlo e avvolgerlo principale invece di in DoCorri. Piuttosto
di passare attraverso questo, passo dopo passo, abbiamo fornito il file che risulta dal porting
questo test torna a un nativo NS-3 copione -- esempi/tutorial/quinto.cc.

Dinamico Traccia fonti
Le quinto.cc esempio mostra una regola estremamente importante che devi capire
prima di utilizzare qualsiasi tipo di origine di traccia: è necessario assicurarsi che la destinazione di a
Config::Connetti comando esiste prima di provare a usarlo. Questo non è diverso dal dire
un oggetto deve essere istanziato prima di provare a chiamarlo. Anche se questo può sembrare ovvio
quando affermato in questo modo, fa inciampare molte persone che cercano di utilizzare il sistema per la prima volta
tempo.

Torniamo alle origini per un momento. Ci sono tre fasi di esecuzione di base che esistono in
in qualsiasi NS-3 sceneggiatura. La prima fase è talvolta chiamata "Tempo di configurazione" o "Impostazione
Time", ed esiste durante il periodo in cui il principale la funzione del tuo script è in esecuzione, ma
prima Simulatore::Esegui è chiamato. La seconda fase è talvolta chiamata "Tempo di simulazione"
ed esiste durante il periodo di tempo in cui Simulatore::Esegui sta eseguendo attivamente i suoi eventi.
Dopo aver completato l'esecuzione della simulazione, Simulatore::Esegui restituirà il controllo a
, il principale funzione. Quando ciò accade, lo script inserisce quello che può essere chiamato "Teardown
Fase", ovvero quando le strutture e gli oggetti creati durante l'installazione vengono smontati e
rilasciato.

Forse l'errore più comune commesso nel tentativo di utilizzare il sistema di tracciamento è presumerlo
entità costruite dinamicamente durante simulazione tempo sono disponibili durante la configurazione
volta. In particolare, l'an NS-3 presa di corrente è un oggetto dinamico spesso creato da Applicazioni a
comunicare tra NodesÈ stato anche creato un NS-3 Applicazioni ha sempre un "Ora di inizio" e un "Stop
Tempo" ad esso associato. Nella stragrande maggioranza dei casi, an Applicazioni non tenterà
per creare un oggetto dinamico fino al suo AvviaApplicazione viene chiamato in alcuni "Start
Time". Questo per garantire che la simulazione sia completamente configurata prima dell'app
tenta di fare qualsiasi cosa (cosa accadrebbe se tentasse di connettersi a un nodo che non esiste
ancora durante il tempo di configurazione?). Di conseguenza, durante la fase di configurazione non è possibile
collegare un'origine di traccia a un sink di traccia se uno di essi viene creato dinamicamente durante il
simulazione.

Le due soluzioni a questo enigma sono

1. Creare un evento del simulatore che viene eseguito dopo la creazione dell'oggetto dinamico e agganciarlo
traccia quando viene eseguito quell'evento; o

2. Creare l'oggetto dinamico al momento della configurazione, agganciarlo e consegnare l'oggetto a
il sistema da utilizzare durante il tempo di simulazione.

Abbiamo adottato il secondo approccio nel quinto.cc esempio. Questa decisione ci ha richiesto di creare
, il MyApp Applicazioni, il cui scopo è quello di prendere a presa di corrente come parametro.

Procedura dettagliata: quinto.cc
Ora, diamo un'occhiata al programma di esempio che abbiamo costruito dissezionando la congestione
prova finestra. Aprire esempi/tutorial/quinto.cc nel tuo editor preferito. Tu dovresti vedere
un codice dall'aspetto familiare:

/* -*- Modalità:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Questo programma è un software gratuito; puoi ridistribuirlo e/o modificarlo
* secondo i termini della GNU General Public License versione 2 as
* pubblicato dalla Free Software Foundation;
*
* Questo programma è distribuito nella speranza che possa essere utile,
* ma SENZA ALCUNA GARANZIA; senza nemmeno la garanzia implicita di
* COMMERCIABILITÀ o IDONEITÀ PER UN PARTICOLARE SCOPO. Vedi il
* GNU General Public License per maggiori dettagli.
*
* Dovresti aver ricevuto una copia della GNU General Public License
* insieme a questo programma; in caso contrario, scrivi al Software Libero
* Foundation, Include., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#includere
#include "ns3/core-module.h"
#include "ns3/modulo-rete.h"
#include "ns3/internet-module.h"
#include "ns3/punto-punto-modulo.h"
#include "ns3/applications-module.h"

usando lo spazio dei nomi ns3;

NS_LOG_COMPONENT_DEFINE ("FifthScriptExample");

Questo è stato tutto coperto, quindi non lo rifaremo. Le prossime righe di origine sono le
illustrazione della rete e un commento che affronta il problema sopra descritto con presa di corrente.

// =========================================================== ==============================
//
// nodo 0 nodo 1
// +----------------+ +----------------+
//| ns-3TCP | | ns-3TCP |
// +----------------+ +----------------+
// | 10.1.1.1 | | 10.1.1.2 |
// +----------------+ +----------------+
// | punto a punto | | punto a punto |
// +----------------+ +----------------+
// | |
// +----------------------+
// 5Mbps, 2 ms
//
//
// Vogliamo esaminare le modifiche nella finestra di congestione TCP di ns-3. Abbiamo bisogno
// per aumentare il flusso e agganciare l'attributo CongestionWindow al socket
// del mittente. Normalmente si usa un'applicazione on-off per generare a
// flusso, ma questo ha un paio di problemi. Innanzitutto, la presa dell'on-off
// l'applicazione non viene creata fino all'ora di inizio dell'applicazione, quindi non lo saremmo
// in grado di agganciare il socket (ora) in fase di configurazione. Secondo, anche se noi
// potrebbe organizzare una chiamata dopo l'ora di inizio, il socket non è pubblico, quindi noi
// non ci sono riuscito.
//
// Quindi, possiamo creare una versione semplice dell'applicazione on-off che fa cosa
// vogliamo. Tra i lati positivi, non abbiamo bisogno di tutta la complessità dell'on-off
// applicazione. Sul lato negativo, non abbiamo un aiutante, quindi dobbiamo ottenere
// un po' più coinvolto nei dettagli, ma questo è banale.
//
// Quindi per prima cosa creiamo un socket e ci colleghiamo alla traccia; poi passiamo
// questo socket nel costruttore della nostra semplice applicazione che noi poi
// installa nel nodo di origine.
// =========================================================== ==============================
//

Anche questo dovrebbe essere autoesplicativo.

La parte successiva è la dichiarazione del MyApp Applicazioni che abbiamo messo insieme per consentire
, il presa di corrente da creare in fase di configurazione.

classe MyApp : Applicazione pubblica
{
pubblico:

La mia app ();
virtuale ~MyApp();

void Setup (Ptr socket, indirizzo indirizzo, uint32_t packetSize,
uint32_t nPacchetti, DataRate dataRate);

privato:
vuoto virtuale StartApplication (void);
virtual void StopApplication (non valido);

void ScheduleTx (non valido);
void SendPacket (non valido);

pt presa m;
Indirizzo m_peer;
uint32_t m_packetSize;
uint32_t m_nPacchetti;
DataRate m_dataRate;
EventId m_sendEvent;
bool m_corsa;
uint32_t m_pacchetti inviati;
};

Puoi vedere che questa classe eredita da NS-3 Applicazioni classe. Date un'occhiata al
src/network/model/application.h se sei interessato a ciò che è ereditato. Il MyApp
la classe è obbligata a sovrascrivere il AvviaApplicazione che a Interrompi applicazione metodi. Questi
i metodi vengono chiamati automaticamente quando MyApp è necessario per avviare e interrompere l'invio di dati
durante la simulazione.

Avvio/Arresto Applicazioni
Vale la pena dedicare un po' di tempo a spiegare come gli eventi iniziano effettivamente nel
sistema. Questa è un'altra spiegazione abbastanza profonda e può essere ignorata se non lo sei
progettando di avventurarsi nelle viscere del sistema. È utile, tuttavia, in questo
la discussione tocca come alcune parti molto importanti di NS-3 lavoro e ne espone alcuni
idiomi importanti. Se stai pianificando di implementare nuovi modelli, probabilmente lo vorrai
capire questa sezione.

Il modo più comune per avviare gli eventi di pompaggio è avviare un Applicazioni. Questo è fatto come
il risultato delle seguenti (si spera) linee familiari di an NS-3 sceneggiatura:

App ApplicationContainer = ...
apps.Start (Secondi (1.0));
app.Stop (Secondi (10.0));

Il codice del contenitore dell'applicazione (vedi src/network/helper/application-container.h se sei
interessati) scorre le applicazioni e gli inviti contenuti,

app->SetStartTime (startTime);

come risultato della app.Avvia chiama e

app->SetStopTime (stopTime);

come risultato della app.Stop chiamata.

Il risultato finale di queste chiamate è che vogliamo avere il simulatore automaticamente
effettuare chiamate nel nostro Applicazioni per dire loro quando iniziare e quando fermarsi. In caso di
MyApp, eredita dalla classe Applicazioni e sostituisce AvviaApplicazione e
Interrompi applicazione. Queste sono le funzioni che verranno richiamate dal simulatore al
tempo appropriato. In caso di MyApp lo scoprirai MiaApp::StartApplication effettua
iniziale legante e Collaborazioni sul socket, quindi avvia il flusso di dati tramite chiamata
MiaApp::InviaPacchetto. MiaApp::StopApplication interrompe la generazione di pacchetti annullandone qualsiasi
eventi di invio in sospeso, quindi chiude il socket.

Una delle cose belle di NS-3 è che puoi ignorare completamente l'implementazione
dettagli di come il tuo Applicazioni viene "automagicamente" chiamato dal simulatore al corretto
volta. Ma dal momento che ci siamo già avventurati in profondità NS-3 già, proviamoci.

Se si guarda alla src/network/model/application.cc scoprirai che il Imposta ora di inizio metodo
di Applicazioni imposta semplicemente la variabile membro m_startTime e le Imposta ora di arresto metodo
solo set m_stopTime. Da lì, senza qualche accenno, il sentiero probabilmente finirà.

La chiave per riprendere il sentiero è sapere che esiste un elenco globale di tutti i
nodi nel sistema. Ogni volta che crei un nodo in una simulazione, un puntatore a quel nodo
viene aggiunto al globale Elenco dei nodi.

Dare un'occhiata a src/network/model/node-list.cc e cercare Elenco nodi::Aggiungi. Il pubblico
l'implementazione statica chiama in un'implementazione privata chiamata NodeListPriv::Aggiungi. Questo
è un idom relativamente comune in NS-3. Quindi, dai un'occhiata NodeListPriv::Aggiungi. Ecco tu
troverà,

Simulatore::ScheduleWithContext (indice, TimeStep (0), &Node::Inizializza, nodo);

Questo ti dice che ogni volta che un nodo viene creato in una simulazione, come effetto collaterale, una chiamata
a quello di quel nodo Inizializzare il metodo è programmato per te che si verifica all'ora zero. Non
leggere troppo in quel nome, ancora. Ciò non significa che il Nodo inizierà a funzionare
qualsiasi cosa, può essere interpretata come una chiamata informativa al Node dicendogli che il
la simulazione è iniziata, non un invito all'azione che dice al Nodo di iniziare a fare qualcosa.

Così, Elenco nodi::Aggiungi programma indirettamente una chiamata a Nodo::Inizializza al tempo zero per avvisare a
nuovo Nodo che la simulazione è iniziata. Se guardi dentro src/network/model/node.h Tu
tuttavia, non troverà un metodo chiamato Nodo::Inizializza. Si scopre che il
Inizializzare il metodo viene ereditato dalla classe Oggetto. Tutti gli oggetti nel sistema possono essere
notificato quando inizia la simulazione e gli oggetti della classe Node sono solo un tipo di quelli
oggetti.

Dare un'occhiata a src/core/modello/oggetto.cc Avanti e cerca Oggetto::Inizializza. Questo codice
non è così semplice come ti aspetteresti da allora NS-3 Oggetti supporto
aggregazione. Il codice dentro Oggetto::Inizializza quindi scorre tutti gli oggetti che
sono stati aggregati insieme e chiama loro Inizializza metodo. Questo è un altro modo di dire
che è molto comune in NS-3, a volte chiamato "modello di progettazione del modello.": un pubblico
metodo API non virtuale, che rimane costante tra le implementazioni e che chiama a
metodo di implementazione virtuale privato ereditato e implementato dalle sottoclassi.
I nomi sono in genere qualcosa di simile methodName per l'API pubblica e DoMethodName per
l'API privata.

Questo ci dice che dovremmo cercare a Nodo::DoInizializza metodo in
src/rete/modello/nodo.cc per il metodo che proseguirà il nostro percorso. Se trovi il
codice, troverai un metodo che scorre tutti i dispositivi nel Node e poi
tutte le applicazioni nella chiamata Node dispositivo->Inizializza che a applicazione->Inizializza
rispettivamente.

Potresti già conoscere quelle classi Dispositivo che a Applicazioni entrambi ereditano dalla classe Oggetto
e quindi il prossimo passo sarà guardare cosa succede quando Applicazione::DoInizializza is
chiamata. Date un'occhiata al src/network/model/application.cc e troverai:

nulla
Applicazione::DoInitialize (nulla)
{
m_startEvent = Simulator::Schedule (m_startTime, &Application::StartApplication, questo);
if (m_stopTime!= TimeStep (0))
{
m_stopEvent = Simulator::Schedule (m_stopTime, &Application::StopApplication, questo);
}
Oggetto::DoInizializza ();
}

Eccoci finalmente giunti alla fine del sentiero. Se hai tenuto tutto dritto, quando tu
implementare un NS-3 Applicazioni, la tua nuova applicazione eredita dalla classe Applicazioni. È
sovrascrivere il AvviaApplicazione che a Interrompi applicazione metodi e fornire meccanismi per
avviare e interrompere il flusso di dati in uscita dal tuo nuovo Applicazioni. Quando un nodo è
creato nella simulazione, viene aggiunto a un globale Elenco dei nodi. L'atto di aggiungere un nodo a
questo Elenco dei nodi fa in modo che un evento del simulatore venga pianificato per il tempo zero che chiama il
Nodo::Inizializza metodo del Nodo appena aggiunto da richiamare all'avvio della simulazione.
Poiché un nodo eredita da Oggetto, questo chiama il Oggetto::Inizializza metodo sul Nodo
che, a sua volta, chiama il Inizializza metodi su tutti i Oggetti aggregato al
Nodo (pensa ai modelli di mobilità). Dal Nodo Oggetto ha scavalcato Inizializza, quella
viene chiamato all'avvio della simulazione. Il Nodo::DoInizializza il metodo chiama
Inizializzare metodi di tutti i Applicazioni sul nodo. Da quando Applicazioni sono inoltre
Oggetti, questo causa Applicazione::DoInizializza da chiamare. quando
Applicazione::DoInizializza viene chiamato, programma gli eventi per il AvviaApplicazione che a
Interrompi applicazione invita il Applicazioni. Queste chiamate sono progettate per avviare e interrompere il
flusso di dati dal Applicazioni

Questo è stato un altro viaggio abbastanza lungo, ma deve essere fatto solo una volta, e tu ora
capire un altro pezzo molto profondo di NS-3.

Le MyApp Applicazioni
Le MyApp Applicazioni ha bisogno di un costruttore e di un distruttore, ovviamente:

La mia app::La mia app ()
: presa_m (0),
m_peer (),
m_dimensione pacchetto (0),
m_nPacchetti (0),
m_dataRate (0),
m_sendEvent(),
m_running (falso),
m_pacchettiSent (0)
{
}

MiaApp::~MiaApp()
{
presa_m = 0;
}

L'esistenza del prossimo bit di codice è l'intero motivo per cui l'abbiamo scritto Applicazioni in
il primo posto.

nulla
MyApp::Setup (Ptr socket, indirizzo indirizzo, uint32_t packetSize,
uint32_t nPacchetti, DataRate dataRate)
{
presa_m = presa;
m_peer = indirizzo;
m_packetSize = dimensionepacchetto;
m_nPacchetti = nPacchetti;
m_dataRate = dataRate;
}

Questo codice dovrebbe essere abbastanza autoesplicativo. Stiamo solo inizializzando le variabili membro.
Quello importante dal punto di vista del tracciamento è il pt presa di corrente che noi
necessario fornire all'applicazione durante il tempo di configurazione. Ricordiamo che stiamo andando
creare il presa di corrente come TCPSocket (che è implementato da TcpNew Reno) e agganciarlo
Sorgente di traccia "CongestionWindow" prima di passarla a Impostare metodo.

nulla
MyApp::StartApplication (nulla)
{
m_running = vero;
m_pacchetti Inviati = 0;
m_socket->Lega ();
m_socket->Connetti (m_peer);
InviaPacchetto ();
}

Il codice sopra è l'implementazione sovrascritta Applicazione::Avvia applicazione quello sarà
chiamato automaticamente dal simulatore per avviare il nostro Applicazioni correndo all'opportuno
volta. Puoi vedere che fa a presa di corrente legante operazione. Se hai familiarità con
Berkeley Sockets questa non dovrebbe essere una sorpresa. Svolge il lavoro richiesto sul locale
lato della connessione proprio come ci si potrebbe aspettare. Il seguente Collaborazioni farà ciò che è
necessario per stabilire una connessione con il TCP a Indirizzo m_peer. Ora dovrebbe essere chiaro
perché dobbiamo rimandare molto di questo al tempo di simulazione, dal momento che il Collaborazioni avrà bisogno
una rete completamente funzionante da completare. Dopo il Collaborazioni, l' Applicazioni poi inizia
creazione di eventi di simulazione chiamando InviaPacchetto.

Il prossimo bit di codice spiega al Applicazioni come interrompere la creazione di eventi di simulazione.

nulla
MyApp::StopApplication (nulla)
{
m_running = falso;

se (m_sendEvent.IsRunning ())
{
Simulatore::Annulla (m_sendEvent);
}

se (m_socket)
{
m_socket->Chiudi ();
}
}

Ogni volta che viene programmato un evento di simulazione, an Evento è creato. Se la Evento È in sospeso
esecuzione o esecuzione, il suo metodo sta correndo sarà di ritorno vero. In questo codice, se
È in esecuzione() restituisce vero, noi Annulla l'evento che lo rimuove dall'evento del simulatore
coda. In questo modo, interrompiamo la catena di eventi che il Applicazioni sta usando per mantenere
inviando il suo pacchetti e le Applicazioni va tranquillo. Dopo che abbiamo messo a tacere il Applicazioni we
Chiudi il socket che interrompe la connessione TCP.

Il socket viene effettivamente eliminato nel distruttore quando il file presa m = 0 viene eseguito. Questo
rimuove l'ultimo riferimento al Ptr che causa il distruttore di
quell'Oggetto da chiamare.

Richiama questo AvviaApplicazione detto InviaPacchetto per avviare la catena di eventi che descrive
, il Applicazioni comportamento.

nulla
MyApp::SendPacket (nulla)
{
pt pacchetto = Crea (m_pacchettoSize);
m_socket->Invia (pacchetto);

if (++m_packetsSent < m_nPackets)
{
ProgrammaTx ();
}
}

Ecco, lo vedi InviaPacchetto fa proprio questo. Crea un Pacchetto e poi fa un Invia
che, se conosci Berkeley Sockets, è probabilmente proprio quello che ti aspettavi di vedere.

È responsabilità del Applicazioni per continuare a programmare la catena di eventi, quindi il
le linee successive chiamano Pianificazione Tx per programmare un altro evento di trasmissione (a InviaPacchetto) fino al
Applicazioni decide di aver inviato abbastanza.

nulla
MyApp::ScheduleTx (nulla)
{
se (m_running)
{
Tempo tNext (Secondi (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, questo);
}
}

Ecco, lo vedi Pianificazione Tx fa esattamente questo. Se la Applicazioni è in esecuzione (se
Interrompi applicazione non è stato chiamato) pianificherà un nuovo evento, che chiama InviaPacchetto
ancora. Il lettore di avvisi individuerà qualcosa che fa inciampare anche nuovi utenti. La velocità dei dati
di Applicazioni è proprio questo. Non ha nulla a che fare con la velocità dati di un sottostante
canale. Questa è la velocità con cui il Applicazioni produce bit. Non prende in
tenere conto dell'eventuale sovraccarico per i vari protocolli o canali che utilizza per trasportare il
dati. Se si imposta la velocità dati di un Applicazioni alla stessa velocità dati del tuo sottostante
canale alla fine otterrai un overflow del buffer.

Traccia lavelli
Il punto centrale di questo esercizio è ottenere le callback di traccia da TCP che indicano il
la finestra di congestione è stata aggiornata. Il prossimo pezzo di codice implementa il corrispondente
lavello di traccia:

vuoto statico
CwndChange (uint32_t vecchioCwnd, uint32_t nuovoCwnd)
{
NS_LOG_UNCOND (Simulatore::Now()).GetSeconds() << "\t" << newCwnd);
}

Questo dovrebbe esserti molto familiare ora, quindi non ci soffermeremo sui dettagli. Questa funzione
registra solo il tempo di simulazione corrente e il nuovo valore della finestra di congestione ogni
tempo è cambiato. Probabilmente puoi immaginare di poter caricare l'output risultante
in un programma di grafica (gnuplot o Excel) e vedere subito un bel grafico del file
comportamento della finestra di congestione nel tempo.

Abbiamo aggiunto un nuovo sink di traccia per mostrare dove vengono eliminati i pacchetti. Stiamo per aggiungere un errore
modello anche per questo codice, quindi volevamo dimostrare questo funzionamento.

vuoto statico
RxDrop (Ptr P)
{
NS_LOG_UNCOND ("RxDrop su " << Simulator::Now ().GetSeconds ());
}

Questo sink di traccia sarà connesso alla sorgente di traccia "PhyRxDrop" del punto a punto
NetDevice. Questa sorgente di traccia si attiva quando un pacchetto viene eliminato dal livello fisico di a
NetDevice. Se fai una piccola deviazione alla fonte
(src/point-to-point/model/point-to-point-net-device.cc) vedrai che questa traccia
fonte si riferisce PointToPointNetDevice::m_phyRxDropTrace. Se poi guardi dentro
src/punto-punto/modello/dispositivo-rete-punto-punto.h per questa variabile membro, lo farai
trova che è dichiarato come a Richiamata tracciata Pacchetto> >. Questo dovrebbe dirtelo
che la destinazione di callback dovrebbe essere una funzione che restituisce void e ne accetta una singola
parametro che è a pt Pacchetto> (supponendo che usiamo Connetti senza contesto) -- appena
quello che abbiamo sopra.

Principale Programma
Il codice seguente dovrebbe esserti molto familiare a questo punto:

int
principale (int argc, char *argv[])
{
nodi NodeContainer;
nodi.Crea (2);

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

dispositivi NetDeviceContainer;
dispositivi = pointToPoint.Install (nodi);

Questo crea due nodi con un canale punto a punto tra di loro, proprio come mostrato in
illustrazione all'inizio del file.

Le prossime righe di codice mostrano qualcosa di nuovo. Se tracciamo una connessione che si comporta
perfettamente, ci ritroveremo con una finestra di congestione in aumento monotono. Per vederne qualcuno
comportamento interessante, vogliamo davvero introdurre errori di collegamento che rilasceranno i pacchetti,
causare ACK duplicati e attivare i comportamenti più interessanti della finestra di congestione.

NS-3 fornisce ErrorModel oggetti a cui possono essere attaccati Canali. Stiamo usando il
RateErrorModel che ci permette di introdurre errori in a canale a un dato tasso.

pt em = CreaOggetto ();
em->SetAttribute ("ErrorRate", DoubleValue (0.00001));
devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em));

Il codice sopra istanzia a RateErrorModel Object e impostiamo "ErrorRate" Attributo
al valore desiderato. Quindi impostiamo l'istanza risultante RateErrorModel come l'errore
modello utilizzato dal punto a punto NetDevice. Questo ci darà alcune ritrasmissioni e
rendere la nostra trama un po' più interessante.

Stack di InternetStackHelper;
stack.Install (nodi);

Ipv4AddressIndirizzo dell'assistente;
indirizzo.SetBase ("10.1.1.0", "255.255.255.252");
Interfacce Ipv4InterfaceContainer = address.Assign (dispositivi);

Il codice sopra dovrebbe essere familiare. Installa stack Internet sui nostri due nodi e
crea interfacce e assegna indirizzi IP per i dispositivi point-to-point.

Poiché stiamo usando TCP, abbiamo bisogno di qualcosa sul nodo di destinazione per ricevere TCP
connessioni e dati. Il PacketSink Applicazioni è comunemente usato in NS-3 per tale
scopo.

uint16_t sinkPort = 8080;
Indirizzo sinkAddress (InetSocketAddress(interfaces.GetAddress (1), sinkPort));
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny(), sinkPort));
ApplicationContainer sinkApps = pacchettoSinkHelper.Install (nodes.Get (1));
sinkApps.Start (secondi (0.));
sinkApps.Stop (Secondi (20.));

Tutto questo dovrebbe essere familiare, ad eccezione di

PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory",
InetSocketAddress (Ipv4Address::GetAny(), sinkPort));

Questo codice istanzia a PacketSinkHelper e gli dice di creare socket usando la classe
ns3::TcpSocketFactory. Questa classe implementa un design pattern chiamato "fabbrica di oggetti"
che è un meccanismo comunemente usato per specificare una classe usata per creare oggetti in un
modo astratto. Qui, invece di dover creare gli oggetti stessi, fornisci il
PacketSinkHelper una stringa che specifica a ID tipo stringa usata per creare un oggetto che
può quindi essere utilizzato, a sua volta, per creare istanze degli Oggetti creati dalla fabbrica.

Il parametro rimanente dice al Applicazioni quale indirizzo e porta dovrebbe legante a.

Le due righe di codice successive creeranno il socket e collegheranno l'origine della traccia.

pt ns3TcpSocket = Socket::CreateSocket (nodes.Get (0),
TcpSocketFactory::GetTypeId ());
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow",
MakeCallback (&CwndChange));

La prima istruzione chiama la funzione membro statica Presa::Crea presa e fornisce un
Nodo e un esplicito ID tipo per la fabbrica di oggetti utilizzata per creare il socket. Questo è un
chiamata di livello leggermente inferiore rispetto a PacketSinkHelper chiamata sopra e usa un C++ esplicito
digitare invece di uno a cui fa riferimento una stringa. Altrimenti, è concettualmente lo stesso
cosa.

Una volta che il TCPSocket viene creato e allegato al Node, possiamo usarlo
TraceConnectWithoutContext per connettere l'origine di traccia CongestionWindow al nostro sink di traccia.

Ricordiamo che abbiamo codificato un Applicazioni quindi potremmo prenderlo presa di corrente abbiamo appena realizzato (durante
tempo di configurazione) e utilizzarlo nel tempo di simulazione. Ora dobbiamo esemplificarlo
Applicazioni. Non ci siamo preoccupati di creare un aiutante per gestire il Applicazioni so
dovremo crearlo e installarlo "manualmente". Questo è in realtà abbastanza facile:

pt app = CreaOggetto ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps"));
nodes.Get (0)->AddApplication (app);
app->Start (Secondi (1.));
app->Stop (Secondi (20.));

La prima riga crea un Oggetto di tipo MyApp -- nostro Applicazioni. La seconda riga racconta
, il Applicazioni che cosa presa di corrente utilizzare, a quale indirizzo collegarsi, a quanti dati inviare
ogni evento di invio, quanti eventi di invio generare e la velocità con cui produrre i dati
da quegli eventi.

Successivamente, aggiungiamo manualmente il MyApp Applicazioni al nodo di origine e chiamare in modo esplicito il
Inizia che a Fermare metodi sul Applicazioni per dirgli quando iniziare e smettere di farlo
cosa.

Dobbiamo effettivamente eseguire la connessione punto a punto dal ricevitore NetDevice evento di caduta
al nostro RxDrop richiamare ora.

devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop));

Ora dovrebbe essere ovvio che stiamo ottenendo un riferimento alla ricezione Nodo NetDevice
dal suo contenitore e collegando la sorgente di traccia definita dall'attributo "PhyRxDrop" su
quel dispositivo al dissipatore di tracce RxDrop.

Infine, diciamo al simulatore di sovrascrivere qualsiasi Applicazioni e interrompi l'elaborazione
eventi a 20 secondi dall'inizio della simulazione.

Simulatore::Stop (secondi(20));
Simulatore::Esegui ();
Simulatore::Distruggi ();

0 ritorno;
}

Ricordalo non appena Simulatore::Esegui viene chiamato, termina il tempo di configurazione e la simulazione
il tempo inizia. Tutto il lavoro che abbiamo orchestrato creando il Applicazioni e insegnandolo
come connettersi e inviare dati avviene effettivamente durante questa chiamata di funzione.

Non appena Simulatore::Esegui ritorna, la simulazione è completa ed entriamo nel teardown
fase. In questo caso, Simulatore::Distruggi si prende cura dei dettagli cruenti e siamo appena tornati
un codice di successo dopo il completamento.

corsa quinto.cc
Dal momento che abbiamo fornito il file quinto.cc per te, se hai costruito la tua distribuzione (in
modalità di debug poiché utilizza NS_LOG -- ricorda che le build ottimizzate ottimizzano NS_LOG) esso
ti aspetterà per correre.

$ ./waf --esegui il quinto
Waf: entrare nella directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
Waf: uscita dalla directory `/home/craigdo/repos/ns-3-allinone-dev/ns-3-dev/build'
'build' è terminato con successo (0.684s)
1 536
1.0093 1072
1.01528 1608
1.02167 2144
...
1.11319 8040
1.12151 8576
1.12983 9112
RxDrop a 1.13696
...

Probabilmente puoi vedere immediatamente uno svantaggio dell'utilizzo di stampe di qualsiasi tipo nelle tue tracce.
Riceviamo quei messaggi waf estranei stampati su tutte le nostre informazioni interessanti insieme
con quei messaggi RxDrop. Presto rimedieremo, ma sono sicuro che non vedi l'ora di vederlo
i risultati di tutto questo lavoro. Reindirizziamo quell'output in un file chiamato cwnd.dat:

$ ./waf --run Fifth > cwnd.dat 2>&1

Ora modifica "cwnd.dat" nel tuo editor preferito e rimuovi lo stato di build waf e rilascia
righe, lasciando solo i dati tracciati (potresti anche commentare il file
TraceConnectWithoutContext("PhyRxDrop", Effettua una richiamata (&RxDrop)); nella sceneggiatura per sbarazzarsi
delle stampe a goccia altrettanto facilmente.

Ora puoi eseguire gnuplot (se lo hai installato) e dirgli di generare qualcosa di carino
immagini:

$gnplot
gnuplot> imposta la dimensione del png del terminale 640,480
gnuplot> imposta l'output "cwnd.png"
gnuplot> traccia "cwnd.dat" usando il titolo 1:2 'Finestra di congestione' con punti di linea
gnuplot> esci

Ora dovresti avere un grafico della finestra di congestione rispetto al tempo che si trova nel file
"cwnd.png" loading="lazy" che assomiglia a:
[immagine]

utilizzando Livello medio Helpers
Nella sezione precedente, abbiamo mostrato come agganciare una fonte di traccia e ottenere, si spera,
informazioni interessanti da una simulazione. Forse ricorderete che abbiamo chiamato
registrazione allo standard output utilizzando std::out uno "strumento contundente" molto prima in questo
capitolo. Abbiamo anche scritto di come fosse un problema dover analizzare l'output del registro in ordine
per isolare informazioni interessanti. Forse ti è venuto in mente che abbiamo appena speso molto
di tempo implementando un esempio che mostra tutti i problemi con cui pretendiamo di risolvere
, il NS-3 sistema di tracciamento! Saresti corretto. Ma, abbi pazienza con noi. Non abbiamo ancora finito.

Una delle cose più importanti che vogliamo fare è avere la capacità di farlo facilmente
controllare la quantità di output che esce dalla simulazione; e vogliamo anche salvare quelli
dati in un file in modo da potervi fare riferimento in seguito. Possiamo usare gli helper di traccia di livello medio
fornito in NS-3 per fare proprio questo e completare il quadro.

Forniamo uno script che scrive gli eventi cwnd change e drop sviluppati nell'esempio
quinto.cc su disco in file separati. Le modifiche cwnd vengono memorizzate come ASCII separati da tabulazioni
file e gli eventi di rilascio vengono archiviati in un file PCAP. Le modifiche per farlo accadere sono
piuttosto piccola.

Procedura dettagliata: sesto.cc
Diamo un'occhiata alle modifiche necessarie per passare quinto.cc a sesto.cc. Aperto
esempi/tutorial/sesto.cc nel tuo editor preferito. Puoi vedere il primo cambiamento di
alla ricerca di CwndChange. Scoprirai che abbiamo cambiato le firme per la traccia
sink e hanno aggiunto una singola riga a ciascun sink che scrive le informazioni tracciate in a
flusso che rappresenta un file.

vuoto statico
CwndChange (Ptr stream, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulatore::Now()).GetSeconds() << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}

vuoto statico
RxDrop (Ptr dossier, pt P)
{
NS_LOG_UNCOND ("RxDrop su " << Simulator::Now ().GetSeconds ());
file->Scrivi(Simulatore::Ora(), p);
}

Abbiamo aggiunto un parametro "stream" al file CwndChange lavello di traccia. Questo è un oggetto che
contiene (mantiene in vita in modo sicuro) un flusso di output C++. Si scopre che questo è molto semplice
oggetto, ma uno che gestisce i problemi di durata per il flusso e risolve un problema che anche
utenti esperti di C++ si imbattono in. Si scopre che il costruttore di copie per std::ostream
è contrassegnato come privato. Ciò significa che std::ostream non obbedire alla semantica dei valori e non possono
essere utilizzato in qualsiasi meccanismo che richieda la copia del flusso. Questo include il NS-3
sistema di callback, che come ricorderete, richiede oggetti che obbediscono alla semantica dei valori.
Ulteriore avviso che abbiamo aggiunto la seguente riga nel CwndChange lavello di traccia
implementazione:

*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Questo sarebbe un codice molto familiare se lo sostituisci *stream->GetStream () con std::out, come
in:

std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;

Ciò dimostra che il pt è davvero solo portare in giro a
std::offstream per te e puoi usarlo qui come qualsiasi altro flusso di output.

Una situazione simile accade in RxDrop tranne che l'oggetto che viene passato (a
pt) rappresenta un file PCAP. C'è un one-liner nel dissipatore di tracce
scrivi un timestamp e il contenuto del pacchetto che viene rilasciato nel file PCAP:

file->Scrivi(Simulatore::Ora(), p);

Naturalmente, se abbiamo oggetti che rappresentano i due file, dobbiamo crearli da qualche parte
e anche farli passare ai pozzi di traccia. Se guardi nel principale funzione,
troverai un nuovo codice per fare proprio questo:

AsciiTraceHelper asciiTraceHelper;
pt flusso = asciiTraceHelper.CreateFileStream ("sesto.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));

...

PcapHelper pcapHelper;
pt file = pcapHelper.CreateFile ("sesto.pcap", std::ios::out, PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));

Nella prima sezione del frammento di codice sopra, stiamo creando il file di traccia ASCII,
creando un oggetto responsabile della sua gestione e utilizzando una variante del callback
funzione di creazione per fare in modo che l'oggetto venga passato al sink. La nostra traccia ASCII
gli helper forniscono un ricco set di funzioni per semplificare l'utilizzo di file di testo (ASCII). Noi siamo
sto solo per illustrare l'uso della funzione di creazione del flusso di file qui.

Le CreaFileStream fondamentalmente la funzione istanzia a std::offstream oggetto e
creare un nuovo file (o troncare un file esistente). Questo std::offstream è confezionato in un
NS-3 oggetto per la gestione della durata e la risoluzione dei problemi del costruttore di copie.

Quindi prendiamo questo NS-3 oggetto che rappresenta il file e passarlo a MakeBoundCallback().
Questa funzione crea una richiamata proprio come Effettua richiamata(), ma "associa" un nuovo valore a
la richiamata. Questo valore viene aggiunto come primo argomento al callback prima che lo sia
chiamato.

Essenzialmente, MakeBoundCallback(&CwndChange, flusso) fa sì che l'origine della traccia aggiunga il file
parametro "stream" aggiuntivo all'inizio dell'elenco di parametri formale prima di richiamare
la richiamata. Questo cambia la firma richiesta del CwndChange lavello in modo che corrisponda a quello
mostrato sopra, che include il parametro "extra". pt ruscello.

Nella seconda sezione di codice nello snippet sopra, istanziamo a PcapHelper per fare il
stessa cosa per il nostro file di traccia PCAP che abbiamo fatto con il file AsciiTraceHelper. La linea di
codice,

pt file = pcapHelper.CreateFile ("sesto.pcap",
"w", PcapHelper::DLT_PPP);

crea un file PCAP denominato "sixth.pcap" con modalità file "w". Ciò significa che il nuovo file
viene troncato (contenuto eliminato) se viene trovato un file esistente con quel nome. Il finale
parametro è il "tipo di collegamento dati" del nuovo file PCAP. Questi sono gli stessi del PCAP
tipi di collegamento dati della libreria definiti in bpf.h se hai familiarità con PCAP. In questo caso,
DLT_PPP indica che il file PCAP conterrà i pacchetti con il prefisso point to
intestazioni di punti. Questo è vero poiché i pacchetti provengono dal nostro dispositivo point-to-point
autista. Altri tipi di collegamento dati comuni sono DLT_EN10MB (10 MB Ethernet) appropriati per csma
dispositivi e DLT_IEEE802_11 (IEEE 802.11) appropriato per i dispositivi Wi-Fi. Questi sono definiti
in src/network/helper/trace-helper.h se sei interessato a vedere l'elenco. Il
le voci nell'elenco corrispondono a quelle in bpf.h ma li duplichiamo per evitare una fonte PCAP
dipendenza.

A NS-3 viene restituito l'oggetto che rappresenta il file PCAP CreateFile e usato in un limite
richiamata esattamente come nel caso ASCII.

Una deviazione importante: è importante notare che anche se entrambi questi oggetti lo sono
dichiarato in modi molto simili,

pt file ...
pt flusso ...

Gli oggetti sottostanti sono completamente diversi. Ad esempio, il pt è un
puntatore intelligente a un NS-3 Oggetto che è una cosa abbastanza pesante che supporta
Attributi ed è integrato nel sistema Config. Il pt, Sulla
d'altra parte, è un puntatore intelligente a un oggetto contato di riferimento che è molto leggero
cosa. Ricordati di guardare l'oggetto a cui ti riferisci prima di fare qualsiasi ipotesi
sui "poteri" che l'oggetto può avere.

Ad esempio, dai un'occhiata src/network/utils/pcap-file-wrapper.h nella distribuzione e
avviso,

classe PcapFileWrapper : oggetto pubblico

quella classe PcapFileWrapper offre NS-3 Oggetto in virtù della sua eredità. Allora guarda
src/network/model/output-stream-wrapper.h e nota,

classe OutputStreamWrapper : pubblico
SimpleRefCount

che questo oggetto non è un NS-3 Oggetto a tutti, è "semplicemente" un oggetto C++ che capita
supportare il conteggio intrusivo dei riferimenti.

Il punto qui è che solo perché leggi pt non significa necessariamente
che qualcosa offre NS-3 Oggetto su cui puoi appendere NS-3 Attributi, per esempio.

Ora, torniamo all'esempio. Se crei ed esegui questo esempio,

$ ./waf --esegui sesto

vedrai apparire gli stessi messaggi di quando hai eseguito "quinto", ma lo faranno due nuovi file
appaiono nella directory di primo livello del tuo NS-3 distribuzione.

sesto.cwnd sesto.pcap

Poiché "sesto.cwnd" è un file di testo ASCII, puoi visualizzarlo con gatto o il tuo file preferito
spettatore.

1 0 536
1.0093 536 1072
1.01528 1072 1608
1.02167 1608 2144
...
9.69256 5149 5204
9.89311 5204 5259

Hai un file separato da tabulazioni con un timestamp, una vecchia finestra di congestione e una nuova
finestra di congestione adatta per l'importazione diretta nel tuo programma di stampa. Non ci sono
stampe estranee nel file, non è richiesta alcuna analisi o modifica.

Dal momento che "sixth.pcap" è un file PCAP, puoi fiew con esso tcpdump.

lettura dal file sesto.pcap, tipo di collegamento 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], lunghezza 504
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], lunghezza 504
...
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], lunghezza 536
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], lunghezza 536

Hai un file PCAP con i pacchetti che sono stati eliminati nella simulazione. Non ci sono
altri pacchetti presenti nel file e non c'è nient'altro presente per fare vita
difficile.

È stato un lungo viaggio, ma ora siamo a un punto in cui possiamo apprezzare il NS-3
sistema di tracciamento. Abbiamo tirato fuori eventi importanti dal mezzo di un'implementazione TCP
e un driver di dispositivo. Abbiamo archiviato quegli eventi direttamente in file utilizzabili con quelli comunemente conosciuti
utensili. L'abbiamo fatto senza modificare il codice principale coinvolto e l'abbiamo fatto
solo 18 righe di codice:

vuoto statico
CwndChange (Ptr stream, uint32_t oldCwnd, uint32_t newCwnd)
{
NS_LOG_UNCOND (Simulatore::Now()).GetSeconds() << "\t" << newCwnd);
*stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl;
}

...

AsciiTraceHelper asciiTraceHelper;
pt flusso = asciiTraceHelper.CreateFileStream ("sesto.cwnd");
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream));

...

vuoto statico
RxDrop (Ptr dossier, pt P)
{
NS_LOG_UNCOND ("RxDrop su " << Simulator::Now ().GetSeconds ());
file->Scrivi(Simulatore::Ora(), p);
}

...

PcapHelper pcapHelper;
pt file = pcapHelper.CreateFile ("sesto.pcap", "w", PcapHelper::DLT_PPP);
devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file));

Traccia Helpers
Le NS-3 gli helper di traccia forniscono un ambiente ricco per la configurazione e la selezione di diversi
tracciare gli eventi e scriverli su file. Nelle sezioni precedenti, principalmente
BuildingTopologies, abbiamo visto diverse varietà di metodi di supporto di traccia progettati
per l'uso all'interno di altri helper (dispositivo).

Forse ricorderete di aver visto alcune di queste variazioni:

pointToPoint.EnablePcapAll ("secondo");
pointToPoint.EnablePcap ("secondo", p2pNodes.Get (0)->GetId (), 0);
csma.EnablePcap ("terzo", csmaDevices.Get (0), true);
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));

Ciò che potrebbe non essere ovvio, tuttavia, è che esiste un modello coerente per tutti
metodi relativi alla traccia trovati nel sistema. Ora ci prendiamo un po' di tempo e diamo un'occhiata
al "quadro generale".

Attualmente ci sono due casi d'uso principali degli helper di tracciamento NS-3: aiutanti del dispositivo
e assistenti di protocollo. Gli assistenti del dispositivo esaminano il problema di specificare quali tracce
deve essere abilitato tramite una coppia (nodo, dispositivo). Ad esempio, potresti voler specificare
che la traccia PCAP debba essere abilitata su un particolare dispositivo su un nodo specifico. Questo
segue dal NS-3 modello concettuale del dispositivo, e anche i modelli concettuali del
vari dispositivi di supporto. A seguito naturalmente di ciò, i file creati seguono a
- - convenzione di denominazione.

Gli helper del protocollo esaminano il problema di specificare quali tracce devono essere abilitate
una coppia di protocollo e interfaccia. Ciò deriva dal NS-3 stack di protocollo concettuale
modello e anche i modelli concettuali degli helper dello stack Internet. Naturalmente, la traccia
i file dovrebbero seguire a - - convenzione di denominazione.

Gli helper di traccia rientrano quindi naturalmente in una tassonomia bidimensionale. Ci sono
sottigliezze che impediscono a tutte e quattro le classi di comportarsi in modo identico, ma ci sforziamo di farlo
farli funzionare tutti nel modo più simile possibile; e quando possibile ci sono analoghi per
tutti i metodi in tutte le classi.

┌───────────────┬──────┬───────┐
│ │ PCAP │ ASCII │
└────────────────┴──────┴───────┘

│Assistente dispositivo │ │ │
├───────────────┼──────┼───────┤
│Protocollo Helper │ │ │
└────────────────┴──────┴───────┘

Usiamo un approccio chiamato a mixin per aggiungere funzionalità di tracciamento alle nostre classi di supporto. UN
mixin è una classe che fornisce funzionalità quando viene ereditata da una sottoclasse.
Ereditare da un mixin non è considerato una forma di specializzazione ma è davvero un modo per farlo
raccogliere funzionalità.

Diamo una rapida occhiata a tutti e quattro questi casi e ai rispettivi mixin.

Dispositivo Helpers
PCAP
L'obiettivo di questi helper è semplificare l'aggiunta di una funzione di traccia PCAP coerente a un file
NS-3 dispositivo. Vogliamo che tutte le varie versioni della traccia PCAP funzionino allo stesso modo
tutti i dispositivi, quindi i metodi di questi helper vengono ereditati dagli helper dei dispositivi. Guarda
at src/network/helper/trace-helper.h se vuoi seguire la discussione mentre guardi
codice reale.

La classe PcapHelperForDevice è un mixin fornisce la funzionalità di alto livello per l'utilizzo
Tracciamento PCAP in un NS-3 dispositivo. Ogni dispositivo deve implementare un unico metodo virtuale
ereditato da questa classe.

virtual void EnablePcapInternal (std::string prefix, Ptr nd, bool promiscuo, bool nomefile esplicito) = 0;

La firma di questo metodo riflette la visione incentrata sul dispositivo della situazione in questo momento
livello. Tutti i metodi pubblici ereditati dalla classe PcapUserHelperForDevice ridurre a
chiamando questo singolo metodo di implementazione dipendente dal dispositivo. Ad esempio, il livello più basso
metodo PCAP,

void EnablePcap (std::string prefix, Ptr nd, bool promiscuus = false, bool esplicitoFilename = false);

chiamerà l'implementazione del dispositivo di AbilitaPcapInternal direttamente. Tutti gli altri PCAP pubblici
i metodi di tracciamento si basano su questa implementazione per fornire un livello utente aggiuntivo
funzionalità. Ciò che questo significa per l'utente è che tutti gli assistenti del dispositivo nel sistema lo faranno
disporre di tutti i metodi di traccia PCAP disponibili; e questi metodi funzioneranno tutti allo stesso modo
attraverso i dispositivi se il dispositivo implementa AbilitaPcapInternal correttamente.

Metodi
void EnablePcap (std::string prefix, Ptr nd, bool promiscuus = false, bool esplicitoFilename = false);
void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool esplicitoFilename = false);
void EnablePcap (std::string prefix, NetDeviceContainer d, bool promiscuous = false);
void EnablePcap (std::string prefix, NodeContainer n, bool promiscuous = false);
void EnablePcap (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool promiscuous = false);
void EnablePcapAll (std::string prefisso, bool promiscuo = false);

In ciascuno dei metodi mostrati sopra, c'è un parametro predefinito chiamato promiscuo che
il valore predefinito è falso. Questo parametro indica che la traccia non deve essere raccolta
modalità promiscua. Se vuoi che le tue tracce includano tutto il traffico visto dal dispositivo
(e se il dispositivo supporta una modalità promiscua) aggiungi semplicemente un parametro true a uno qualsiasi dei file
chiamate sopra. Per esempio,

pt nd;
...
helper.EnablePcap ("prefisso", nd, true);

abiliterà le acquisizioni in modalità promiscua su NetDevice specificato da nd.

I primi due metodi includono anche un parametro predefinito chiamato nomefile esplicito quella volontà
essere discusso di seguito.

Ti invitiamo a leggere la documentazione API per la classe PcapHelperForDevice per trovare
i dettagli di questi metodi; ma per riassumere...

· È possibile abilitare la traccia PCAP su una particolare coppia nodo/dispositivo di rete fornendo a
pt a un AbilitaPcap metodo. Il Ptr è implicito dal dispositivo di rete
deve appartenere esattamente a un nodo. Per esempio,

pt nd;
...
helper.EnablePcap ("prefisso", nd);

· È possibile abilitare la traccia PCAP su una particolare coppia nodo/dispositivo di rete fornendo a
std::stringa che rappresenta una stringa di servizio del nome oggetto in un AbilitaPcap metodo. Il
pt viene cercato dalla stringa del nome. Ancora una volta, il è implicito poiché
il dispositivo net denominato deve appartenere esattamente a un nodo. Per esempio,

Nomi::Add ("server" ...);
Nomi::Add ("server/eth0" ...);
...
helper.EnablePcap ("prefisso", "server/ath0");

· È possibile abilitare la traccia PCAP su una raccolta di coppie nodo/rete-dispositivo fornendo a
NetDeviceContenitore. Per ciascuno NetDevice nel contenitore viene verificato il tipo. Per ciascuno
dispositivo del tipo corretto (lo stesso tipo gestito dall'helper del dispositivo), la traccia è
abilitato. Ancora una volta, il è implicito poiché il dispositivo di rete trovato deve appartenere
esattamente un nodo. Per esempio,

NetDeviceContainer d = ...;
...
helper.EnablePcap ("prefisso", d);

· È possibile abilitare la traccia PCAP su una raccolta di coppie nodo/rete-dispositivo fornendo a
NodoContenitore. Per ogni nodo nel NodoContenitore è allegato NetDevice sono iterati.
Per ciascun NetDevice collegato a ciascun nodo nel contenitore, il tipo di quel dispositivo è
controllato. Per ogni dispositivo del tipo corretto (lo stesso tipo gestito dal dispositivo
helper), la traccia è abilitata.

NodoContenitore n;
...
helper.EnablePcap ("prefisso", n);

· È possibile abilitare la traccia PCAP sulla base dell'ID del nodo e dell'ID del dispositivo, nonché con
esplicito Ptr. Ogni nodo nel sistema ha un ID nodo intero e ogni dispositivo connesso
a un nodo ha un ID dispositivo intero.

helper.EnablePcap ("prefisso", 21, 1);

· Infine, puoi abilitare il tracciamento PCAP per tutti i dispositivi nel sistema, con lo stesso tipo
come quella gestita dall'assistente del dispositivo.

helper.EnablePcapAll ("prefisso");

I nomi dei file
Implicita nelle descrizioni del metodo di cui sopra è la costruzione di un nome file completo da parte di
il metodo di attuazione. Per convenzione, PCAP traccia nel NS-3 sistema sono della forma
- id>- id>.pcap

Come accennato in precedenza, ogni nodo nel sistema avrà un ID nodo assegnato dal sistema; e
ogni dispositivo avrà un indice di interfaccia (chiamato anche ID dispositivo) relativo al suo nodo.
Per impostazione predefinita, quindi, un file di traccia PCAP creato come risultato dell'abilitazione della traccia sul primo
dispositivo del nodo 21 utilizzando il prefisso "prefisso" sarebbe prefisso-21-1.pcap.

Puoi sempre usare il file NS-3 servizio nome oggetto per renderlo più chiaro. Ad esempio, se
si utilizza il servizio nome oggetto per assegnare il nome "server" al nodo 21, il PCAP risultante
il nome del file di traccia diventerà automaticamente, prefisso-server-1.pcap e se assegni anche il
nome "eth0" al dispositivo, il nome del file PCAP lo raccoglierà automaticamente e sarà
detto prefisso-server-eth0.pcap.

Infine, due dei metodi mostrati sopra,

void EnablePcap (std::string prefix, Ptr nd, bool promiscuus = false, bool esplicitoFilename = false);
void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool esplicitoFilename = false);

avere un parametro predefinito chiamato nomefile esplicito. Quando è impostato su true, questo parametro
disabilita il meccanismo di completamento automatico del nome file e consente di creare un file esplicito
nome del file. Questa opzione è disponibile solo nei metodi che abilitano la traccia PCAP su a
unico dispositivo.

Ad esempio, per fare in modo che un dispositivo di supporto crei un singolo PCAP promiscuo
catturare un file con un nome specifico il mio-pcap-file.pcap su un determinato dispositivo, si potrebbe:

pt nd;
...
helper.EnablePcap ("my-pcap-file.pcap", nd, true, true);

Il primo vero parametro abilita tracce in modalità promiscua e il secondo dice all'helper
interpretare il prefisso parametro come un nome file completo.

ASCII
Il comportamento dell'helper di traccia ASCII mixin è sostanzialmente simile alla versione PCAP.
Dare un'occhiata a src/network/helper/trace-helper.h se vuoi seguire la discussione
mentre guardi il codice reale.

La classe AsciiTraceHelperForDevice aggiunge la funzionalità di alto livello per l'utilizzo di ASCII
traccia a una classe di supporto del dispositivo. Come nel caso PCAP, ogni dispositivo deve implementare a
singolo metodo virtuale ereditato dalla traccia ASCII mixin.

virtual void EnableAsciiInternal (Ptr flusso,
std::prefisso di stringa,
pt nd,
bool nomefile esplicito) = 0;

La firma di questo metodo riflette la visione incentrata sul dispositivo della situazione in questo momento
livello; e anche il fatto che l'helper possa scrivere su un flusso di output condiviso. Tutto di
i metodi pubblici relativi alla traccia ASCII ereditati dalla classe AsciiTraceHelperForDevice
ridurre a chiamare questo singolo metodo di implementazione dipendente dal dispositivo. Ad esempio, il
metodi di traccia ascii di livello più basso,

void EnableAscii (std::string prefix, Ptr nd, bool esplicitoFilename = false);
void EnableAscii (Ptr ruscello, pt nd);

chiamerà l'implementazione del dispositivo di AbilitaAsciiInternal direttamente, fornendo a
prefisso o flusso valido. Tutti gli altri metodi di traccia ASCII pubblici si baseranno su questi
funzioni di basso livello per fornire funzionalità aggiuntive a livello di utente. Cosa significa questo
l'utente è che tutti gli assistenti del dispositivo nel sistema disporranno di tutti i metodi di traccia ASCII
a disposizione; e questi metodi funzioneranno tutti allo stesso modo su tutti i dispositivi se i dispositivi
realizzare Abilitazione interna correttamente.

Metodi
void EnableAscii (std::string prefix, Ptr nd, bool esplicitoFilename = false);
void EnableAscii (Ptr ruscello, pt nd);

void EnableAscii (std::string prefix, std::string ndName, bool esplicitoFilename = false);
void EnableAscii (Ptr stream, std::string ndName);

void EnableAscii (std::string prefisso, NetDeviceContainer d);
void EnableAscii (Ptr flusso, NetDeviceContainer d);

void EnableAscii (std::string prefisso, NodeContainer n);
void EnableAscii (Ptr flusso, NodeContainer n);

void EnableAsciiAll (std::string prefisso);
void EnableAsciiAll (Ptr flusso);

void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool esplicitoFilename);
void EnableAscii (Ptr stream, uint32_t nodeid, uint32_t deviceid);

Ti invitiamo a leggere la documentazione API per la classe AsciiTraceHelperForDevice a
trovare i dettagli di questi metodi; ma per riassumere...

· Sono disponibili il doppio dei metodi disponibili per la traccia ASCII rispetto a PCAP
tracciare. Questo perché, oltre al modello in stile PCAP in cui traccia da ciascuno
la coppia univoca di nodo/dispositivo viene scritta in un file univoco, supportiamo un modello in cui trace
le informazioni per molte coppie nodo/dispositivo vengono scritte in un file comune. Ciò significa che il
- - il meccanismo di generazione del nome file è sostituito da un meccanismo a
fare riferimento a un file comune; e il numero di metodi API è raddoppiato per consentire tutto
combinazioni.

· Proprio come nella traccia PCAP, puoi abilitare la traccia ASCII su un particolare (nodo, dispositivo di rete)
coppia fornendo a pt a un Abilita Ascii metodo. Il Ptr è implicito
poiché il dispositivo di rete deve appartenere esattamente a un nodo. Per esempio,

pt nd;
...
helper.EnableAscii ("prefisso", nd);

· I primi quattro metodi includono anche un parametro predefinito chiamato nomefile esplicito che
operare in modo simile a parametri equivalenti nel caso PCAP.

In questo caso, nessun contesto di traccia viene scritto nel file di traccia ASCII poiché lo sarebbe
ridondante. Il sistema selezionerà il nome del file da creare utilizzando le stesse regole di
descritto nella sezione PCAP, tranne per il fatto che il file avrà il suffisso TR invece di
.pcap.

· Se si desidera abilitare la traccia ASCII su più di un dispositivo di rete e inviare tutte le tracce
in un singolo file, puoi farlo anche usando un oggetto per fare riferimento a un singolo file.
Lo abbiamo già visto nell'esempio "cwnd" sopra:

pt nd1;
pt nd2;
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (flusso, nd1);
helper.EnableAscii (flusso, nd2);

In questo caso, traccia i contesti sono scritti nel file di traccia ASCII poiché sono obbligatori
per disambiguare le tracce dai due dispositivi. Si noti che poiché l'utente è completamente
specificando il nome del file, la stringa dovrebbe includere l'estensione ,tr suffisso per coerenza.

· È possibile abilitare la traccia ASCII su una coppia particolare (nodo, dispositivo di rete) fornendo a
std::stringa che rappresenta una stringa di servizio del nome oggetto in un AbilitaPcap metodo. Il
pt viene cercato dalla stringa del nome. Ancora una volta, il è implicito poiché
il dispositivo net denominato deve appartenere esattamente a un nodo. Per esempio,

Nomi::Add ("client" ...);
Nomi::Add ("client/eth0" ...);
Nomi::Add ("server" ...);
Nomi::Add ("server/eth0" ...);
...
helper.EnableAscii ("prefisso", "client/eth0");
helper.EnableAscii ("prefisso", "server/eth0");

Ciò risulterebbe in due file denominati ``prefix-client-eth0.tr`` e
``prefix-server-eth0.tr`` con tracce per ogni dispositivo nel file
rispettivo file di traccia. Poiché tutte le funzioni di ``EnableAscii``
sono sovraccaricati per prendere un wrapper di flusso, puoi usare quel modulo come
bene::

Nomi::Add ("client" ...);
Nomi::Add ("client/eth0" ...);
Nomi::Add ("server" ...);
Nomi::Add ("server/eth0" ...);
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (stream, "client/eth0");
helper.EnableAscii (stream, "server/eth0");

Ciò risulterebbe in un unico file di traccia chiamato nome-file-traccia.tr che contiene tutto
gli eventi di traccia per entrambi i dispositivi. Gli eventi sarebbero disambiguati dal contesto di traccia
stringhe.

· È possibile abilitare la traccia ASCII su una raccolta di coppie (nodo, dispositivo di rete) fornendo a
NetDeviceContenitore. Per ciascuno NetDevice nel contenitore viene verificato il tipo. Per ciascuno
dispositivo del tipo corretto (lo stesso tipo gestito dall'helper del dispositivo), la traccia è
abilitato. Ancora una volta, il è implicito poiché il dispositivo di rete trovato deve appartenere
esattamente un nodo. Per esempio,

NetDeviceContainer d = ...;
...
helper.EnableAscii ("prefisso", d);

Ciò comporterebbe la creazione di un numero di file di traccia ASCII,
ognuno dei quali segue il `` - - .tr``
convenzione.

La combinazione di tutte le tracce in un unico file viene eseguita in modo simile agli esempi
sopra:

NetDeviceContainer d = ...;
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAscii (flusso, d);

· È possibile abilitare la traccia ASCII su una raccolta di coppie (nodo, dispositivo di rete) fornendo a
NodoContenitore. Per ogni nodo nel NodoContenitore è allegato NetDevice sono iterati.
Per ciascun NetDevice collegato a ciascun nodo nel contenitore, il tipo di quel dispositivo è
controllato. Per ogni dispositivo del tipo corretto (lo stesso tipo gestito dal dispositivo
helper), la traccia è abilitata.

NodoContenitore n;
...
helper.EnableAscii ("prefisso", n);

Ciò comporterebbe la creazione di numerosi file di traccia ASCII, ognuno dei quali segue
, il - id>- id>.tr convenzione. Combinando tutte le tracce in a
il singolo file viene eseguito in modo simile agli esempi precedenti.

· È possibile abilitare la traccia PCAP sulla base dell'ID del nodo e dell'ID del dispositivo, nonché con
esplicito Ptr. Ogni nodo nel sistema ha un ID nodo intero e ogni dispositivo connesso
a un nodo ha un ID dispositivo intero.

helper.EnableAscii ("prefisso", 21, 1);

Naturalmente, le tracce possono essere combinate in un unico file come mostrato sopra.

· Infine, puoi abilitare il tracciamento PCAP per tutti i dispositivi nel sistema, con lo stesso tipo
come quella gestita dall'assistente del dispositivo.

helper.EnableAsciiAll ("prefisso");

Ciò comporterebbe la creazione di un numero di file di traccia ASCII, uno per ogni dispositivo
nel sistema del tipo gestito dall'helper. Tutti questi file seguiranno il
- id>- id>.tr convenzione. Combinando tutte le tracce in un unico
il file viene eseguito in modo simile agli esempi precedenti.

I nomi dei file
Implicita nelle descrizioni del metodo in stile prefisso di cui sopra è la costruzione del completo
nomi di file dal metodo di implementazione. Per convenzione, ASCII traccia nel NS-3 sistema
sono della forma - id>- id>.tr

Come accennato in precedenza, ogni nodo nel sistema avrà un ID nodo assegnato dal sistema; e
ogni dispositivo avrà un indice di interfaccia (chiamato anche ID dispositivo) relativo al suo nodo.
Per impostazione predefinita, quindi, un file di traccia ASCII creato come risultato dell'abilitazione della traccia sul primo
dispositivo del nodo 21, utilizzando il prefisso "prefisso", sarebbe prefisso-21-1.tr.

Puoi sempre usare il file NS-3 servizio nome oggetto per renderlo più chiaro. Ad esempio, se
si utilizza il servizio nome oggetto per assegnare il nome "server" al nodo 21, il risultato
Il nome del file di traccia ASCII diventerà automaticamente, prefisso-server-1.tr e se assegni anche tu
il nome "eth0" al dispositivo, il nome del file di traccia ASCII lo rileverà automaticamente
ed essere chiamato prefisso-server-eth0.tr.

Molti dei metodi hanno un parametro predefinito chiamato nomefile esplicito. Quando impostato su
true, questo parametro disabilita il meccanismo di completamento automatico del nome file e ti consente
per creare un nome file esplicito. Questa opzione è disponibile solo nei metodi che richiedono a
prefisso e abilita la traccia su un singolo dispositivo.

Protocollo Helpers
PCAP
L'obiettivo di questi mixin è semplificare l'aggiunta di una funzione di traccia PCAP coerente a
protocolli. Vogliamo che tutte le varie versioni della traccia PCAP funzionino allo stesso modo su tutte
protocolli, quindi i metodi di questi helper vengono ereditati dagli stack helper. Date un'occhiata al
src/network/helper/trace-helper.h se vuoi seguire la discussione mentre guardi
codice reale.

In questa sezione illustreremo i metodi applicati al protocollo Ipv4. A
specificare le tracce in protocolli simili, basta sostituire il tipo appropriato. Per esempio,
Usa un pt invece di a pt e chiama AbilitaPcapIpv6 invece di AbilitaPcapIpv4.

La classe PcapHelperForIpv4 fornisce la funzionalità di alto livello per l'utilizzo della traccia PCAP
nel Ipv4 protocollo. Ciascun helper di protocollo che abilita questi metodi deve implementarne uno
metodo virtuale ereditato da questa classe. Ci sarà un'implementazione separata per
Ipv6, ad esempio, ma l'unica differenza sarà nei nomi e nelle firme dei metodi.
Sono necessari nomi di metodi diversi per disambiguare la classe Ipv4 da Ipv6 che sono entrambi
derivato da classe Oggettoe metodi che condividono la stessa firma.

vuoto virtuale EnablePcapIpv4Internal (std::prefisso stringa,
pt ipv4,
interfaccia uint32_t,
bool nomefile esplicito) = 0;

La firma di questo metodo riflette il protocollo e la vista incentrata sull'interfaccia di
situazione a questo livello. Tutti i metodi pubblici ereditati dalla classe PcapHelperForIpv4
ridurre a chiamare questo singolo metodo di implementazione dipendente dal dispositivo. Ad esempio, il
metodo PCAP di livello più basso,

void EnablePcapIpv4 (std::string prefix, Ptr ipv4, interfaccia uint4_t, bool esplicitoFilename = false);

chiamerà l'implementazione del dispositivo di AbilitaPcapIpv4Internal direttamente. Tutti gli altri pubblici
I metodi di traccia PCAP si basano su questa implementazione per fornire un livello utente aggiuntivo
funzionalità. Ciò che questo significa per l'utente è che tutti gli helper di protocollo nel sistema
avrà tutti i metodi di traccia PCAP disponibili; e questi metodi funzioneranno tutti nel
allo stesso modo attraverso i protocolli se l'helper implementa AbilitaPcapIpv4Internal correttamente.

Metodi
Questi metodi sono progettati per essere in corrispondenza uno-a-uno con il nodo e
NetDevice- versioni centriche delle versioni del dispositivo. Invece di Nodo e NetDevice (coppia),
vincoli, utilizziamo vincoli di protocollo e di interfaccia.

Nota che, proprio come nella versione del dispositivo, ci sono sei metodi:

void EnablePcapIpv4 (std::string prefix, Ptr ipv4, interfaccia uint4_t, bool esplicitoFilename = false);
void EnablePcapIpv4 (std::string prefix, std::string ipv4Name, interfaccia uint32_t, bool esplicitoFilename = false);
void EnablePcapIpv4 (std::prefisso di stringa, Ipv4InterfaceContainer c);
void EnablePcapIpv4 (std::prefisso di stringa, NodeContainer n);
void EnablePcapIpv4 (std::string prefix, uint32_t nodeid, uint32_t interface, bool esplicitoFilename);
void EnablePcapIpv4All (std::prefisso stringa);

Ti invitiamo a leggere la documentazione API per la classe PcapHelperForIpv4 per trovare l'
dettagli di questi metodi; ma per riassumere...

· È possibile abilitare la traccia PCAP su una particolare coppia protocollo/interfaccia fornendo a
pt che a interfaccia a un AbilitaPcap metodo. Per esempio,

pt ipv4 = nodo->GetObject ();
...
helper.EnablePcapIpv4 ("prefisso", ipv4, 0);

· È possibile abilitare la traccia PCAP su una particolare coppia nodo/dispositivo di rete fornendo a
std::stringa che rappresenta una stringa di servizio del nome oggetto in un AbilitaPcap metodo. Il
pt viene cercato dalla stringa del nome. Per esempio,

Nomi::Add ("serverIPv4" ...);
...
helper.EnablePcapIpv4 ("prefisso", "serverIpv4", 1);

· È possibile abilitare la traccia PCAP su una raccolta di coppie protocollo/interfaccia fornendo un
Contenitore di interfaccia IPv4. Per ciascuno Ipv4 / coppia di interfaccia nel contenitore il protocollo
il tipo è controllato. Per ogni protocollo del tipo corretto (lo stesso tipo gestito da
l'assistente del dispositivo), il tracciamento è abilitato per l'interfaccia corrispondente. Per esempio,

nodi NodeContainer;
...
Dispositivi NetDeviceContainer = deviceHelper.Install (nodi);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfacce Ipv4InterfaceContainer = ipv4.Assign (dispositivi);
...
helper.EnablePcapIpv4 ("prefisso", interfacce);

· È possibile abilitare la traccia PCAP su una raccolta di coppie protocollo/interfaccia fornendo a
NodoContenitore. Per ogni nodo nel NodoContenitore viene trovato il protocollo appropriato.
Per ogni protocollo vengono enumerate le sue interfacce e viene abilitata la traccia sul risultante
coppie. Per esempio,

NodoContenitore n;
...
helper.EnablePcapIpv4 ("prefisso", n);

· È anche possibile abilitare la traccia PCAP sulla base dell'ID nodo e dell'interfaccia. In questo
caso, il node-id viene tradotto in a Ptr e si cerca il protocollo appropriato
nel nodo. Il protocollo e l'interfaccia risultanti vengono utilizzati per specificare il risultato
fonte di traccia.

helper.EnablePcapIpv4 ("prefisso", 21, 1);

· Infine, è possibile abilitare il tracciamento PCAP per tutte le interfacce del sistema, con le associate
il protocollo è dello stesso tipo di quello gestito dall'helper del dispositivo.

helper.EnablePcapIpv4All ("prefisso");

I nomi dei file
Implicita in tutte le descrizioni del metodo di cui sopra è la costruzione del completo
nomi di file dal metodo di implementazione. Per convenzione, le tracce PCAP prese per i dispositivi in
, il NS-3 sistema sono della forma " - - .pcap". Nel caso di
tracce di protocollo, esiste una corrispondenza biunivoca tra protocolli e Nodes. Questo
è perché protocollo Oggetti sono aggregati a Nodo Oggetti. Dal momento che non esiste un globale
id protocollo nel sistema, utilizziamo l'ID nodo corrispondente nella denominazione dei file. Perciò
esiste la possibilità di collisioni di nomi di file nei nomi di file di traccia scelti automaticamente.
Per questo motivo, la convenzione del nome file viene modificata per le tracce di protocollo.

Come accennato in precedenza, ogni nodo nel sistema avrà un ID nodo assegnato dal sistema.
Poiché esiste una corrispondenza uno a uno tra le istanze del protocollo e le istanze del nodo
usiamo l'id del nodo. Ogni interfaccia ha un ID interfaccia relativo al proprio protocollo. Noi usiamo
la convenzione" -n -io .pcap" per la denominazione dei file di traccia in
aiutanti del protocollo.

Pertanto, per impostazione predefinita, viene creato un file di traccia PCAP come risultato dell'abilitazione della traccia
l'interfaccia 1 del protocollo Ipv4 del nodo 21 utilizzando il prefisso "prefisso" sarebbe
"prefisso-n21-i1.pcap".

Puoi sempre usare il file NS-3 servizio nome oggetto per renderlo più chiaro. Ad esempio, se
si utilizza il servizio nome oggetto per assegnare il nome "serverIpv4" al Ptr su Nodo
21, il nome del file di traccia PCAP risultante diventerà automaticamente,
"prefisso-nserverIpv4-i1.pcap".

Molti dei metodi hanno un parametro predefinito chiamato nomefile esplicito. Quando impostato su
true, questo parametro disabilita il meccanismo di completamento automatico del nome file e ti consente
per creare un nome file esplicito. Questa opzione è disponibile solo nei metodi che richiedono a
prefisso e abilita la traccia su un singolo dispositivo.

ASCII
Il comportamento degli helper di traccia ASCII è sostanzialmente simile al caso PCAP. Prendi un
guardare src/network/helper/trace-helper.h se vuoi seguire la discussione mentre
guardando il codice reale.

In questa sezione illustreremo i metodi applicati al protocollo Ipv4. A
specificare le tracce in protocolli simili, basta sostituire il tipo appropriato. Per esempio,
Usa un pt invece di a pt e chiama Abilita AsciiIpv6 invece di
Abilita AsciiIpv4.

La classe AsciiTraceHelperForIpv4 aggiunge la funzionalità di alto livello per l'utilizzo di ASCII
tracciamento a un assistente di protocollo. Ogni protocollo che abilita questi metodi deve implementare a
singolo metodo virtuale ereditato da questa classe.

virtual void EnableAsciiIpv4Internal (Ptr flusso,
std::prefisso di stringa,
pt ipv4,
interfaccia uint32_t,
bool nomefile esplicito) = 0;

La firma di questo metodo riflette la vista incentrata sul protocollo e sull'interfaccia di
situazione a questo livello; e anche il fatto che l'assistente possa scrivere a una persona condivisa
flusso di uscita. Tutti i metodi pubblici ereditati dalla classe
PcapAndAsciiTraceHelperForIpv4 ridurre a chiamare questo singolo dispositivo dipendente
metodo di attuazione. Ad esempio, i metodi di traccia ASCII di livello più basso,

void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interfaccia uint4_t, bool esplicitoFilename = false);
void EnableAsciiIpv4 (Ptr ruscello, pt ipv4, interfaccia uint4_t);

chiamerà l'implementazione del dispositivo di AbilitaAsciiIpv4Internal direttamente, fornendo entrambi
il prefisso o il flusso. Tutti gli altri metodi di traccia ASCII pubblici si baseranno su questi
funzioni di basso livello per fornire funzionalità aggiuntive a livello di utente. Cosa significa questo
l'utente è che tutti gli assistenti del dispositivo nel sistema disporranno di tutti i metodi di traccia ASCII
a disposizione; e questi metodi funzioneranno tutti allo stesso modo su tutti i protocolli se il
implementano i protocolli Abilitazione interna correttamente.

Metodi
void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, interfaccia uint4_t, bool esplicitoFilename = false);
void EnableAsciiIpv4 (Ptr ruscello, pt ipv4, interfaccia uint4_t);

void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, interfaccia uint32_t, bool esplicitoFilename = false);
void EnableAsciiIpv4 (Ptr stream, std::string ipv4Name, interfaccia uint32_t);

void EnableAsciiIpv4 (std::prefisso di stringa, Ipv4InterfaceContainer c);
void EnableAsciiIpv4 (Ptr flusso, Ipv4InterfaceContainer c);

void EnableAsciiIpv4 (std::prefisso di stringa, NodeContainer n);
void EnableAsciiIpv4 (Ptr flusso, NodeContainer n);

void EnableAsciiIpv4All (std::prefisso di stringa);
void EnableAsciiIpv4All (Ptr flusso);

void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool esplicitoFilename);
void EnableAsciiIpv4 (Ptr stream, uint32_t nodeid, interfaccia uint32_t);

Ti invitiamo a leggere la documentazione API per la classe PcapAndAsciiHelperForIpv4 a
trovare i dettagli di questi metodi; ma per riassumere...

· Sono disponibili il doppio dei metodi disponibili per la traccia ASCII rispetto a PCAP
tracciare. Questo perché, oltre al modello in stile PCAP in cui traccia da ciascuno
la coppia protocollo/interfaccia univoca viene scritta in un file univoco, supportiamo un modello in cui
le informazioni di traccia per molte coppie protocollo/interfaccia vengono scritte in un file comune. Questo
significa che il -n - meccanismo di generazione del nome file è
sostituito da un meccanismo per fare riferimento a un file comune; e il numero di metodi API è
raddoppiato per consentire tutte le combinazioni.

· Proprio come nella traccia PCAP, è possibile abilitare la traccia ASCII su un protocollo/interfaccia particolare
coppia fornendo a pt e interfaccia a un Abilita Ascii metodo. Per esempio,

pt ipv4;
...
helper.EnableAsciiIpv4 ("prefisso", ipv4, 1);

In questo caso, nessun contesto di traccia viene scritto nel file di traccia ASCII poiché lo sarebbe
ridondante. Il sistema selezionerà il nome del file da creare utilizzando le stesse regole di
descritto nella sezione PCAP, tranne per il fatto che il file avrà invece il suffisso ".tr".
di ".pcap".

· Se si desidera abilitare la traccia ASCII su più di un'interfaccia e inviare tutte le tracce
in un singolo file, puoi farlo anche usando un oggetto per fare riferimento a un singolo file.
Abbiamo già qualcosa di simile a questo nell'esempio "cwnd" sopra:

pt protocollo4 = nodo1->GetObject ();
pt protocollo4 = nodo2->GetObject ();
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (flusso, protocollo1, 1);
helper.EnableAsciiIpv4 (flusso, protocollo2, 1);

In questo caso, i contesti di traccia vengono scritti nel file di traccia ASCII poiché sono obbligatori
per disambiguare le tracce dalle due interfacce. Si noti che poiché l'utente è completamente
specificando il nome del file, la stringa dovrebbe includere ",tr" per coerenza.

· È possibile abilitare la traccia ASCII su un protocollo particolare fornendo a std::stringa
che rappresenta una stringa di servizio del nome oggetto in un AbilitaPcap metodo. Il pt is
alzato lo sguardo dalla stringa del nome. Il nei nomi dei file risultanti è implicito poiché
esiste una corrispondenza uno a uno tra le istanze del protocollo e i nodi, ad esempio,

Nomi::Add ("node1Ipv4" ...);
Nomi::Add ("node2Ipv4" ...);
...
helper.EnableAsciiIpv4 ("prefisso", "node1Ipv4", 1);
helper.EnableAsciiIpv4 ("prefisso", "node2Ipv4", 1);

Ciò risulterebbe in due file denominati "prefix-nnode1Ipv4-i1.tr" e
"prefix-nnode2Ipv4-i1.tr" con tracce per ciascuna interfaccia nel rispettivo file di traccia.
Poiché tutte le funzioni EnableAscii sono sovraccaricate per accettare un wrapper di flusso, è possibile
usa anche quel modulo:

Nomi::Add ("node1Ipv4" ...);
Nomi::Add ("node2Ipv4" ...);
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (flusso, "node1Ipv4", 1);
helper.EnableAsciiIpv4 (flusso, "node2Ipv4", 1);

Ciò risulterebbe in un unico file di traccia chiamato "trace-file-name.tr" che contiene tutto
degli eventi di traccia per entrambe le interfacce. Gli eventi sarebbero disambiguati dalla traccia
stringhe di contesto.

· È possibile abilitare la traccia ASCII su una raccolta di coppie protocollo/interfaccia fornendo un
Contenitore di interfaccia IPv4. Per ogni protocollo del tipo corretto (lo stesso tipo che è
gestito dall'helper del dispositivo), il tracciamento è abilitato per l'interfaccia corrispondente.
Ancora una volta, la è implicito poiché esiste una corrispondenza uno a uno tra ciascuno
protocollo e il suo nodo. Per esempio,

nodi NodeContainer;
...
Dispositivi NetDeviceContainer = deviceHelper.Install (nodi);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfacce Ipv4InterfaceContainer = ipv4.Assign (dispositivi);
...
...
helper.EnableAsciiIpv4 ("prefisso", interfacce);

Ciò comporterebbe la creazione di numerosi file di traccia ASCII, ognuno dei quali segue
il -n -io convenzione .tr. Combinando tutte le tracce in a
singolo file viene eseguito in modo simile agli esempi precedenti:

nodi NodeContainer;
...
Dispositivi NetDeviceContainer = deviceHelper.Install (nodi);
...
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Interfacce Ipv4InterfaceContainer = ipv4.Assign (dispositivi);
...
pt stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr");
...
helper.EnableAsciiIpv4 (stream, interfacce);

· È possibile abilitare la traccia ASCII su una raccolta di coppie protocollo/interfaccia fornendo a
NodoContenitore. Per ogni nodo nel NodoContenitore viene trovato il protocollo appropriato.
Per ogni protocollo vengono enumerate le sue interfacce e viene abilitata la traccia sul risultante
coppie. Per esempio,

NodoContenitore n;
...
helper.EnableAsciiIpv4 ("prefisso", n);

Ciò comporterebbe la creazione di numerosi file di traccia ASCII, ognuno dei quali segue
il - - convenzione .tr. Combinando tutte le tracce in a
il singolo file viene eseguito in modo simile agli esempi precedenti.

· È possibile abilitare la traccia PCAP anche sulla base dell'ID del nodo e dell'ID del dispositivo. In questo
caso, il node-id viene tradotto in a Ptr e si cerca il protocollo appropriato
nel nodo. Il protocollo e l'interfaccia risultanti vengono utilizzati per specificare il risultato
fonte di traccia.

helper.EnableAsciiIpv4 ("prefisso", 21, 1);

Naturalmente, le tracce possono essere combinate in un unico file come mostrato sopra.

· Infine, è possibile abilitare la traccia ASCII per tutte le interfacce del sistema, con associate
il protocollo è dello stesso tipo di quello gestito dall'helper del dispositivo.

helper.EnableAsciiIpv4All ("prefisso");

Ciò comporterebbe la creazione di un numero di file di traccia ASCII, uno per ciascuno
interfaccia nel sistema relativa ad un protocollo del tipo gestito dall'helper. Tutto di
questi file seguiranno il -n -io
tutte le tracce in un unico file vengono eseguite in modo simile agli esempi precedenti.

I nomi dei file
Implicita nelle descrizioni del metodo in stile prefisso di cui sopra è la costruzione del completo
nomi di file dal metodo di implementazione. Per convenzione, ASCII traccia nel NS-3 sistema
sono della forma" - - .tr"

Come accennato in precedenza, ogni nodo nel sistema avrà un ID nodo assegnato dal sistema.
Poiché esiste una corrispondenza uno-a-uno tra protocolli e nodi, utilizziamo node-id
per identificare l'identità del protocollo. Ogni interfaccia su un determinato protocollo avrà un
indice di interfaccia (chiamato anche semplicemente interfaccia) relativo al suo protocollo. Per impostazione predefinita,
quindi, un file di traccia ASCII creato come risultato dell'abilitazione della traccia sul primo dispositivo di
Il nodo 21, utilizzando il prefisso "prefisso", sarebbe "prefisso-n21-i1.tr". Usa il prefisso per
disambiguare più protocolli per nodo.

Puoi sempre usare il file NS-3 servizio nome oggetto per renderlo più chiaro. Ad esempio, se
si utilizza il servizio nome oggetto per assegnare il nome "serverIpv4" al protocollo su Node
21 e specificare anche l'interfaccia uno, il nome del file di traccia ASCII risultante verrà automaticamente
diventa "prefix-nserverIpv4-1.tr".

Molti dei metodi hanno un parametro predefinito chiamato nomefile esplicito. Quando impostato su
true, questo parametro disabilita il meccanismo di completamento automatico del nome file e ti consente
per creare un nome file esplicito. Questa opzione è disponibile solo nei metodi che richiedono a
prefisso e abilita la traccia su un singolo dispositivo.

Sommario
NS-3 include un ambiente estremamente ricco che consente agli utenti a più livelli di personalizzare
i tipi di informazioni che possono essere estratte dalle simulazioni.

Esistono funzioni di supporto di alto livello che consentono agli utenti di controllare semplicemente la raccolta di
output predefiniti con una granularità fine. Ci sono funzioni di supporto di livello medio da consentire
utenti più sofisticati per personalizzare il modo in cui le informazioni vengono estratte e salvate; e lì
sono funzioni principali di basso livello per consentire agli utenti esperti di modificare il sistema per presentare nuovi e
informazioni precedentemente non esportate in un modo che sarà immediatamente accessibile agli utenti all'indirizzo
livelli superiori.

Questo è un sistema molto completo e ci rendiamo conto che è molto da digerire, soprattutto
per i nuovi utenti o per coloro che non hanno familiarità con C++ e i suoi idiomi. Consideriamo
il sistema di tracciamento una parte molto importante di NS-3 e quindi consiglia di diventare familiare come
possibile con esso. Probabilmente è il caso che la comprensione del resto del NS-3 sistema
sarà abbastanza semplice una volta che avrai imparato il sistema di tracciamento

DATA COLLEZIONE


Il nostro capitolo dell'esercitazione finale introduce alcuni componenti a cui sono stati aggiunti NS-3 nella versione
3.18, e che sono ancora in fase di sviluppo. Questa sezione tutorial è anche a
lavori in corso.

Motivazione
Uno dei punti principali dell'esecuzione delle simulazioni è generare dati di output, sia per
scopi di ricerca o semplicemente per conoscere il sistema. Nel capitolo precedente, noi
introdotto il sottosistema di tracciamento e l'esempio sesto.cc. da cui traccia PCAP o ASCII
i file vengono generati. Queste tracce sono preziose per l'analisi dei dati utilizzando una varietà di
strumenti esterni e per molti utenti tali dati di output sono un mezzo preferito di raccolta
dati (per analisi con strumenti esterni).

Tuttavia, esistono anche casi d'uso per qualcosa di più della generazione di file di traccia, incluso il file
seguenti:

· generazione di dati che non si associano bene a tracce PCAP o ASCII, ad esempio non-packet
dati (ad es. transizioni della macchina a stati del protocollo),

· simulazioni di grandi dimensioni per le quali sono i requisiti di I/O del disco per la generazione di file di traccia
proibitivo o ingombrante, e

· il bisogno di online riduzione o calcolo dei dati, nel corso della simulazione.
Un buon esempio di ciò è definire una condizione di terminazione per la simulazione, da raccontare
quando fermarsi quando ha ricevuto dati sufficienti per formare una confidenza sufficientemente ristretta
intervallo intorno alla stima di qualche parametro.

Le NS-3 il framework di raccolta dati è progettato per fornire queste funzionalità aggiuntive
oltre l'output basato sulla traccia. Si consiglia al lettore interessato a questo argomento di consultare
, il NS-3 Manuale per una trattazione più dettagliata di questo quadro; qui, riassumiamo con
un programma di esempio alcune delle capacità di sviluppo.

Esempio Code
L'esempio del tutorial esempi/tutorial/settimo.cc ricorda il sesto.cc esempio noi
precedentemente recensito, salvo alcune modifiche. Innanzitutto, è stato abilitato per IPv6
supporto con un'opzione della riga di comando:

Riga di comando cmd;
cmd.AddValue ("useIpv6", "Usa Ipv6", useV6);
cmd.Parse (argc, argv);

Se l'utente specifica usa Ipv6, opzione, il programma verrà eseguito utilizzando IPv6 anziché IPv4.
Le Aiuto opzione, disponibile su tutti NS-3 programmi che supportano l'oggetto CommandLine come
mostrato sopra, può essere invocato come segue (si prega di notare l'uso delle virgolette doppie):

./waf --run "seventh --help"

che produce:

ns3-dev-seventh-debug [Argomenti del programma] [Argomenti generali]

Argomenti del programma:
--useIpv6: Usa Ipv6 [falso]

Argomenti generali:
--PrintGlobals: stampa l'elenco dei globali.
--PrintGroups: stampa l'elenco dei gruppi.
--PrintGroup=[group]: stampa tutti i TypeId del gruppo.
--PrintTypeIds: stampa tutti i TypeId.
--PrintAttributes=[typeid]: stampa tutti gli attributi di typeid.
--PrintHelp: stampa questo messaggio di aiuto.

Questo valore predefinito (uso di IPv4, poiché useIpv6 è falso) può essere modificato attivando il booleano
valore come segue:

./waf --run "settimo --useIpv6=1"

e dai un'occhiata al pcap generato, come con tcpdump:

tcpdump -r settimo.pcap -nn -tt

Questa è stata una breve digressione sul supporto IPv6 e sulla riga di comando, che lo era anche
introdotto in precedenza in questo tutorial. Per un esempio dedicato di utilizzo della riga di comando,
perfavore guarda src/core/examples/command-line-example.cc.

Ora torniamo alla raccolta dei dati. Nel esempi/tutorial/ directory, digitare quanto segue
comando: diff -u sesto.cc settimo.cc, ed esaminare alcune delle nuove righe di questa differenza:

+ std::string tipoprobe;
+ std::string tracePath;
+ se (useV6 == false)
+ {
...
+ probeType = "ns3::Ipv4PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv4L3Protocol/Tx";
+ }
+ altro
+ {
...
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";
+ }
...
+ // Usa GnuplotHelper per tracciare il conteggio dei byte del pacchetto nel tempo
+ GnuplotHelper plotHelper;
+
+ // Configura la trama. Il primo argomento è il prefisso del nome del file
+ // per i file di output generati. Il secondo, il terzo e il quarto
+ // gli argomenti sono, rispettivamente, le etichette del titolo della trama, dell'asse x e dell'asse y
+ plotHelper.ConfigurePlot ("conteggio byte del settimo pacchetto",
+ "Conteggio byte pacchetto vs. tempo",
+ "Tempo (secondi)",
+ "Conteggio byte pacchetto");
+
+ // Specifica il tipo di sonda, il percorso dell'origine della traccia (nello spazio dei nomi di configurazione) e
+ // Sorgente della traccia di output della sonda ("OutputBytes") da tracciare. Il quarto argomento
+ // specifica il nome dell'etichetta della serie di dati sul grafico. L'ultimo
+ // argomento formatta il grafico specificando dove deve essere posizionata la chiave.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "Byte di output",
+ "Conteggio byte pacchetto",
+ GnuplotAggregator::KEY_BELOW);
+
+ // Usa FileHelper per scrivere il conteggio dei byte del pacchetto nel tempo
+ FileHelper fileHelper;
+
+ // Configura il file da scrivere e la formattazione dei dati di output.
+ fileHelper.ConfigureFile ("conteggio byte del settimo pacchetto",
+ FileAggregator::FORMATTATO);
+
+ // Imposta le etichette per questo file di output formattato.
+ fileHelper.Set2dFormat ("Tempo (secondi) = %.3e\tConteggio byte pacchetti = %.0f");
+
+ // Specifica il tipo di sonda, il percorso della sonda (nello spazio dei nomi di configurazione) e
+ // sorgente della traccia di output del probe ("OutputBytes") da scrivere.
+ fileHelper.WriteProbe (tipo sonda,
+ tracePath,
+ "Byte di output");
+
Simulatore::Stop (secondi (20));
Simulatore::Esegui ();
Simulatore::Distruggi ();

Il lettore attento avrà notato, durante il test dell'attributo della riga di comando IPv6 sopra,
che settimo.cc aveva creato una serie di nuovi file di output:

settimo-pacchetto-byte-count-0.txt
settimo-pacchetto-byte-count-1.txt
settimo-pacchetto-byte-count.dat
settimo-pacchetto-byte-count.plt
settimo-packet-byte-count.png
settimo-pacchetto-byte-count.sh

Questi sono stati creati dalle dichiarazioni aggiuntive introdotte sopra; in particolare, dall'a
GnuplotHelper e un FileHelper. Questi dati sono stati prodotti agganciando la raccolta dei dati
componenti ai NS-3 tracciare le origini e effettuare il marshalling dei dati in un formato formattato gnplot che a
in un file di testo formattato. Nelle prossime sezioni, esamineremo ciascuno di questi.

GnuplotHelper
GnuplotHelper è un NS-3 oggetto helper finalizzato alla produzione di gnplot trame con
il minor numero di affermazioni possibile, per casi comuni. Si aggancia NS-3 tracciare le fonti con i dati
tipi supportati dal sistema di raccolta dati. Non tutto NS-3 i tipi di dati delle origini di traccia sono
supportato, ma molti dei tipi di traccia comuni lo sono, inclusi TracedValues ​​con plain old
tipi di dati (POD).

Diamo un'occhiata all'output prodotto da questo helper:

settimo-pacchetto-byte-count.dat
settimo-pacchetto-byte-count.plt
settimo-pacchetto-byte-count.sh

Il primo è un file di dati gnuplot con una serie di timestamp e pacchetti delimitati da spazi
conteggi di byte. Tratteremo come è stato configurato questo particolare output di dati di seguito, ma andiamo
continua con i file di output. Il file settimo-pacchetto-byte-count.plt è una trama gnuplot
file, che può essere aperto da gnuplot. I lettori che capiscono la sintassi di gnuplot possono
vedi che questo produrrà un file PNG di output formattato chiamato
settimo-packet-byte-count.png. Infine, un piccolo script di shell
settimo-pacchetto-byte-count.sh esegue questo file di stampa tramite gnuplot per produrre il file desiderato
PNG (che può essere visualizzato in un editor di immagini); cioè il comando:

sh conteggio byte del settimo pacchetto.sh

cederà settimo-packet-byte-count.png. Perché questo PNG non è stato prodotto nel primo
posto? La risposta è che fornendo il file plt, l'utente può configurare manualmente il file
risultato se lo si desidera, prima di produrre il PNG.

Il titolo dell'immagine PNG afferma che questa trama è una trama di "Packet Byte Count vs. Time" e
che sta tracciando i dati sondati corrispondenti al percorso di origine della traccia:

/Lista nodi/*/$ns3::Protocollo Ipv6L3/Tx

Notare il carattere jolly nel percorso di traccia. In sintesi, ciò che questa trama sta catturando è la trama
di byte di pacchetto osservati all'origine della traccia di trasmissione dell'oggetto Ipv6L3Protocol;
segmenti TCP in gran parte a 596 byte in una direzione e ack TCP a 60 byte nell'altra (due
le origini di traccia del nodo sono state abbinate a questa origine di traccia).

Come è stato configurato? È necessario fornire alcune affermazioni. Innanzitutto, GnuplotHelper
l'oggetto deve essere dichiarato e configurato:

+ // Usa GnuplotHelper per tracciare il conteggio dei byte del pacchetto nel tempo
+ GnuplotHelper plotHelper;
+
+ // Configura la trama. Il primo argomento è il prefisso del nome del file
+ // per i file di output generati. Il secondo, il terzo e il quarto
+ // gli argomenti sono, rispettivamente, le etichette del titolo della trama, dell'asse x e dell'asse y
+ plotHelper.ConfigurePlot ("conteggio byte del settimo pacchetto",
+ "Conteggio byte pacchetto vs. tempo",
+ "Tempo (secondi)",
+ "Conteggio byte pacchetto");

A questo punto è stata configurata una trama vuota. Il prefisso del nome del file è il primo
argomento, il titolo della trama è il secondo, l'etichetta dell'asse x la terza e l'etichetta dell'asse y
il quarto argomento.

Il passaggio successivo consiste nel configurare i dati e qui è dove viene agganciata l'origine della traccia.
Innanzitutto, nota sopra nel programma abbiamo dichiarato alcune variabili per un uso successivo:

+ std::string tipoprobe;
+ std::string tracePath;
+ probeType = "ns3::Ipv6PacketProbe";
+ tracePath = "/NodeList/*/$ns3::Ipv6L3Protocol/Tx";

Li usiamo qui:

+ // Specifica il tipo di sonda, il percorso dell'origine della traccia (nello spazio dei nomi di configurazione) e
+ // Sorgente della traccia di output della sonda ("OutputBytes") da tracciare. Il quarto argomento
+ // specifica il nome dell'etichetta della serie di dati sul grafico. L'ultimo
+ // argomento formatta il grafico specificando dove deve essere posizionata la chiave.
+ plotHelper.PlotProbe (probeType,
+ tracePath,
+ "Byte di output",
+ "Conteggio byte pacchetto",
+ GnuplotAggregator::KEY_BELOW);

I primi due argomenti sono il nome del tipo di sonda e il percorso dell'origine della traccia. Queste
due sono probabilmente i più difficili da determinare quando si tenta di utilizzare questo framework per tracciarne altri
tracce. La traccia della sonda qui è il Tx traccia la fonte della classe Protocollo IPv6L3. Quando noi
esaminare questa implementazione di classe (src/internet/model/ipv6-l3-protocol.cc) possiamo osservare:

.AddTraceSource ("Tx", "Invia pacchetto IPv6 all'interfaccia in uscita.",
MakeTraceSourceAccessor (&Ipv6L3Protocol::m_txTrace))

Questo dice che Tx è un nome per variabile m_txTrace, che ha una dichiarazione di:

/ **
* \brief Richiamata per tracciare i pacchetti TX (trasmissione).
*/
Richiamata tracciata , pt , uint6_t> m_txTrace;

Si scopre che questa specifica firma dell'origine di traccia è supportata da una classe Probe (what
abbiamo bisogno qui) della classe Ipv6PacketProbe. Guarda i file
src/internet/modello/sonda-pacchetto-ipv6.{h,cc}.

Quindi, nell'istruzione PlotProbe sopra, vediamo che l'istruzione sta agganciando la traccia
sorgente (identificata dalla stringa di percorso) con una corrispondenza NS-3 Tipo di sonda di IPv6PacketProbe. Se
non abbiamo supportato questo tipo di sonda (corrispondente alla firma dell'origine della traccia), non avremmo potuto
ha usato questa affermazione (sebbene alcune istruzioni di livello inferiore più complicate avrebbero potuto essere
usato, come descritto nel manuale).

Ipv6PacketProbe esporta, di per sé, alcune origini di traccia che estraggono i dati dal file
oggetto Pacchetto sondato:

ID tipo
Ipv6PacketProbe::GetTypeId ()
{
static TypeId tid = TypeId ("ns3::Ipv6PacketProbe")
.SetParent ()
.Aggiungi costruttore ()
.AddTraceSource ("Uscita",
"Il pacchetto più il suo oggetto IPv6 e l'interfaccia che servono come output per questa sonda",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_output))
.AddTraceSource ("OutputBytes",
"Il numero di byte nel pacchetto",
MakeTraceSourceAccessor (&Ipv6PacketProbe::m_outputBytes))
;
ritorno a mare;
}

Il terzo argomento della nostra affermazione PlotProbe specifica che siamo interessati al
numero di byte in questo pacchetto; in particolare, l'origine di traccia "OutputBytes" di
Ipv6PacketProbe. Infine, gli ultimi due argomenti della dichiarazione forniscono la legenda della trama
per questa serie di dati ("Packet Byte Count") e un'istruzione di formattazione gnuplot facoltativa
(GnuplotAggregator::KEY_BELOW) vogliamo che la chiave del grafico sia inserita sotto il grafico.
Altre opzioni includono NO_KEY, KEY_INSIDE e KEY_ABOVE.

Supporto Traccia Tipi
I seguenti valori tracciati sono supportati con le sonde al momento della stesura di questo documento:

┌ronicheranno ────────────────────┐
│Tipo TracedValue │ Tipo di sonda │ File │
├ronicheranno ────────────────────┤
│doppio │ DoubleProbe │ statistiche/modello/doppio-sonda.h │
├ronicheranno ────────────────────┤
│uint8_t │ Uinteger8Probe │ statistiche/modello/uinteger-8-probe.h │
├ronicheranno ────────────────────┤
│uint16_t │ Uinteger16Probe │ statistiche/modello/uinteger-16-probe.h │
├ronicheranno ────────────────────┤
│uint32_t │ Uinteger32Probe │ statistiche/modello/uinteger-32-probe.h │
├ronicheranno ────────────────────┤
│bool │ BooleanProbe │ statistiche/modello/uinteger-16-probe.h │
├ronicheranno ────────────────────┤
│ns3::Time │ TimeProbe │ statistiche/modello/time-probe.h │
└ronicheranno ────────────────────┘

I seguenti tipi di TraceSource sono supportati da Probes al momento della stesura di questo documento:

┌ronicheranno ─── forse ──────────┐
├ronicheranno ─── forse ──────────┤
├ronicheranno ─── forse ──────────┤
├ronicheranno ─── forse ──────────┤
├ronicheranno ─── forse ──────────┤
├ronicheranno ─── forse ──────────┤
└ronicheranno ─── forse ──────────┘

Come si può vedere, sono supportate solo poche sorgenti di traccia e sono tutte orientate verso
emettendo la dimensione del pacchetto (in byte). Tuttavia, la maggior parte dei tipi di dati fondamentali
disponibile come TracedValues ​​può essere supportato con questi helper.

FileHelper
La classe FileHelper è solo una variazione del precedente esempio di GnuplotHelper. Il
programma di esempio fornisce un output formattato degli stessi dati con timestamp, come segue:

Tempo (secondi) = 9.312e+00 Conteggio byte pacchetto = 596
Tempo (secondi) = 9.312e+00 Conteggio byte pacchetto = 564

Sono forniti due file, uno per il nodo "0" e uno per il nodo "1", come si può vedere in
nomi di file. Diamo un'occhiata al codice pezzo per pezzo:

+ // Usa FileHelper per scrivere il conteggio dei byte del pacchetto nel tempo
+ FileHelper fileHelper;
+
+ // Configura il file da scrivere e la formattazione dei dati di output.
+ fileHelper.ConfigureFile ("conteggio byte del settimo pacchetto",
+ FileAggregator::FORMATTATO);

Il prefisso del file helper è il primo argomento e il successivo è un identificatore di formato. Alcuni
altre opzioni per la formattazione includono SPACE_SEPARATED, COMMA_SEPARATED e TAB_SEPARATED.
Gli utenti possono modificare la formattazione (se è specificato FORMATTED) con una stringa di formato
come segue:

+
+ // Imposta le etichette per questo file di output formattato.
+ fileHelper.Set2dFormat ("Tempo (secondi) = %.3e\tConteggio byte pacchetti = %.0f");

Infine, la fonte di traccia di interesse deve essere agganciata. Di nuovo, probeType e tracePath
in questo esempio vengono utilizzate le variabili e l'origine della traccia di output del probe "OutputBytes" è
agganciata:

+
+ // Specifica il tipo di sonda, il percorso dell'origine della traccia (nello spazio dei nomi di configurazione) e
+ // sorgente della traccia di output del probe ("OutputBytes") da scrivere.
+ fileHelper.WriteProbe (tipo sonda,
+ tracePath,
+ "Byte di output");
+

I campi con caratteri jolly in questo identificatore di origine di traccia corrispondono a due origini di traccia. non mi piace il
Esempio di GnuplotHelper, in cui due serie di dati sono state sovrapposte sullo stesso grafico, qui due
file separati vengono scritti su disco.

Sommario
Il supporto per la raccolta dei dati è nuovo a partire da ns-3.18 e il supporto di base per la fornitura di serie temporali
l'output è stato aggiunto. Il modello di base sopra descritto può essere replicato all'interno del
ambito di supporto delle sonde esistenti e delle sorgenti di traccia. Più capacità tra cui
l'elaborazione delle statistiche sarà aggiunta nelle versioni future.

CONCLUSIONE


Futures
Questo documento è inteso come un documento vivente. Speriamo e ci aspettiamo che cresca nel tempo
per coprire sempre più dadi e bulloni di NS-3.

Scrivere capitoli di manuali e tutorial non è qualcosa di cui tutti siamo entusiasti, ma lo è
molto importante per il progetto. Se sei un esperto in una di queste aree, per favore
considerare di contribuire a NS-3 fornendo uno di questi capitoli; o qualsiasi altro capitolo tu
può pensare che sia importante.

Chiusura
NS-3 è un sistema ampio e complicato. È impossibile coprire tutte le cose che tu
avrà bisogno di sapere in un piccolo tutorial. I lettori che vogliono saperne di più sono incoraggiati a farlo
leggere la seguente documentazione aggiuntiva:

· Il NS-3 Manuale

· Il NS-3 documentazione della libreria di modelli

· Il NS-3 Doxygen (documentazione API)

· Il NS-3 wiki

-- Il NS-3 team di sviluppo.

Usa ns-3-tutorial online usando i servizi onworks.net


Server e workstation gratuiti

Scarica app per Windows e Linux

Comandi Linux

Ad