ns-3 netwurk simulator tutorial. Haadstik 4

ns-3 netwurk simulator tutorial. Haadstik 4
haadstik 1,2
haadstik 3

4 Konseptoersjoch
4.1 Key abstraksjes
4.1.1 Knooppunt
4.1.2 Applikaasje
4.1.3 Kanaal
4.1.4 Net Apparaat
4.1.5 Topologyske assistinten
4.2 Earste ns-3 skript
4.2.1 Boilerplate koade
4.2.2 Ynstekkers
4.2.3 ns3 nammeromte
4.2.4 Logging
4.2.5 Main funksje
4.2.6 Mei help fan topology assistinten
4.2.7 Mei help fan tapassing
4.2.8 Simulator
4.2.9 Bouwe jo skript
4.3 ns-3 Boarnekoade

Haadstik 4

Konseptoersjoch

It earste wat wy moatte dwaan foardat wy begjinne te learen of skriuwen ns-3 koade is te ferklearjen in pear basisbegripen en abstraksjes yn it systeem. In protte fan dit kin foar guon fanselssprekkend lykje, mar wy riede oan om de tiid te nimmen om dizze seksje te lêzen om te soargjen dat jo begjinne op in solide basis.

4.1 Key abstraksjes

Yn dizze seksje sille wy sjen nei guon termen dy't faak brûkt wurde op it web, mar hawwe in spesifike betsjutting yn ns-3.

4.1.1 Knooppunt

Yn ynternetjargon wurdt in kompjûterapparaat dat oanslút op in netwurk in host neamd of soms in einsysteem. Om't ns-3 in netwurksimulator is en gjin ynternetsimulator, brûke wy de term host mei opsetsin net, om't dit nau besibbe is mei it ynternet en syn protokollen. Ynstee dêrfan brûke wy in mear algemiene term, ek brûkt troch oare simulators, dy't ûntstiet yn 'e grafykteory: node (node).

Yn ns-3 wurdt de ûnderlizzende abstraksje fan in komputerapparaat in knooppunt neamd. Dizze abstraksje wurdt yn C ++ fertsjintwurdige troch de Node-klasse. Klasse NodeNode (knooppunt) jout metoaden foar it manipulearjen fan foarstellings fan komputerapparaten yn simulaasjes.

Jo moatte begripe node lykas in kompjûter dêr't jo funksjonaliteit taheakje. Jo sille dingen tafoegje lykas applikaasjes, protokolstapels en perifeare kaarten mei sjauffeurs wêrmei't de kompjûter nuttich wurk kin dwaan. Wy brûke itselde basismodel yn ns-3.

4.1.2 Applikaasje

Yn 't algemien is kompjûtersoftware ferdield yn twa brede klassen. Systeem software organisearret ferskate kompjûter boarnen lykas ûnthâld, prosessor cycles, skiif, netwurk, ensfh neffens guon computing model. Systeemsoftware brûkt typysk dizze boarnen net om taken út te fieren dy't de brûker direkt profitearje. In brûker rint typysk in applikaasje om in spesifyk doel te berikken, dy't boarnen krijt en brûkt kontroleare troch de systeemsoftware.

Faak wurdt de line fan skieding tusken systeem- en tapassingssoftware tekene op feroarings op privileezjenivo dy't foarkomme yn bestjoeringssysteemfallen. ns-3 hat gjin echte konsept fan in bestjoeringssysteem en dêrom gjin konsept fan privileezje nivo's of systeem calls. Wy hawwe wol in idee foar in app. Krekt as yn 'e "echte wrâld" software-applikaasjes rinne op kompjûters om taken út te fieren, rinne ns-3-applikaasjes op ns-3-knooppunten om simulaasjes yn 'e simulearre wrâld te kontrolearjen.

Yn ns-3 is de basis abstraksje foar in brûker programma dat generearret wat aktiviteit foar modellewurk is in applikaasje. Dizze abstraksje wurdt yn C ++ fertsjintwurdige troch de Applikaasjeklasse. De Applikaasjeklasse leveret metoaden foar it manipulearjen fan werjeften fan ús ferzje fan applikaasjes op brûkersnivo yn simulaasjes. Untwikkelders wurde ferwachte dat se de Applikaasjeklasse spesjalisearje yn in objekt-rjochte programmearring sin om nije applikaasjes te meitsjen. Yn dizze tutorial sille wy spesjalisaasjes brûke fan 'e Applikaasjeklasse neamd UdpEchoClientApplication и UdpEchoServerApplication. Lykas jo miskien ferwachtsje, meitsje dizze applikaasjes in set fan client-/serverapplikaasjes út dy't brûkt wurde om netwurkpakketten te generearjen en te echo.

4.1.3 Kanaal

Yn 'e echte wrâld kinne jo in kompjûter ferbine mei in netwurk. Faak wurde de media dêr't gegevens oer oerbrocht wurde yn dizze netwurken kanalen neamd. As jo ​​​​in Ethernet-kabel yn in stikkontakt stekke, ferbine jo jo kompjûter mei in Ethernet-keppeling. Yn 'e simulearre ns-3 wrâld is in knooppunt ferbûn mei in objekt dat in kommunikaasjekanaal fertsjintwurdiget. Hjir wurdt de basisabstraksje fan it kommunikaasjesubnetwurk in kanaal neamd en wurdt fertsjintwurdige yn C ++ troch de Channel-klasse.

Klasse ChannelChannel jout metoaden foar it behearen fan de ynteraksje fan subnetobjekten en it ferbinen fan knooppunten dêrmei. Kanalen kinne ek spesjalisearre wurde troch ûntwikkelders yn in objekt-rjochte programmearring. Kanaal spesjalisaasje kin model wat sa ienfâldich as in tried. In tawijd kanaal kin ek komplekse dingen modellearje lykas in grutte Ethernet-switch of in trijediminsjonale romte fol obstakels yn it gefal fan draadloze netwurken.

Wy sille spesjalisearre ferzjes fan it kanaal brûke yn dizze tutorial neamd CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel и WifiChannelWifiChannel. CsmaChannel, bygelyks, modellen in ferzje fan in kommunikaasje subnet dat ymplemintearret in carrier-sense meardere tagong kommunikaasje omjouwing. Dit jout ús Ethernet-like funksjonaliteit.

4.1.4 Net Apparaat

It wie eartiids dat as jo in kompjûter ferbine woene mei in netwurk, jo in spesifike netwurkkabel keapje moasten en in hardwareapparaat neamd (yn PC-terminology) in perifeare kaart dy't yn 'e kompjûter ynstallearre wurde moast. As in perifeare kaart ymplementearre guon netwurk funksjes, se waarden neamd netwurk ynterface cards of netwurk cards. Tsjintwurdich komme de measte kompjûters mei yntegreare hardware foar netwurkynterface en wurde troch brûkers net as aparte apparaten sjoen.

In netwurkkaart sil net wurkje sûnder in softwarebestjoerder dy't har hardware kontrolearret. Yn Unix (as Linux) wurdt in stik perifeare apparatuer klassifisearre as in apparaat. Apparaten wurde beheard mei apparaatbestjoerders, en netwurkapparaten (NIC's) wurde beheard mei netwurkapparaatbestjoerders (netwurk apparaat drivers) en wurde mei-inoar netwurkapparaten neamd (net apparaten). Yn Unix en Linux ferwize jo nei netwurkapparaten mei nammen lykas Eth0.

Yn ns-3 beslacht de abstraksje fan netwurkapparaat sawol de softwarebestjoerder as de hardware dy't wurdt modeleare. Yn 'e simulaasje wurdt in netwurkapparaat "ynstalleare" yn in knooppunt om it fia kanalen te kommunisearjen mei oare knooppunten. Krekt as in echte kompjûter kin in knooppunt wurde ferbûn mei meardere kanalen fia meardere apparaten NetDevices.

De netwurkabstraksje fan in apparaat wurdt fertsjintwurdige yn C ++ troch de klasse NetDevice. Klasse NetDevice jout metoaden foar it behearen fan ferbinings nei Node- en Channel-objekten; en kin wurde spesjalisearre troch ûntwikkelders yn 'e betsjutting fan objekt-rjochte programmearring. Yn dizze tutorial sille wy ferskate spesjalisearre ferzjes brûke fan NetDevice neamd CsmaNetDevice, PointToPointNetDevice и WifiNetDevice. Krekt as in Ethernet-netwurkadapter is ûntworpen om te wurkjen mei in netwurk Ethernet, CsmaNetDevice ûntwurpen om te wurkjen mei CsmaChannel, PointToPointNetDevice ûntwurpen om te wurkjen mei PointToPointChannelen WifiNetDevice - ûntwurpen om te wurkjen mei WifiChannel.

4.1.5 Topologyske assistinten

Yn in echt netwurk fine jo hostkompjûters mei netwurkkaarten tafoege (of ynboude). Yn ns-3 soene wy ​​sizze dat jo knooppunten sille sjen mei NetDevices taheakke. Yn in grut simulearre netwurk moatte jo ferbiningen organisearje tusken in protte objekten node, NetDevice и Kanaal.

Sûnt it ferbinen fan NetDevices oan knopen, NetDevices nei keppelings, it tawizen fan IP-adressen, ensfh. yn ns-3 binne in mienskiplike taak, foar in meitsje dit sa maklik mooglik wy jouwe saneamde topology helpers. Bygelyks, om in NetDevice te meitsjen, moatte jo in protte ns-3 kernel-operaasjes útfiere, in MAC-adres tafoegje, it netwurkapparaat yn Node ynstallearje, de protokolstapel fan 'e knoop konfigurearje, en dan it NetDevice ferbine mei it kanaal. Noch mear wurk sil nedich wêze om meardere apparaten te ferbinen mei multipoint-keppelings en dan de yndividuele netwurken te ferbinen mei in Internetworks-netwurk. Wy leverje topologyhelpobjekten dy't dizze protte operaasjes kombinearje yn in maklik te brûken model foar jo gemak.

4.2 Earste ns-3 skript

As jo ​​​​it systeem ynstalleare lykas hjirboppe oansteld, sille jo de ns-3-release hawwe yn in map mei de namme repos yn jo thúsmap. Gean nei triemtafel release

As jo ​​net sa'n map hawwe, betsjut it dat jo de útfiermap net hawwe opjûn by it bouwen fan de releaseferzje fan ns-3, bouwe sa:
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf build

dêr soene jo in mapstruktuer sjen moatte lykas de folgjende:

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

Gean nei triemtafel foarbylden / tutorial. Jo moatte in bestân sjen dat dêr leit neamd earst.cc. Dit is in skript dat sil meitsje in ienfâldige punt-to-punt ferbining tusken twa knooppunten en stjoert ien pakket tusken de knooppunten. Litte wy dit skript rigel foar rigel besjen; om dit te dwaan, iepenje first.cc yn jo favorite bewurker.

4.2.1 Boilerplate koade
De earste rigel yn it bestân is de line fan de bewurkermodus emacs. It fertelt emacs oer de opmaakkonvinsjes (kodearingsstyl) dy't wy brûke yn ús boarnekoade.

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

Dit is altyd nochal in kontroversjele kwestje, dus wy moatte it rekord rjocht sette om it fuort út 'e wei te krijen. It ns-3-projekt hat, lykas de measte grutte projekten, in kodearringstyl oannaam dêr't alle bydroegen koade oan moatte foldwaan. As jo ​​jo koade bydrage wolle oan it projekt, moatte jo úteinlik oanpasse oan de ns-3-kodearringsstandert, lykas beskreaun yn it bestân doc/codingstd.txt of werjûn op de projektwebside: https://www.nsnam.org/develop/contributing-code/coding-style/.

Wy riede oan dat jo wend wurde oan it uterlik en gefoel fan ns-3-koade en dizze standert tapasse as jo mei ús koade wurkje. It hiele ûntwikkelingsteam en de meiwurkers stimden dêr nei wat grommeljen mei yn. De emacs-modusline hjirboppe makket it maklik om korrekt te formatteren as jo de emacs-bewurker brûke.

De ns-3-simulator is mei lisinsje GNU Algemiene publike lisinsje. Jo sille de passende GNU-juridyske koptekst sjen yn elk ns-3-distribúsjebestân. Faak sjogge jo in auteursrjochtmelding foar ien fan 'e dielnimmende ynstellingen yn it ns-3-projekt boppe de GPL-tekst en auteur, hjirûnder werjûn.

/* 
* 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 Ynstekkers

De koade sels begjint mei in searje ynklúzjebewearingen (ynklusyf).

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

Om ús skriptbrûkers op heech nivo te helpen om te gean mei it grutte oantal koptekstbestannen oanwêzich yn it systeem, groepearje wy se neffens har gebrûk yn grutte modules. Wy leverje in inkele kopteksttriem dy't alle koptekstbestannen rekursyf sil laden yn in opjûne module. Yn stee fan te sykjen nei krekt hokker koptekst jo nedich hawwe en mooglik de juste list mei ôfhinklikens krije, jouwe wy jo de mooglikheid om in groep bestannen yn grutte granulariteit te downloaden. It is net de meast effisjinte oanpak, mar it makket grif it skriuwen fan skripts in stik makliker.

Elk fan 'e ns-3 befetsje triemmen wurdt pleatst yn in map neamd ns3 (build subdirectory) om bestânsnammekonflikten te foarkommen tidens it bouproses. Map ns3/core-module.h komt oerien mei de ns-3-module, dy't jo fine yn 'e map src/core yn 'e release dy't jo ynstalleare. Yn 'e list fan dizze map fine jo in grut oantal koptekstbestannen. As jo ​​​​de gearstalling dogge, Waf pleatst iepenbiere koptekstbestannen yn 'e ns3-map yn in submap build / debug

As jo ​​net sa'n map hawwe, betsjut it dat jo de útfiermap net hawwe opjûn by it bouwen fan de releaseferzje fan ns-3, bouwe sa:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf build
of
$ ./waf configure --build-profile=optimalisearre --out=build/optimisearre
$ ./waf build

of build / optimalisearre, ôfhinklik fan jo konfiguraasje. Waf sil ek automatysk in module befetsje triem generearje om alle publike koptekstbestannen te laden. Om't jo dizze gids fansels religieus folgje, hawwe jo it al dien

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

om it projekt te konfigurearjen om debug-builds út te fieren dy't foarbylden en tests omfetsje. Jo hawwe ek dien

$ ./waf

om it projekt te sammeljen. Dus no as jo yn 'e map sjogge ../../build/debug/ns3, dan fine jo dêr ûnder oaren de koptekstbestannen fan de fjouwer hjirboppe werjûn modules. Jo kinne de ynhâld fan dizze bestannen besjen en fine dat se alle iepenbiere bestannen befetsje dy't brûkt wurde troch de oerienkommende modules.

4.2.3 ns3 nammeromte

Folgjende rigel yn skript earst.cc is in nammeromte deklaraasje.

using namespace ns3;

It ns-3-projekt wurdt ymplementearre yn in C ++ nammeromte neamd ns3. Dit groepearret alle ns-3-relatearre ferklearrings yn in omfang bûten de globale nammeromte, dy't hooplik sil helpe mei yntegraasje mei oare koade. It brûken fan de C ++ operator yntrodusearret de ns-3 nammeromte yn de hjoeddeiske (globale) declarative regio. Dit is in fancy manier om te sizzen dat jo nei dizze ferklearring de ns3 :: scope tastimmingsoperator net hoege te typen foar al jo ns-3-koade om it te brûken. As jo ​​net bekend binne mei nammeromten, ferwize dan nei hast elk C++-learboek en fergelykje de ns3-nammeromte mei de std-nammeromte en deklaraasje using namespace std; yn foarbylden fan wurkjen mei de útfier operator kosten en streamen.

4.2.4 Logging

De folgjende rigel fan it skript is:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Wy sille dizze ferklearring brûke as in handich plak om ús dokumintaasjesysteem te besprekken doxygen. As jo ​​​​nei de webside fan it ns-3-projekt sjogge, sille jo in dokumintaasjekeppeling fine yn 'e navigaasjebalke. As jo ​​op dizze keppeling klikke, wurde jo nei ús dokumintaasjeside brocht. D'r is in keppeling "Lêste release" dy't jo bringt nei de dokumintaasje foar de lêste stabile ferzje fan ns-3. As jo ​​de keppeling "API Documentation" selektearje, wurde jo nei de ns-3 API dokumintaasje side brocht.

Oan de linkerkant fan de side fine jo in grafyske foarstelling fan de dokumintaasje struktuer. In goed plak om te begjinnen is it Modules ns-3 "boek" yn 'e ns-3 navigaasjebeam. As jo ​​iepenbierje modules, sjogge jo in list mei ns-3 modules dokumintaasje. Lykas hjirboppe besprutsen, is it konsept fan in module hjir direkt relatearre oan de bestannen opnaam yn 'e module hjirboppe. It ns-3-logging-subsysteem wurdt besprutsen yn seksje It brûken fan de Logging Module, dus wy komme der letter op werom yn dizze tutorial, mar jo kinne leare oer de boppesteande ferklearring troch te sjen nei de module Kearnen dan it boek iepenje Debugging-arken selektearje dan de side Logging. Klikje op Logging.

Jo moatte no de dokumintaasje besjen doxygen foar module Logging. Yn 'e list mei makro's oan' e boppekant fan 'e side sille jo in yngong sjen foar NS_LOG_COMPONENT_DEFINE. Foardat jo op de kepling klikke, wês wis dat jo de "Detaillearre beskriuwing" fan 'e registraasjemodule besjen om te begripen hoe't it yn it algemien wurket. Om dit te dwaan kinne jo nei ûnderen rôlje of "Mear ..." selektearje ûnder it diagram.

As jo ​​​​ienris in algemien idee hawwe fan wat der bart, gean dan fierder en sjoch nei de dokumintaasje foar de spesifike NS_LOG_COMPONENT_DEFINE. Ik sil de dokumintaasje hjir net duplisearje, mar om gear te nimmen, dizze rigel ferklearret in registraasjekomponint neamd Foarbyld fan FirstScript, wêrmei jo konsole-logging fan berjochten yn- of útskeakelje kinne troch ferwizing nei in namme.

4.2.5 Main funksje

Yn 'e folgjende rigels fan it skript sille jo sjen,

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

Dit is gewoan in ferklearring fan 'e haadfunksje fan jo programma (skript). Lykas by alle C++ programma, moatte jo in haadfunksje definiearje, dit wurdt earst útfierd. D'r is hjir neat spesjaal. Jo ns-3 skript is gewoan in C++ programma. De folgjende rigel stelt de tiidresolúsje yn op 1 nanosekonde, dat is de standert:

Time::SetResolution (Time::NS);

Tiid resolúsje, of gewoan resolúsje, is de lytste tiid wearde dy't brûkt wurde kin (it lytste fertsjintwurdige ferskil tusken twa kear). Jo kinne de resolúsje krekt ien kear feroarje. It meganisme dat dizze fleksibiliteit leveret, ferbrûkt ûnthâld, dus as de resolúsje eksplisyt ynsteld is, befrije wy it ûnthâld, en foarkomme fierdere updates. (As jo ​​de resolúsje net eksplisyt ynstelle, sil it standert ien nanosekonde en it ûnthâld sil befrijd wurde as de simulaasje begjint.)

De folgjende twa rigels fan skript wurde brûkt om twa logging komponinten yn te skeakeljen dy't binne ynboud yn applikaasjes EchoClient и EchoServer:

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

As jo ​​de dokumintaasje lêze foar de komponint Logging, sille jo sjen dat d'r ferskate nivo's fan logging / granulariteit binne dy't jo kinne ynskeakelje op elke komponint. Dizze twa rigels koade kinne debug-logging ynskeakelje nei it INFO-nivo foar echo-kliïnten en servers. Op dit nivo sil de applikaasje berjochten printsje as it pakketten ferstjoert en ûntfangt tidens simulaasje.

No sille wy delkomme by it bedriuw fan it meitsjen fan de topology en it útfieren fan de simulaasje. Wy brûke topologyhelpobjekten om dizze taak sa maklik mooglik te meitsjen.

4.2.6 Mei help fan topology assistinten

De folgjende twa rigels koade yn ús skript sille eins de Node ns-3-objekten meitsje dy't de kompjûters yn 'e simulaasje fertsjintwurdigje.

NodeContainer nodes;
nodes.Create (2);

Foardat wy trochgean, litte wy de dokumintaasje foar de klasse fine NodeContainer. In oare manier om nei de dokumintaasje foar in opjûne klasse te kommen is fia de ljepper klassen op de siden doxygen. As jo ​​Doxygen al iepen hawwe, rôlje dan gewoan nei de boppekant fan 'e pagina en selektearje it ljepblêd Klassen. Jo moatte in nije set ljeppers sjen, wêrfan ien in list mei klassen is. Under dizze ljepper sille jo in list sjen fan alle ns-3-klassen. Skow del nei ns3 :: NodeContainer. As jo ​​in klasse fine, selektearje dizze om nei de dokumintaasje foar de klasse te gean.

As wy ûnthâlde, is ien fan ús wichtichste abstraksjes de knooppunt. It fertsjintwurdiget de kompjûter dêr't wy dingen sille tafoegje lykas protokolstacks, applikaasjes en perifeare kaarten. Topology assistint NodeContainer biedt in handige manier om alle objekten te meitsjen, te behearjen en tagong te krijen node, dy't wy meitsje om de simulaasje út te fieren. De earste line hjirboppe ferklearret gewoan NodeContainer, dy't wy nodes neame. De twadde rigel neamt de metoade Create op it knooppuntobjekt en freget de kontener om twa knooppunten te meitsjen. As beskreaun yn doxygen, de kontener freget it ns-3-systeem om twa objekten te meitsjen node en bewarret pointers nei dizze objekten yntern.

De knopen makke yn it skript dogge noch neat. De folgjende stap yn it bouwen fan de topology is it ferbinen fan ús knopen mei it netwurk. De ienfâldichste foarm fan netwurk dat wy stypje is in punt-to-punt ferbining tusken twa knopen. Wy sille no sa'n ferbining meitsje.

PointToPointHelper

Wy meitsje in punt-tot-punt ferbining mei in bekend patroan, mei help fan in topology helper foarwerp te dwaan it leech-nivo wurk nedich foar de ferbining. Tink derom dat ús twa wichtige abstraksjes NetDevice и Kanaal. Yn 'e echte wrâld komme dizze termen rûchwei oerien mei perifeare kaarten en netwurkkabels. Typysk binne dizze twa dingen nau besibbe oan elkoar, en gjinien kin rekkenje op it dielen fan bygelyks apparaten Ethernet oer in draadloos kanaal. Us topologyhelpers folgje dizze nauwe relaasje en dêrom sille jo in inkeld objekt yn dit senario brûke PointToPointHelper foar it opsetten en ferbinen fan ns-3 objekten PointToPointNetDevice и PointToPointChannel. De folgjende trije rigels yn it skript:

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

Earste rigel,

PointToPointHelper pointToPoint;

makket in eksimplaar fan in foarwerp op 'e steapel PointToPointHelper. Ut in eachpunt fan boppeste nivo de folgjende line,

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

fertelt it objekt PointToPointHelper brûk de wearde "5 Mbit/s" (fiif megabits per sekonde) as "DataRate".

Ut in mear spesifyk eachpunt komt de tekenrige "DataRate" oerien mei wat wy in attribút neame PointToPointNetDevice. As jo ​​sjogge nei doxygen foar klasse ns3 :: PointToPointNetDevice en yn 'e dokumintaasje foar de metoade GetTypeId jo fine in list mei attributen definiearre foar it apparaat. Under harren sil it attribút wêze "DataRate" De measte brûker-sichtbere ns-3-objekten hawwe ferlykbere listen mei attributen. Wy brûke dit meganisme om de simulaasje maklik yn te stellen sûnder opnij kompilaasje, lykas jo sille sjen yn 'e folgjende paragraaf.

Gelyk oan "DataRate" yn PointToPointNetDevice, fine jo it "Delay" attribút ferbûn mei it PointToPointChannel. De lêste rigel

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

seit PointToPointHelper brûk de wearde "2 ms" (twa millisekonden) as de wearde fan ferspriedingsfertraging foar de punt-nei-punt-keppeling dy't it dêrnei oanmakket.

NetDeviceContainer

Op it stuit hawwe wy yn it skript NodeContainer, dy't twa knopen befettet. Wy hawwe PointToPointHelper, dat is taret foar it meitsjen fan objekten PointToPointNetDevices en ferbine se mei in PointToPointChannel-objekt. Krekt sa't wy it NodeContainer topologyhelperobjekt brûkten om knopen te meitsjen, sille wy freegje PointToPointHelper útfiere wurk foar ús yn ferbân mei de skepping, konfiguraasje en ynstallaasje fan ús apparaten. Wy moatte in list fan alle oanmakke objekten NetDevice, dus wy brûke NetDeviceContainer om se op deselde manier te bewarjen as wy brûkten NodeContainer om de knopen dy't wy makke hawwe op te slaan. De folgjende twa rigels koade,

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

folsleine apparaat en kanaal opset. De earste rigel ferklearret de hjirboppe neamde apparaatcontainer, en de twadde docht it haadwurk. Metoade Ynstallearje objekt PointToPointHelper aksepteart NodeContainer as parameter. Binnenkant NetDeviceContainer foar elke node leit yn NodeContainer wurdt makke (foar punt-tot-punt kommunikaasje moatte der krekt twa fan wêze) PointToPointNetDevice wurdt makke en bewarre yn 'e apparaatkontainer. PointToPointChannel wurdt makke en der binne twa oan ferbûn PointToPointNetDevices. Nei it meitsjen fan objekten binne de attributen opslein yn PointToPointHelper, wurde brûkt om de oerienkommende attributen yn 'e oanmakke objekten te inisjalisearjen.

Nei it meitsjen fan in oprop pointToPoint.Install (knooppunten) wy sille hawwe twa knopen, elk mei in punt-to-punt netwurk apparaat ynstallearre en ien punt-to-punt keppeling tusken harren. Beide apparaten sille wurde konfigureare om gegevens te ferstjoeren mei in snelheid fan fiif megabits per sekonde mei in transmissiefertraging fan twa millisekonden oer it kanaal.

InternetStackHelper

Wy hawwe no knooppunten en apparaten konfigureare, mar ús knooppunten hawwe gjin protokolstacks ynstalleare. De folgjende twa rigels fan koade sille soargje foar dit.

InternetStackHelper stack;
stack.Install (nodes);

InternetStackHelper - is in topologyhelper foar ynternetstapels, fergelykber mei PointToPointHelper foar punt-tot-punt netwurkapparaten. Metoade Ynstallearje nimt NodeContainer as parameter. As it wurdt útfierd, sil it de ynternetstapel (TCP, UDP, IP, ensfh.) Op elke kontenerknooppunt ynstallearje.

IPv4 AddressHelper

Dan moatte wy ús apparaten assosjearje mei IP-adressen. Wy leverje in topology-assistint om de tawizing fan IP-adres te behearjen. De ienige API sichtber foar de brûker is it ynstellen fan it basis IP-adres en netmasker om te brûken by it dwaan fan de eigentlike adresferdieling (dit wurdt dien op in leger nivo binnen de helper). De folgjende twa rigels koade yn ús foarbyldskript earst.cc,

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

ferklearje it adreshelperobjekt en fertel it dat it moat begjinne mei it tawizen fan IP-adressen fan netwurk 10.1.1.0, mei it 255.255.255.0 bitmasker om te bepalen. Standert sille tawiisde adressen begjinne by ien en monotoanysk tanimme, sadat it earste adres dat fan dizze basis wurdt tawiisd 10.1.1.1, dan 10.1.1.2, ensfh. Yn 'e realiteit, op in leech nivo, ûnthâldt it ns-3-systeem alle tawiisde IP-adressen en genereart in fatale flater as jo per ongelok in situaasje meitsje wêrby't itselde adres twa kear generearre wurdt (troch de manier, dizze flater is lestich te debuggen).

De folgjende rigel fan koade,

Ipv4InterfaceContainer interfaces = address.Assign (devices);

fiert de eigentlike adres opdracht. Yn ns-3 meitsje wy in ferbining tusken in IP-adres en in apparaat mei it objekt IPv4 ynterface. Krekt sa't wy soms in list fan netwurkapparaten nedich hawwe makke troch de assistint foar letter gebrûk, hawwe wy soms in list mei objekten nedich IPv4 ynterface. IPv4 InterfaceContainer jout dizze funksjonaliteit.

Wy bouden in punt-to-punt netwurk, mei stacks ynstallearre en IP-adressen tawiisd. No hawwe wy applikaasjes nedich yn elke knooppunt om ferkear te generearjen.

4.2.7 Mei help fan tapassing

In oare fan 'e wichtichste abstraksjes fan it ns-3 systeem is Oanfraach (oanfraach). Yn dit senario brûke wy twa basisklasse spesjalisaasjes Oanfraach ns-3 neamd UdpEchoServerApplication и UdpEchoClientApplication. Lykas yn eardere gefallen brûke wy helpobjekten om de basisobjekten te konfigurearjen en te behearjen. Hjir brûke wy UdpEchoServerHelper и UdpEchoClientHelper objekten om ús libben makliker te meitsjen.

UdpEchoServerHelper

De folgjende rigels koade yn ús first.cc foarbyldskript wurde brûkt om in UDP-echo-tsjinnerapplikaasje te konfigurearjen op ien fan 'e knopen dy't wy earder makke hawwe.

UdpEchoServerHelper echoServer (9);

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

De earste rigel fan koade yn it boppesteande snippet makket UdpEchoServerHelper. Lykas gewoanlik is dit gjin applikaasje sels, it is in objekt dat ús helpt om echte applikaasjes te meitsjen. Ien fan ús konvinsjes is om de fereaske attributen troch te jaan oan de konstruktor fan it helperobjekt. Yn dit gefal kin de helper neat nuttich dwaan, útsein as it it poartenûmer wurdt jûn wêrop de tsjinner nei pakketten harket, dit nûmer moat ek bekend wêze oan de kliïnt. Yn dit gefal jouwe wy it poartenûmer troch oan de helperkonstruktor. De konstruktor, op syn beurt, gewoan docht SetAttribute mei de trochjûn wearde. Letter, as jo wolle, kinne jo SetAttribute brûke om in oare wearde yn te stellen foar it Port-attribút.

Lykas in protte oare helpobjekten, it foarwerp UdpEchoServerHelper hat in metoade Ynstallearje. It útfieren fan dizze metoade makket effektyf in basale echo-serverapplikaasje en bynt it oan de host. Opfallend is de metoade Ynstallearje aksepteart NodeContainer as parameter krekt as de oaren Ynstallearje metoaden dy't wy hawwe sjoen.

De C ++ ymplisite konverzje dy't hjir wurket nimt it resultaat fan 'e metoade node.Get(1) (dy't in tûke oanwizer werombringt nei it knooppuntobjekt - Ptr) en brûkt it yn 'e konstruktor foar it anonime objekt NodeContainerdat wurdt dan trochjûn oan de metoade Ynstallearje. As jo ​​net kinne bepale yn C ++ koade hokker metoade hântekening wurdt gearstald en útfierd, dan sjoch ûnder de ymplisite konversaasjes.

No sjogge wy dat echoServer.Ynstallearje oer de applikaasje te ynstallearjen UdpEchoServerApplication op fûn yn NodeContainerdy't wy brûke om te behearjen ús knopen, knooppunt mei yndeks 1. Metoade Ynstallearje sil in kontener weromjaan dy't oanwizers befettet foar alle applikaasjes (yn dit gefal ien, om't wy in anonime NodeContainer, mei ien knooppunt) makke troch de helper.

Applikaasjes moatte oanjaan wannear't se begjinne mei it generearjen fan ferkear "start" en moat miskien ek in tiid opjaan wannear't it stopje moat "ophâlde". Wy biede beide opsjes. Dizze tiden wurde ynsteld mei de metoaden ApplicationContainer Start и Ophâlde. Dizze metoaden akseptearje parameters fan type Tiid. Yn dit gefal brûke wy in eksplisite folchoarder fan C ++-konverzjes om C ++ te nimmen dûbel 1.0 en konvertearje it nei in tns-3 Time-objekt dat it Seconds-objekt brûkt om te konvertearjen nei sekonden. Unthâld dat de konverzje regels kinne wurde regele troch it model skriuwer, en C ++ hat syn eigen regels, dus do kinst net altyd rekkenje op de parameters wurde omsetten sa't jo ferwachte. Twa rigels

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

sil de echo-tsjinnerapplikaasje begjinne (automatysk ynskeakelje) ien sekonde nei't de simulaasje begjint en stopje (útsette) nei tsien sekonden fan 'e simulaasje. Fanwegen it feit dat wy in simulaasje-evenemint (applikaasje-stop-evenemint) ferklearre, dat yn tsien sekonden útfierd wurde sil, sil op syn minst tsien sekonden fan netwurkoperaasje wurde simulearre.

UdpEchoClientHelper

Client applikaasje echo ynsteld op in manier hast gelyk oan de tsjinner. Der is in basis foarwerp UdpEchoClientApplicationrinne troch
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));;

Foar de echo-kliïnt moatte wy lykwols fiif ferskillende attributen ynstelle. De earste twa attributen wurde ynsteld op skepping tiid UdpEchoClientHelper. Wy passe parameters troch dy't wurde brûkt (binnen de helper) om de attributen yn te stellen "RemoteAddress" и "RemotePort" yn oerienstimming mei ús oerienkomst om de nedige parameters troch te jaan oan de helperkonstruktor.

Lit ús ûnthâlde dat wy brûkten IPv4 InterfaceContainer om de IP-adressen te folgjen dy't wy oan ús apparaten hawwe tawiisd. De nul-ynterface yn 'e ynterface-kontener sil oerienkomme mei it IP-adres fan' e nul-knooppunt yn 'e nodes-kontener. De earste ynterface yn 'e ynterfacecontainer komt oerien mei it IP-adres fan' e earste node yn 'e nodescontainer. Dat, yn 'e earste rigel fan koade (boppe), meitsje wy in helper en fertelle it dat it ôfstânadres fan de kliïnt it IP-adres sil wêze dat is tawiisd oan de host wêr't de tsjinner leit. Wy sizze ek dat wy moatte regelje dat pakketten wurde stjoerd nei poarte njoggen.

It attribút "MaxPackets" fertelt de kliïnt it maksimum oantal pakketten dat wy kinne stjoere tidens de simulaasje. De "Interval" attribút fertelt de klant hoe lang te wachtsjen tusken pakketten, en de "PacketSize" attribút fertelt de klant hoe grut it pakket syn payload moat wêze. Mei dizze attribútkombinaasje fertelle wy de kliïnt om in inkele 1024-byte pakket te stjoeren.

Lykas by de echo-tsjinner, sette wy de attributen fan 'e echo-client yn Start и Ophâlde, mar hjir begjinne wy ​​de kliïnt in sekonde nei't de tsjinner ynskeakele is (twa sekonden nei it begjin fan 'e simulaasje).

4.2.8 Simulator

Op dit punt moatte wy de simulaasje útfiere. Dit wurdt dien mei de globale funksje Simulator :: Run.

Simulator::Run ();

Doe't wy earder metoaden neamden,

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

wy hawwe eins barrens yn 'e simulator pland op 1,0 sekonden, 2,0 sekonden, en twa eveneminten op 10,0 sekonden. Nei de oprop Simulator :: Run, sil it systeem begjinne om de list mei plande eveneminten te besjen en se út te fieren. It sil earst in evenemint nei 1,0 sekonden fjoerje, wat de echo-tsjinnerapplikaasje sil trigger (dit evenemint kin op syn beurt in protte oare eveneminten planne). It sil dan in barren ûntsteane dat is pland op t = 2,0 sekonden dy't de echo-kliïntapplikaasje sil starte. Nochris kin dit barren folle mear eveneminten pland hawwe. De ymplemintaasje fan startevenemint yn 'e echo-client sil de gegevensferfierfaze fan' e simulaasje begjinne troch in pakket nei de tsjinner te stjoeren.

De hanneling fan it ferstjoeren fan in pakket nei de tsjinner sil in keatling fan eveneminten trigger dy't automatysk efter de skermen wurdt pland en dy't de meganika sil ymplementearje fan it ferstjoeren fan in echopakket neffens de timingparameters dy't wy yn it skript hawwe ynsteld.

As gefolch, om't wy mar ien pakket ferstjoere (ûnthâld, it attribút MaxPackets waard ynsteld op ien), sil de keatling fan eveneminten inisjearre troch dizze single client-ping einigje en de simulaasje sil yn standby-modus gean. Sadree't dit bart, sille de oerbleaune plande eveneminten de eveneminten wêze Ophâlde foar tsjinner en client. Wannear't dizze eveneminten wurde útfierd, der sil gjin eveneminten oerbleaun foar fierdere ferwurking en Simulator :: Run sil weromgean kontrôle. De simulaasje is kompleet.

Alles wat oerbliuwt is om nei josels op te romjen. Dit wurdt dien troch de globale funksje op te roppen Simulator :: Ferneatigje. Omdat de helper funksjes (of low-level ns-3 koade) waarden neamd, dy't organisearre sadat heakken waarden ynfoege yn de simulator te ferneatigjen alle foarwerpen dy't waarden makke. Jo hoege net ien fan dizze objekten sels te folgjen - alles wat jo hoege te dwaan wie belje Simulator :: Ferneatigje en útgean. It ns-3-systeem sil dit hurde wurk foar jo dwaan. De oerbleaune rigels fan ús earste ns-3-skript, first.cc, dogge krekt dat:

Simulator::Destroy ();
return 0;
}

Wannear sil de simulator stopje?

ns-3 is in diskrete evenemint (DE) simulator. Yn sa'n simulator wurdt elk barren ferbûn mei syn útfieringstiid, en de simulaasje giet troch mei it ferwurkjen fan eveneminten yn 'e folchoarder dy't se foarkomme as de simulaasje fuort giet. Eveneminten kinne feroarsaakje dat takomstige eveneminten wurde pland (bygelyks, in timer kin himsels opnij planne om it tellen te foltôgjen yn it folgjende ynterval).

Inisjele eveneminten wurde normaal inisjearre troch de entiteit, bygelyks IPv6 sil de ûntdekking fan tsjinsten op it netwurk planne, oanfragen fan buorlju, ensfh. De applikaasje plant it earste pakketferstjoerevenemint, ensfh. As in evenemint wurdt ferwurke, kin it generearje nul, ien, of mear eveneminten. As de simulaasje foarútgiet, komme eveneminten foar, einigje of meitsje nije. De simulaasje sil automatysk stopje as de barrenswachtrige leech is of in spesjaal barren wurdt ûntdutsen Ophâlde. Barren Ophâlde generearre troch de funksje Simulator :: Stopje (stoptiid).

Der is in typysk gefal dêr't Simulator :: Stop is perfoarst nedich te stopjen de simulaasje: as der sels-sustaining eveneminten. Sels ûnderhâldende (of werheljende) eveneminten binne eveneminten dy't altyd opnij ynsteld wurde. As gefolch hâlde se de wachtrige foar eveneminten altyd net leech. D'r binne in protte protokollen en modules mei werhelle eveneminten, bygelyks:

• FlowMonitor - periodike kontrôle foar ferlerne pakketten;

• RIPng - periodike útstjoering fan fernijings fan routingtabel;

• ensfh.

Yn sokke gefallen Simulator :: Stopje nedich om de simulaasje korrekt te stopjen. Derneist, as ns-3 yn emulaasjemodus is, wurdt de RealtimeSimulator brûkt om de simulaasjeklok te syngronisearje mei de masineklok, en Simulator :: Stopje nedich om it proses te stopjen.

In protte fan 'e simulaasjeprogramma's yn it learboek neame net Simulator :: Stopje eksplisyt, sûnt se beëinige automatysk as de wachtrige eveneminten wurde útput. Dizze programma's sille lykwols ek de Simulator :: Stop-oprop akseptearje. Bygelyks, de folgjende ekstra ferklearring yn it earste foarbyldprogramma soe in eksplisite stop op 11 sekonden planne:

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

It boppesteande sil it gedrach fan dit programma eins net feroarje, om't dizze bepaalde simulaasje fansels einiget nei 10 sekonden. Mar as jo de stoptiid yn 'e boppesteande ferklearring soene feroarje fan 11 sekonden nei 1 sekonde, soene jo fernimme dat de simulaasje stoppet foardat elke útfier op it skerm komt (om't de útfier nei sawat 2 sekonden fan simulaasjetiid komt).

It is wichtich om te neamen Simulator :: Stopje foardat jo neame Simulator :: Run; oars Simulator :: Run kin nea weromgean kontrôle nei de wichtichste programma foar in útfiere de halte!

4.2.9 Bouwe jo skript

Wy hawwe it meitsjen fan jo ienfâldige skripts triviaal makke. Alles wat jo hoege te dwaan is jo skript yn 'e scratch-map te pleatsen en it sil automatysk boud wurde as jo rinne Waf. Litte we it besykje. Gean werom nei de map op boppeste nivo en kopiearje foarbylden/tutorial/first.cc nei de katalogus skram

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

Bou no jo earste foarbyldskript mei waf:

$ ./waf

Jo moatte berjochten sjen dy't oanjaan dat jo earste foarbyld mei sukses makke is.

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)

No kinne jo it foarbyld útfiere (notysje dat as jo jo programma bouwe yn 'e scratch-map, dan moatte jo it útfiere fanút skram):

$ ./waf --run scratch/myfirst

Jo moatte ferlykbere útfier sjen:

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

Hjir kinne jo sjen dat it bousysteem kontrolearret dat it bestân boud is en it dan rint. Jo sjogge de komponint yngong op de echo client jout oan dat it stjoerde in inkele 1024-byte pakket nei echo server 10.1.1.2. Jo sjogge ek de logging-komponint op 'e echo-tsjinner om te sizzen dat it 1024 bytes krige fan 10.1.1.1. De echo-tsjinner spilet it pakket stil werom en jo kinne yn it logboek fan 'e echo-client sjen dat it syn pakket werom krige fan 'e tsjinner.

4.3 ns-3 Boarnekoade

No't jo guon fan 'e ns-3-helpers hawwe brûkt, kinne jo in pear fan' e boarnekoade besjen dy't dizze funksjonaliteit ymplementearret. De lêste koade kin besjoen wurde op ús webserver op de folgjende keppeling: https://gitlab.com/nsnam/ns-3-dev.git. Dêr sille jo de Mercurial gearfetting side sjen foar ús ns-3 ûntwikkelingsbeam. Oan 'e boppekant fan' e side sille jo ferskate keppelings sjen,

summary | shortlog | changelog | graph | tags | files

Gean fierder en selektearje de bestannen keppeling. Dit is hoe it boppeste nivo fan de measte fan ús repositories der útsjen sil:

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

Us foarbyldskripts binne yn 'e map foarbylden. As jo ​​op de foarbylden klikke, sille jo in list mei submappen sjen. Ien fan 'e bestannen yn' e submap tutorial - first.cc. As jo ​​klikke op earst.cc jo sille de koade sjen dy't jo krekt leard hawwe.

De boarnekoade is benammen te finen yn 'e map src. Jo kinne de boarnekoade besjen troch te klikken op de mapnamme of te klikken op de bestannen link rjochts fan de mapnamme. As jo ​​op de src-map klikke, krije jo in list mei src-submappen. As jo ​​dan op de kearnsubmap klikke, sille jo in list mei bestannen fine. It earste bestân dat jo sille sjen (op it momint fan it skriuwen fan dizze gids) is ôfbrekke.h. As jo ​​klikke op de keppeling ôfbrekke.h, Jo wurde stjoerd nei de boarne triem foar ôfbrekke.h, dy't nuttige makro's befettet foar it útgean fan skripts as abnormale omstannichheden wurde ûntdutsen. De boarnekoade foar de helpers dy't wy brûkten yn dit haadstik is te finen yn 'e map src/Applikaasjes/helper. Fiel jo frij om yn 'e mapbeam te snuffeljen om út te finen wat wêr is en de styl fan ns-3-programma's te begripen.

Boarne: www.habr.com

Add a comment