Tutorial simulator de rețea ns-3. capitolul 4

Tutorial simulator de rețea ns-3. capitolul 4
capitolul 1,2
capitolul 3

4 Prezentare generală a conceptului
4.1 Abstracții cheie
4.1.1 Nod
4.1.2 Aplicare
4.1.3 Canal
4.1.4 Dispozitiv net
4.1.5 Asistenți topologici
4.2 Primul script ns-3
4.2.1 Cod boilerplate
4.2.2 Plug-in-uri
4.2.3 spatiu de nume ns3
4.2.4 Înregistrare
4.2.5 Funcția principală
4.2.6 Utilizarea asistenților de topologie
4.2.7 Utilizarea aplicației
4.2.8 Simulator
4.2.9 Construirea scriptului
4.3 ns-3 Cod sursă

Capitolul 4

Prezentare generală a conceptului

Primul lucru pe care trebuie să-l facem înainte de a începe să învățăm sau să scriem codul ns-3 este să explicăm câteva concepte și abstracții de bază din sistem. Multe dintre acestea pot părea evidente pentru unii, dar vă recomandăm să vă acordați timp pentru a citi această secțiune pentru a vă asigura că porniți pe o bază solidă.

4.1 Abstracții cheie

În această secțiune, ne vom uita la câțiva termeni care sunt utilizați în mod obișnuit pe web, dar au o semnificație specifică în ns-3.

4.1.1 Nod

În jargonul internetului, un dispozitiv de computer care se conectează la o rețea se numește gazdă sau, uneori, un sistem final. Deoarece ns-3 este un simulator de rețea și nu un simulator de Internet, nu folosim în mod deliberat termenul gazdă, deoarece acesta este strâns legat de Internet și de protocoalele sale. În schimb, folosim un termen mai general, folosit și de alte simulatoare, care își are originea în teoria grafurilor: node (nod).

În ns-3, abstracția de bază a unui dispozitiv de calcul se numește nod. Această abstractizare este reprezentată în C++ de clasa Node. Clasă NodeNode (nodul) oferă metode de manipulare a reprezentărilor dispozitivelor de calcul în simulări.

Trebuie să înțelegeți Nod ca un computer căruia îi adaugi funcționalități. Veți adăuga lucruri precum aplicații, stive de protocoale și carduri periferice cu drivere care permit computerului să facă lucrări utile. Folosim același model de bază în ns-3.

4.1.2 Aplicare

În general, software-ul de calculator este împărțit în două clase mari. Software-ul de sistem organizează diverse resurse ale computerului, cum ar fi memoria, ciclurile procesorului, discul, rețeaua etc., conform unui model de calcul. Software-ul de sistem nu utilizează de obicei aceste resurse pentru a efectua sarcini care beneficiază direct utilizatorul. Un utilizator rulează de obicei o aplicație pentru a atinge un obiectiv specific, care obține și utilizează resurse controlate de software-ul de sistem.

Adesea, linia de separare între software-ul de sistem și aplicația este trasată la modificările nivelului de privilegii care apar în capcanele sistemului de operare. ns-3 nu are un concept real de sistem de operare și, prin urmare, nici un concept de niveluri de privilegii sau apeluri de sistem. Cu toate acestea, avem o idee pentru o aplicație. La fel ca în „lumea reală” aplicațiile software rulează pe computere pentru a efectua sarcini, aplicațiile ns-3 rulează pe noduri ns-3 pentru a controla simulările din lumea simulată.

În ns-3, abstractizarea de bază pentru un program utilizator care generează o anumită activitate pentru modelare este o aplicație. Această abstractizare este reprezentată în C++ de clasa Application. Clasa Application oferă metode pentru manipularea vizualizărilor versiunii noastre la nivel de utilizator a aplicațiilor în simulări. Se așteaptă ca dezvoltatorii să specializeze clasa Application într-un sens de programare orientată pe obiecte pentru a crea noi aplicații. În acest tutorial, vom folosi specializările clasei Application numite UdpEchoClientApplication и UdpEchoServerApplication. După cum v-ați putea aștepta, aceste aplicații alcătuiesc un set de aplicații client/server utilizate pentru a genera și ecou pachete de rețea.

4.1.3 Canal

În lumea reală, puteți conecta un computer la o rețea. Adesea, mediile prin care sunt transmise datele în aceste rețele se numesc canale. Când conectați un cablu Ethernet la o priză de perete, vă conectați computerul la o legătură Ethernet. În lumea simulată ns-3, un nod este conectat la un obiect reprezentând un canal de comunicație. Aici, abstractizarea de bază a subrețelei de comunicații se numește canal și este reprezentată în C++ de clasa Channel.

clasă ChannelChannel oferă metode de gestionare a interacțiunii obiectelor de subrețea și de conectare a nodurilor la acestea. Canalele pot fi, de asemenea, specializate de dezvoltatori într-un sens de programare orientată pe obiecte. Specializarea canalului poate modela ceva la fel de simplu ca un fir. Un canal dedicat poate modela și lucruri complexe precum un switch Ethernet mare sau un spațiu tridimensional plin de obstacole în cazul rețelelor wireless.

Vom folosi versiuni specializate ale canalului în acest tutorial numit CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel и WifiChannelWifiChannel. CsmaChannel, de exemplu, modelează o versiune a unei subrețele de comunicații care implementează un mediu de comunicații cu acces multiplu cu sens de transportator. Acest lucru ne oferă o funcționalitate asemănătoare Ethernet.

4.1.4 Dispozitiv net

În trecut, dacă doreai să conectezi un computer la o rețea, trebuia să cumperi un anumit cablu de rețea și un dispozitiv hardware numit (în terminologia PC) un card periferic care trebuia instalat în computer. Dacă o placă periferică implementa unele funcții de rețea, acestea erau numite plăci de interfață de rețea sau plăci de rețea. Astăzi, majoritatea computerelor vin cu hardware de interfață de rețea integrat și nu sunt văzute de utilizatori ca dispozitive separate.

O placă de rețea nu va funcționa fără un driver software care îi controlează hardware-ul. În Unix (sau Linux), un echipament periferic este clasificat ca dispozitiv. Dispozitivele sunt gestionate folosind drivere de dispozitiv, iar dispozitivele de rețea (NIC) sunt gestionate folosind drivere de dispozitiv de rețea (drivere de dispozitiv de rețea) și sunt denumite în mod colectiv dispozitive de rețea (dispozitive net). În Unix și Linux, vă referiți la dispozitivele de rețea prin nume precum eth0.

În ns-3, abstracția dispozitivului de rețea acoperă atât software-ul driverului, cât și hardware-ul care este modelat. În simulare, un dispozitiv de rețea este „instalat” într-un nod pentru a-i permite să comunice cu alte noduri prin canale. La fel ca un computer real, un nod poate fi conectat la mai multe canale prin mai multe dispozitive NetDevices.

Abstracția de rețea a unui dispozitiv este reprezentată în C++ de clasă NetDevice. Clasă NetDevice furnizează metode de gestionare a conexiunilor la obiectele Nod și Channel; și poate fi specializat de dezvoltatori în sensul de programare orientată pe obiecte. În acest tutorial vom folosi mai multe versiuni specializate ale NetDevice numite CsmaNetDevice, PointToPointNetDevice и Dispozitiv WifiNet. La fel cum un adaptor de rețea Ethernet este proiectat să funcționeze cu o rețea Ethernet, CsmaNetDevice conceput pentru a lucra cu CsmaChannel, PointToPointNetDevice conceput pentru a lucra cu PointToPointChannelȘi Dispozitiv WifiNet - conceput pentru a lucra cu WifiChannel.

4.1.5 Asistenți topologici

Într-o rețea reală, veți găsi computere gazdă cu plăci de rețea adăugate (sau încorporate). În ns-3 am spune că veți vedea noduri cu NetDevices atașat. Într-o rețea simulată mare, va trebui să organizați conexiuni între multe obiecte Nod, NetDevice и Canal.

De la conectarea NetDevices la noduri, NetDevices la linkuri, atribuirea adreselor IP etc. în ns-3 sunt o sarcină comună, pentru a face acest lucru cât mai ușor posibil, oferim așa-numitele ajutoare de topologie. De exemplu, pentru a crea un NetDevice, trebuie să efectuați multe operații de nucleu ns-3, să adăugați o adresă MAC, să instalați dispozitivul de rețea în Node, să configurați stiva de protocoale a nodului și apoi să conectați NetDevice la canal. Va fi necesară și mai multă muncă pentru a conecta mai multe dispozitive la legături multipunct și apoi a conecta rețelele individuale la o rețea Internetworks. Oferim obiecte de ajutor de topologie care combină aceste multe operații într-un model ușor de utilizat pentru confortul dumneavoastră.

4.2 Primul script ns-3

Dacă ați instalat sistemul așa cum s-a sugerat mai sus, veți avea versiunea ns-3 într-un director numit repos în directorul dvs. de acasă. Accesați directorul eliberaţi

Dacă nu aveți un astfel de director, înseamnă că nu ați specificat directorul de ieșire la construirea versiunii de lansare a ns-3, construiți astfel:
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf build

acolo ar trebui să vedeți o structură de directoare similară cu următoarea:

AUTHORS       examples      scratch       utils       waf.bat*
bindings      LICENSE       src           utils.py    waf-tools
build         ns3           test.py*      utils.pyc   wscript
CHANGES.html  README        testpy-output VERSION     wutils.py
doc           RELEASE_NOTES testpy.supp   waf*        wutils.pyc

Accesați directorul exemple/tutorial. Ar trebui să vedeți un fișier aflat acolo numit mai întâi.cc. Acesta este un script care va crea o conexiune simplă punct la punct între două noduri și va transmite un pachet între noduri. Să ne uităm la acest script linie cu linie; pentru a face acest lucru, deschide first.cc în editorul tău preferat.

4.2.1 Cod boilerplate
Prima linie din fișier este linia modului editor emacs. Îi spune emacs-ului despre convențiile de formatare (stil de codare) pe care le folosim în codul sursă.

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

Aceasta este întotdeauna o problemă destul de controversată, așa că trebuie să stabilim recordul pentru a o îndepărta imediat. Proiectul ns-3, la fel ca majoritatea proiectelor mari, a adoptat un stil de codare căruia trebuie să se conformeze tot codul contribuit. Dacă doriți să contribuiți cu codul dvs. la proiect, în cele din urmă va trebui să vă conformați standardului de codare ns-3, așa cum este descris în fișier doc/codingstd.txt sau afișat pe pagina web a proiectului: https://www.nsnam.org/develop/contributing-code/coding-style/.

Vă recomandăm să vă obișnuiți cu aspectul codului ns-3 și să aplicați acest standard ori de câte ori lucrați cu codul nostru. Întreaga echipă de dezvoltare și colaboratorii au fost de acord cu acest lucru după câteva mormăieli. Linia de mod emacs de mai sus facilitează formatarea corectă dacă utilizați editorul emacs.

Simulatorul ns-3 este licențiat folosind GNU General Public License. Veți vedea antetul legal GNU corespunzător în fiecare fișier de distribuție ns-3. Adesea, veți vedea o notificare privind drepturile de autor pentru una dintre instituțiile participante la proiectul ns-3 deasupra textului și autorului GPL, prezentate mai jos.

/* 
* This program is free software; you can redistribute it and/or modify 
* it under the terms of the GNU General Public License version 2 as 
* published by the Free Software Foundation; 
*
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program; if not, write to the Free Software 
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/

4.2.2 Plug-in-uri

Codul în sine începe cu o serie de declarații de includere (include).

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

Pentru a ajuta utilizatorii noștri de scripturi de nivel înalt să facă față numărului mare de fișiere antet prezente în sistem, le grupăm în funcție de utilizarea lor în module mari. Oferim un singur fișier antet care va încărca recursiv toate fișierele antet utilizate într-un anumit modul. În loc să trebuiască să căutați exact ce antet aveți nevoie și, eventual, să obțineți lista corectă de dependențe, vă oferim posibilitatea de a descărca un grup de fișiere cu o mare granularitate. Nu este cea mai eficientă abordare, dar cu siguranță ușurează mult scrierea scenariilor.

Fiecare dintre fișierele incluse ns-3 este plasat într-un director numit ns3 (subdirectorul de compilare) pentru a evita conflictele de nume de fișier în timpul procesului de construire. Fişier ns3/core-module.h corespunde modulului ns-3, pe care îl veți găsi în director src/core în versiunea pe care ați instalat-o. În lista acestui director veți găsi un număr mare de fișiere de antet. Când faci asamblarea, waf plasează fișierele de antet publice în directorul ns3 într-un subdirector construi/depanează

Dacă nu aveți un astfel de director, înseamnă că nu ați specificat directorul de ieșire la construirea versiunii de lansare a ns-3, construiți astfel:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf build
sau
$ ./waf configure --build-profile=optimized --out=build/optimized
$ ./waf build

sau construi/optimizat, în funcție de configurația dvs. waf va genera, de asemenea, automat un fișier include modul pentru a încărca toate fișierele de antet publice. Deoarece, desigur, urmați acest ghid religios, ați făcut-o deja

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

pentru a configura proiectul să ruleze versiuni de depanare care includ exemple și teste. Și tu ai făcut-o

$ ./waf

pentru a asambla proiectul. Deci acum când te uiți în director ../../build/debug/ns3, apoi acolo veți găsi, printre altele, fișierele antet ale celor patru module prezentate mai sus. Puteți privi conținutul acestor fișiere și puteți constata că acestea includ toate fișierele publice utilizate de modulele corespunzătoare.

4.2.3 spatiu de nume ns3

Rândul următor în script mai întâi.cc este o declarație de spațiu de nume.

using namespace ns3;

Proiectul ns-3 este implementat într-un spațiu de nume C++ numit ns3. Acest lucru grupează toate declarațiile legate de ns-3 într-un domeniu în afara spațiului de nume global, ceea ce, sperăm, va ajuta la integrarea cu alt cod. Utilizarea operatorului C++ introduce spațiul de nume ns-3 în regiunea declarativă (globală) curentă. Acesta este un mod elegant de a spune că, după această declarație, nu va trebui să tastați operatorul de permisiuni ns3::scope înainte de tot codul dvs. ns-3 pentru a-l folosi. Dacă nu sunteți familiarizat cu spațiile de nume, consultați aproape orice manual C++ și comparați spațiul de nume ns3 folosind spațiul de nume și declarația std using namespace std; în exemple de lucru cu operatorul de ieșire cout și pâraiele.

4.2.4 Înregistrare

Următoarea linie a scriptului este:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Vom folosi această declarație ca un loc convenabil pentru a discuta despre sistemul nostru de documentare Oxigen. Dacă vă uitați pe site-ul web al proiectului ns-3, veți găsi un link pentru documentație în bara de navigare. Dacă faceți clic pe acest link, veți fi direcționat către pagina noastră de documentație. Există un link „Latest Release” care vă va duce la documentația pentru cea mai recentă versiune stabilă a ns-3. Dacă selectați linkul „Documentație API”, veți fi direcționat către pagina de documentație API ns-3.

În partea stângă a paginii veți găsi o reprezentare grafică a structurii documentației. Un loc bun pentru a începe este „cartea” Modulelor ns-3 din arborele de navigare ns-3. Dacă dezvălui Module, veți vedea o listă de documentație a modulelor ns-3. După cum sa discutat mai sus, conceptul de modul de aici este direct legat de fișierele incluse în modulul de mai sus. Subsistemul de înregistrare ns-3 este discutat în secțiune Folosind modulul de înregistrare, așa că vom reveni la asta mai târziu în acest tutorial, dar puteți afla despre declarația de mai sus uitându-vă la modulul Nucleuși apoi deschizând cartea Instrumente de depanareși apoi selectând pagina Exploatari forestiere. Click pe Exploatari forestiere.

Acum ar trebui să revizuiți documentația Oxigen pentru modul Exploatari forestiere. În lista de macrocomenzi din partea de sus a paginii, veți vedea o intrare pentru NS_LOG_COMPONENT_DEFINE. Înainte de a face clic pe link, asigurați-vă că vă uitați la „Descrierea detaliată” a modulului de înregistrare pentru a înțelege cum funcționează în general. Pentru a face acest lucru, puteți derula în jos sau selectați „Mai multe...” sub diagramă.

Odată ce aveți o idee generală despre ceea ce se întâmplă, continuați și uitați-vă la documentația pentru NS_LOG_COMPONENT_DEFINE specific. Nu voi duplica documentația aici, dar pentru a rezuma, această linie declară o componentă de înregistrare numită FirstScriptExample, care vă permite să activați sau să dezactivați înregistrarea mesajelor în consola prin referire la un nume.

4.2.5 Funcția principală

În următoarele rânduri ale scriptului veți vedea,

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

Aceasta este pur și simplu o declarație a funcției principale a programului dumneavoastră (script). Ca și în cazul oricărui program C++, trebuie să definiți o funcție principală, aceasta este executată mai întâi. Nu e nimic special aici. Scriptul tău ns-3 este doar un program C++. Următoarea linie setează rezoluția de timp la 1 nanosecundă, care este valoarea implicită:

Time::SetResolution (Time::NS);

Rezoluția în timp, sau pur și simplu rezoluția, este cea mai mică valoare a timpului care poate fi utilizată (cea mai mică diferență reprezentabilă între doi timpi). Puteți schimba rezoluția exact o dată. Mecanismul care oferă această flexibilitate consumă memorie, așa că odată ce rezoluția este setată în mod explicit, eliberăm memoria, prevenind actualizările ulterioare. (Dacă nu setați rezoluția în mod explicit, aceasta va fi implicită la o nanosecundă și memoria va fi eliberată când începe simularea.)

Următoarele două linii de script sunt utilizate pentru a activa două componente de jurnalizare care sunt încorporate în aplicații EchoClient и EchoServer:

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

Dacă citiți documentația pentru componenta Logging, veți vedea că există mai multe niveluri de înregistrare/granularitate pe care le puteți activa pentru fiecare componentă. Aceste două linii de cod permit înregistrarea de depanare la nivelul INFO pentru clienții și serverele echo. La acest nivel, aplicația va imprima mesaje pe măsură ce trimite și primește pachete în timpul simulării.

Acum vom trece la treaba creării topologiei și rulării simulării. Folosim obiecte de ajutor de topologie pentru a face acest lucru cât mai ușor posibil.

4.2.6 Utilizarea asistenților de topologie

Următoarele două linii de cod din scriptul nostru vor crea de fapt obiectele Node ns-3 care vor reprezenta computerele din simulare.

NodeContainer nodes;
nodes.Create (2);

Înainte de a continua, să găsim documentația pentru clasă NodeContainer. O altă modalitate de a ajunge la documentația pentru o anumită clasă este prin fila Clase pe pagini Oxigen. Dacă aveți deja Doxygen deschis, pur și simplu derulați în sus în partea de sus a paginii și selectați fila Clasuri. Ar trebui să vedeți un nou set de file, dintre care una este o listă de clase. Sub această filă veți vedea o listă cu toate clasele ns-3. Derulați în jos la ns3::NodeContainer. Când găsiți o clasă, selectați-o pentru a accesa documentația pentru clasă.

După cum ne amintim, una dintre abstracțiile noastre cheie este nodul. Reprezintă computerul la care vom adăuga lucruri precum stive de protocol, aplicații și carduri periferice. Asistent topologie NodeContainer oferă o modalitate convenabilă de a crea, gestiona și accesa orice obiecte Nod, pe care îl creăm pentru a rula simularea. Prima linie de mai sus declară pur și simplu NodeContainer, pe care le numim noduri. A doua linie apelează metoda Create pe obiectul noduri și cere containerului să creeze două noduri. După cum este descris în Oxigen, containerul solicită sistemului ns-3 să creeze două obiecte Nod și stochează pointeri către aceste obiecte în interior.

Nodurile create în script nu fac încă nimic. Următorul pas în construirea topologiei este conectarea nodurilor noastre la rețea. Cea mai simplă formă de rețea pe care o acceptăm este o conexiune punct la punct între două noduri. Acum vom crea o astfel de conexiune.

PointToPointHelper

Creăm o conexiune punct-la-punct folosind un model familiar, folosind un obiect de ajutor de topologie pentru a face munca de nivel scăzut necesară pentru conexiune. Amintiți-vă că cele două abstracții cheie ale noastre NetDevice и Canal. În lumea reală, acești termeni corespund aproximativ plăcilor periferice și cablurilor de rețea. De obicei, aceste două lucruri sunt strâns legate între ele și nimeni nu poate conta pe partajarea, de exemplu, a dispozitivelor Ethernet pe un canal wireless. Asistentii noștri de topologie urmăresc această relație strânsă și, prin urmare, veți folosi un singur obiect în acest scenariu PointToPointHelper pentru configurarea și conectarea obiectelor ns-3 PointToPointNetDevice и PointToPointChannel. Următoarele trei rânduri din scenariu:

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

Prima linie,

PointToPointHelper pointToPoint;

creează o instanță a unui obiect pe stivă PointToPointHelper. Din punct de vedere de nivel superior, următoarea linie,

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

spune obiectului PointToPointHelper utilizați valoarea „5 Mbit/s” (cinci megabiți pe secundă) ca „Rata de date".

Dintr-un punct de vedere mai specific, șirul „DataRate” corespunde ceea ce numim un atribut PointToPointNetDevice. Dacă te uiți la Oxigen pentru clasă ns3::PointToPointNetDevice iar în documentația pentru metodă GetTypeId veți găsi o listă de atribute definite pentru dispozitiv. Printre acestea va fi atributul „Rata de date" Majoritatea obiectelor ns-3 vizibile de utilizator au liste similare de atribute. Folosim acest mecanism pentru a configura cu ușurință simularea fără recompilare, așa cum veți vedea în secțiunea următoare.

ca "Rata de date" în PointToPointNetDevice, veți găsi atributul „Delay” asociat cu PointToPointChannel. Linia finală

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

El vorbește PointToPointHelper utilizați valoarea „2 ms” (două milisecunde) ca valoare a întârzierii de propagare pentru legătura punct la punct pe care o creează ulterior.

NetDeviceContainer

Momentan avem în scenariu NodeContainer, care conține două noduri. Avem PointToPointHelper, care este pregătit pentru crearea de obiecte PointToPointNetDevices și conectarea acestora folosind un obiect PointToPointChannel. Așa cum am folosit obiectul helper de topologie NodeContainer pentru a crea noduri, vom întreba PointToPointHelper efectuează lucrări pentru noi legate de crearea, configurarea și instalarea dispozitivelor noastre. Avem nevoie de o listă cu toate obiectele create NetDevice, așa că folosim NetDeviceContainer pentru a le stoca în același mod în care am folosit NodeContainer pentru a stoca nodurile pe care le-am creat. Următoarele două linii de cod,

NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);

configurarea completă a dispozitivului și a canalului. Prima linie declară containerul dispozitivului menționat mai sus, iar a doua face activitatea principală. Metodă Instala obiect PointToPointHelper ia NodeContainer ca parametru. Interior NetDeviceContainer pentru fiecare nod situat în NodeContainer este creat (pentru comunicarea punct la punct trebuie să existe exact două dintre ele) PointToPointNetDevice este creat și salvat în containerul dispozitivului. PointToPointChannel este creat și doi îi sunt atașați PointToPointNetDevices. După crearea obiectelor, atributele stocate în PointToPointHelper, sunt folosite pentru a inițializa atributele corespunzătoare în obiectele create.

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

InternetStackHelper

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

InternetStackHelper stack;
stack.Install (nodes);

InternetStackHelper - este un ajutor de topologie pentru stivele de Internet, similar cu PointToPointHelper pentru dispozitivele de rețea punct la punct. Metodă Instala ia NodeContainer ca parametru. Când este executat, va instala stiva de Internet (TCP, UDP, IP etc.) pe fiecare nod container.

IPv4AddressHelper

Apoi trebuie să ne asociem dispozitivele cu adrese IP. Oferim un asistent de topologie pentru a gestiona alocarea adreselor IP. Singurul API vizibil pentru utilizator este setarea adresei IP de bază și masca de rețea pe care să le folosească atunci când se realizează distribuția reală a adresei (acest lucru se face la un nivel inferior în cadrul ajutorului). Următoarele două linii de cod din scriptul nostru exemplu mai întâi.cc,

Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");

declarați obiectul de ajutor de adresă și spuneți-i că ar trebui să înceapă să aloce adrese IP din rețeaua 10.1.1.0, folosind masca de biți 255.255.255.0 pentru a determina. În mod implicit, adresele alocate vor începe de la unu și vor crește monoton, deci prima adresă alocată din această bază va fi 10.1.1.1, apoi 10.1.1.2 etc. În realitate, la un nivel scăzut, sistemul ns-3 își amintește toate adresele IP alocate și generează o eroare fatală dacă creați accidental o situație în care aceeași adresă este generată de două ori (apropo, această eroare este greu de depanat).

Următoarea linie de cod,

Ipv4InterfaceContainer interfaces = address.Assign (devices);

realizează atribuirea efectivă a adresei. În ns-3 stabilim o conexiune între o adresă IP și un dispozitiv care utilizează obiectul Interfață IPv4. Așa cum uneori avem nevoie de o listă de dispozitive de rețea create de asistent pentru utilizare ulterioară, uneori avem nevoie de o listă de obiecte Interfață IPv4. IPv4InterfaceContainer oferă această funcționalitate.

Am construit o rețea punct la punct, cu stive instalate și adrese IP atribuite. Acum avem nevoie de aplicații în fiecare nod pentru a genera trafic.

4.2.7 Utilizarea aplicației

O altă dintre principalele abstracții ale sistemului ns-3 este aplicație (aplicație). În acest scenariu, folosim două specializări de clasă de bază aplicație ns-3 numit UdpEchoServerApplication и UdpEchoClientApplication. Ca și în cazurile anterioare, folosim obiecte auxiliare pentru a configura și gestiona obiectele de bază. Aici folosim UdpEchoServerHelper и UdpEchoClientHelper obiecte pentru a ne ușura viața.

UdpEchoServerHelper

Următoarele linii de cod din exemplul nostru de script first.cc sunt folosite pentru a configura o aplicație de server Echo UDP pe unul dintre nodurile pe care le-am creat mai devreme.

UdpEchoServerHelper echoServer (9);

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

Se creează prima linie de cod din fragmentul de mai sus UdpEchoServerHelper. Ca de obicei, aceasta nu este o aplicație în sine, este un obiect care ne ajută să creăm aplicații reale. Una dintre convențiile noastre este să transmitem atributele necesare constructorului obiectului helper. În acest caz, helperul nu poate face nimic util decât dacă i se dă numărul portului pe care serverul va asculta pachetele, acest număr trebuie să fie cunoscut și de client. În acest caz, trecem numărul portului constructorului de ajutor. Constructorul, la rândul său, pur și simplu face SetAttribute cu valoarea transmisă. Mai târziu, dacă doriți, puteți utiliza SetAttribute pentru a seta o valoare diferită pentru atributul Port.

Ca multe alte obiecte auxiliare, obiectul UdpEchoServerHelper are o metodă Instala. Executarea acestei metode creează în mod eficient o aplicație de bază de server echo și o leagă de gazdă. Interesant, metoda Instala ia NodeContainer ca parametru la fel ca celelalte Instala metodele pe care le-am văzut.

Conversia implicită C++ care lucrează aici ia rezultatul metodei nod.Get(1) (care returnează un pointer inteligent la obiectul nod - Ptr ) și îl folosește în constructor pentru obiectul anonim NodeContainercare se trece apoi la metoda Instala. Dacă nu puteți determina în codul C++ ce semnătură de metodă este compilată și executată, atunci căutați printre conversiile implicite.

Acum vedem asta echoServer.Instalare pe cale să instaleze aplicația UdpEchoServerApplication pe găsit în NodeContainerpe care îl folosim pentru a ne gestiona nodurile, nod cu indice 1. Metodă Instala va returna un container care conține pointeri către toate aplicațiile (în acest caz una, deoarece am trecut un anonim NodeContainer, care conține un nod) creat de către ajutor.

Aplicațiile trebuie să specifice când să înceapă să genereze trafic "start" și poate fi necesar să specificați suplimentar un moment în care să îl opriți "Stop". Oferim ambele variante. Aceste ore sunt stabilite folosind metodele ApplicationContainer acasă и Stop. Aceste metode acceptă parametri de tip Timp. În acest caz, folosim o secvență explicită de conversii C++ pentru a lua C++ dubla 1.0 și convertiți-l într-un obiect de timp tns-3 care utilizează obiectul Seconds pentru a converti în secunde. Amintiți-vă că regulile de conversie pot fi controlate de autorul modelului, iar C++ are propriile reguli, așa că nu puteți conta întotdeauna pe parametrii convertiți așa cum vă așteptați. Două rânduri

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

va face ca aplicația de server echo să pornească (pornirea automată) la o secundă după începerea simulării și să se oprească (oprire) după zece secunde de la simulare. Datorită faptului că am declarat un eveniment de simulare (eveniment de oprire a aplicației), care va fi executat în zece secunde, se vor simula cel puțin zece secunde de funcționare a rețelei.

UdpEchoClientHelper

Aplicație client ecou configurat într-un mod aproape similar cu serverul. Există un obiect de bază UdpEchoClientApplication, care este controlat
UdpEchoClientHelper.

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

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

Cu toate acestea, pentru clientul echo trebuie să setăm cinci atribute diferite. Primele două atribute sunt setate în momentul creării UdpEchoClientHelper. Transmitem parametrii care sunt folosiți (în interiorul helperului) pentru a seta atributele „RemoteAddress” и „RemotePort” în conformitate cu acordul nostru de a transmite parametrii necesari constructorului de ajutor.

Să ne amintim că am folosit IPv4InterfaceContainer pentru a urmări adresele IP pe care le-am atribuit dispozitivelor noastre. Interfața nulă din containerul de interfețe va corespunde adresei IP a nodului nul din containerul de noduri. Prima interfață din containerul de interfețe corespunde adresei IP a primului nod din containerul de noduri. Deci, în prima linie de cod (mai sus), creăm un ajutor și îi spunem că adresa de la distanță a clientului va fi adresa IP alocată gazdei pe care se află serverul. De asemenea, spunem că trebuie să aranjăm ca pachetele să fie trimise în portul nouă.

Atributul „MaxPackets” îi spune clientului numărul maxim de pachete pe care le putem trimite în timpul simulării. Atributul „Interval” îi spune clientului cât timp trebuie să aștepte între pachete, iar atributul „PacketSize” îi spune clientului cât de mare ar trebui să fie sarcina utilă a pachetului. Cu această combinație de atribute îi spunem clientului să trimită un singur pachet de 1024 de octeți.

Ca și în cazul serverului echo, setăm atributele clientului echo acasă и Stop, dar aici pornim clientul la o secundă după ce serverul este pornit (două secunde după începerea simulării).

4.2.8 Simulator

În acest moment, trebuie să rulăm simularea. Acest lucru se face folosind funcția globală Simulator::Run.

Simulator::Run ();

Când am numit anterior metode,

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

de fapt, am programat evenimente în simulator la 1,0 secunde, 2,0 secunde și două evenimente la 10,0 secunde. După apel Simulator::Run, sistemul va începe să vizualizeze lista de evenimente programate și să le execute. Mai întâi va declanșa un eveniment după 1,0 secunde, care va declanșa aplicația de server echo (acest eveniment poate programa, la rândul său, multe alte evenimente). Apoi va declanșa un eveniment programat la t=2,0 secunde care va lansa aplicația client echo. Din nou, acest eveniment poate avea multe alte evenimente planificate. Implementarea evenimentului de pornire în clientul echo va începe faza de transfer de date a simulării prin trimiterea unui pachet către server.

Acțiunea de a trimite un pachet către server va declanșa un lanț de evenimente care vor fi programate automat în culise și care vor implementa mecanica trimiterii unui pachet echo conform parametrilor de sincronizare pe care i-am setat în script.

Ca urmare, deoarece trimitem un singur pachet (rețineți, atributul MaxPackets a fost setat la unu), lanțul de evenimente inițiat de acest singur client ping se va încheia și simularea va intra în modul de așteptare. Odată ce se întâmplă acest lucru, evenimentele programate rămase vor fi evenimentele Stop pentru server și client. Când aceste evenimente sunt executate, nu vor mai rămâne evenimente pentru procesare ulterioară și Simulator::Run va reveni controlul. Simularea este completă.

Tot ce rămâne este să te cureți după tine. Acest lucru se face prin apelarea funcției globale Simulator::Distruge. Pentru că au fost apelate funcțiile de ajutor (sau codul ns-3 de nivel scăzut), care sunt organizate astfel încât să fie introduse cârlige în simulator pentru a distruge toate obiectele care au fost create. Nu trebuia să urmăriți singur niciunul dintre aceste obiecte - tot ce trebuia să faceți era să suni Simulator::Distruge si iesi afara. Sistemul ns-3 va face această muncă grea pentru dvs. Rândurile rămase ale primului nostru script ns-3, first.cc, fac exact asta:

Simulator::Destroy ();
return 0;
}

Când se va opri simulatorul?

ns-3 este un simulator de evenimente discrete (DE). Într-un astfel de simulator, fiecare eveniment este asociat cu timpul său de execuție, iar simularea continuă prin procesarea evenimentelor în ordinea în care apar pe măsură ce simularea progresează. Evenimentele pot determina programarea evenimentelor viitoare (de exemplu, un cronometru se poate reprograma singur pentru a termina numărarea în intervalul următor).

Evenimentele inițiale sunt de obicei inițiate de entitate, de exemplu IPv6 va programa descoperirea serviciilor în rețea, solicitările vecinilor etc. Aplicația programează primul eveniment de trimitere a pachetelor și așa mai departe. Când un eveniment este procesat, acesta poate genera zero, unul sau mai multe evenimente. Pe măsură ce simularea progresează, apar evenimente, fie terminând, fie creând altele noi. Simularea se va opri automat dacă coada de evenimente este goală sau este detectat un eveniment special Stop. Eveniment Stop generată de funcție Simulator::Stop (opreste timpul).

Există un caz tipic în care Simulator::Stop este absolut necesar pentru a opri simularea: atunci când există evenimente auto-susținute. Evenimentele auto-susținute (sau repetate) sunt evenimente care sunt întotdeauna reprogramate. În consecință, ei păstrează întotdeauna coada de evenimente nu goală. Există multe protocoale și module care conțin evenimente repetate, de exemplu:

• FlowMonitor - verificare periodică a pachetelor pierdute;

• RIPng – difuzare periodică a actualizărilor tabelului de rutare;

• etc.

În astfel de cazuri Simulator::Stop necesar pentru a opri corect simularea. În plus, când ns-3 este în modul de emulare, RealtimeSimulator este folosit pentru a sincroniza ceasul de simulare cu ceasul mașinii și Simulator::Stop necesar pentru oprirea procesului.

Multe dintre programele de simulare din manual nu apelează Simulator::Stop în mod explicit, deoarece se încheie automat când evenimentele din coadă sunt epuizate. Cu toate acestea, aceste programe vor accepta și Simulator::Stop apel. De exemplu, următoarea instrucțiune suplimentară din primul exemplu de program ar programa o oprire explicită la 11 secunde:

+ Simulator::Stop (Seconds (11.0));
  Simulator::Run ();
  Simulator::Destroy ();
  return 0;
}

Cele de mai sus nu vor schimba de fapt comportamentul acestui program, deoarece această simulare particulară se termină în mod natural după 10 secunde. Dar dacă ar fi să modificați timpul de oprire din declarația de mai sus de la 11 secunde la 1 secundă, veți observa că simularea se oprește înainte ca orice ieșire să lovească ecranul (deoarece ieșirea are loc după aproximativ 2 secunde de timp de simulare).

Este important să apelați Simulator::Stop înainte de a apela Simulator::Run; în caz contrar, Simulator::Run nu poate returna niciodată controlul programului principal pentru a executa oprirea!

4.2.9 Construirea scriptului

Am făcut ca crearea scripturilor tale simple să fie banală. Tot ce trebuie să faceți este să vă puneți scriptul în directorul scratch și va fi construit automat dacă rulați waf. Sa incercam. Reveniți la directorul de nivel superior și copiați exemple/tutorial/first.cc la catalog zgâria

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

Acum construiți primul exemplu de script folosind WAF:

$ ./waf

Ar trebui să vedeți mesaje care indică faptul că primul exemplu a fost creat cu succes.

Waf: Entering 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: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (2.357s)

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

$ ./waf --run scratch/myfirst

Ar trebui să vedeți rezultate similare:

Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
'build' finished successfully (0.418s) Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2

Aici puteți vedea că sistemul de compilare verifică dacă fișierul a fost construit și apoi îl rulează. Vedeți că intrarea de componentă pe clientul echo indică faptul că a trimis un singur pachet de 1024 de octeți către serverul echo 10.1.1.2. Vedeți și dvs. componenta de înregistrare pe serverul echo pentru a spune că a primit 1024 de octeți de la 10.1.1.1. Serverul echo redă în tăcere pachetul și puteți vedea în jurnalul clientului echo că a primit pachetul înapoi de la server.

4.3 ns-3 Cod sursă

Acum că ați folosit unii dintre ajutoarele ns-3, puteți arunca o privire asupra codului sursă care implementează această funcționalitate. Cel mai recent cod poate fi vizualizat pe serverul nostru web la următorul link: https://gitlab.com/nsnam/ns-3-dev.git. Acolo veți vedea pagina de rezumat Mercurial pentru arborele nostru de dezvoltare ns-3. În partea de sus a paginii veți vedea mai multe link-uri,

summary | shortlog | changelog | graph | tags | files

Continuați și selectați linkul fișierelor. Iată cum va arăta nivelul superior al majorității depozitelor noastre:

drwxr-xr-x                               [up]
drwxr-xr-x                               bindings python  files
drwxr-xr-x                               doc              files
drwxr-xr-x                               examples         files
drwxr-xr-x                               ns3              files
drwxr-xr-x                               scratch          files
drwxr-xr-x                               src              files
drwxr-xr-x                               utils            files
-rw-r--r-- 2009-07-01 12:47 +0200 560    .hgignore        file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1886   .hgtags          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 1276   AUTHORS          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 30961  CHANGES.html     file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 17987  LICENSE          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 3742   README           file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 16171  RELEASE_NOTES    file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 6      VERSION          file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 88110  waf              file | revisions | annotate
-rwxr-xr-x 2009-07-01 12:47 +0200 28     waf.bat          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 35395  wscript          file | revisions | annotate
-rw-r--r-- 2009-07-01 12:47 +0200 7673   wutils.py        file | revisions | annotate

Exemplele noastre de scripturi sunt în director exemple. Dacă faceți clic pe exemple, veți vedea o listă de subdirectoare. Unul dintre fișierele din subdirector tutorial - primul.cc. Dacă dai clic pe mai întâi.cc veți vedea codul pe care tocmai l-ați învățat.

Codul sursă se află în principal în director src. Puteți vizualiza codul sursă făcând clic pe numele directorului sau făcând clic pe linkul fișierelor din dreapta numelui directorului. Dacă faceți clic pe directorul src, veți obține o listă de subdirectoare src. Dacă apoi faceți clic pe subdirectorul de bază, veți găsi o listă de fișiere. Primul fișier pe care îl veți vedea (la momentul scrierii acestui ghid) este avorta.h. Dacă dați clic pe link avorta.h, veți fi trimis la fișierul sursă pentru avorta.h, care conține macrocomenzi utile pentru ieșirea din scripturi dacă sunt detectate condiții anormale. Codul sursă pentru ajutoarele pe care le-am folosit în acest capitol poate fi găsit în director src/Aplicații/helper. Simțiți-vă liber să căutați în arborele de directoare pentru a afla ce este unde și pentru a înțelege stilul programelor ns-3.

Sursa: www.habr.com

Adauga un comentariu