
4 Visió general del concepte
4.1 Abstraccions clau
4.1.1 Node
4.1.2 Aplicació
4.1.3 Canal
4.1.4 Dispositiu de xarxa
4.1.5 Ajudants topològics
4.2 Primer script ns-3
4.2.1 Codi normalitzat
4.2.2 Connectors
4.2.3 Espai de noms ns3
4.2.4 Registre
4.2.5 Funció principal
4.2.6 Ús d'assistents de topologia
4.2.7 Ús de l'aplicació
4.2.8 Simulador
4.2.9 Creació del vostre script
4.3 ns-3 Codi font
Capítol 4
Visió general del concepte
El primer que hem de fer abans de començar a aprendre o escriure codi ns-3 és explicar alguns conceptes bàsics i abstraccions del sistema. Gran part d'això pot semblar obvi per a alguns, però us recomanem que preneu-vos el temps per llegir aquesta secció per assegurar-vos que esteu començant amb una base sòlida.
4.1 Abstraccions clau
En aquesta secció, veurem alguns termes que s'utilitzen habitualment al web però que tenen un significat específic a ns-3.
4.1.1 Node
En l'argot d'Internet, un dispositiu informàtic que es connecta a una xarxa s'anomena host o, de vegades, sistema final. Com que ns-3 és un simulador de xarxa i no un simulador d'Internet, deliberadament no utilitzem el terme host, ja que està estretament relacionat amb Internet i els seus protocols. En canvi, utilitzem un terme més general, també utilitzat per altres simuladors, que s'origina en la teoria de grafs: node (node).
A ns-3, l'abstracció subjacent d'un dispositiu informàtic s'anomena node. Aquesta abstracció està representada en C++ per la classe Node. Classe NodeNode (node) proporciona mètodes per manipular representacions de dispositius informàtics en simulacions.
Has d'entendre Node com un ordinador al qual afegiu funcionalitats. Afegiràs coses com ara aplicacions, piles de protocols i targetes perifèriques amb controladors que permeten que l'ordinador faci un treball útil. Utilitzem el mateix model bàsic a ns-3.
4.1.2 Aplicació
En general, el programari informàtic es divideix en dues grans classes. El programari del sistema organitza diversos recursos informàtics com la memòria, els cicles del processador, el disc, la xarxa, etc. segons algun model informàtic. El programari del sistema normalment no utilitza aquests recursos per realitzar tasques que beneficien directament l'usuari. Normalment, un usuari executa una aplicació per aconseguir un objectiu específic, que obté i utilitza recursos controlats pel programari del sistema.
Sovint, la línia de separació entre el sistema i el programari d'aplicació es dibuixa en els canvis de nivell de privilegis que es produeixen en les trampes del sistema operatiu. ns-3 no té cap concepte real de sistema operatiu i, per tant, no té cap concepte de nivells de privilegis o trucades al sistema. Tanmateix, tenim una idea per a una aplicació. De la mateixa manera que en les aplicacions de programari del "món real" s'executen en ordinadors per realitzar tasques, les aplicacions ns-3 s'executen en nodes ns-3 per controlar simulacions en el món simulat.
A ns-3, l'abstracció bàsica per a un programa d'usuari que genera alguna activitat per al modelatge és una aplicació. Aquesta abstracció està representada en C++ per la classe Application. La classe Application proporciona mètodes per manipular les vistes de la nostra versió d'aplicacions a nivell d'usuari en simulacions. S'espera que els desenvolupadors especialitzin la classe Aplicació en un sentit de programació orientada a objectes per crear noves aplicacions. En aquest tutorial, utilitzarem les especialitzacions de la classe d'aplicació anomenada UdpEchoClientApplication и Aplicació UdpEchoServer. Com és d'esperar, aquestes aplicacions constitueixen un conjunt d'aplicacions client/servidor que s'utilitzen per generar i fer ressò de paquets de xarxa.
4.1.3 Canal
En el món real, podeu connectar un ordinador a una xarxa. Sovint, els mitjans sobre els quals es transmeten dades en aquestes xarxes s'anomenen canals. Quan connecteu un cable Ethernet a una presa de corrent, connecteu l'ordinador a un enllaç Ethernet. En el món ns-3 simulat, un node està connectat a un objecte que representa un canal de comunicació. Aquí, l'abstracció bàsica de la subxarxa de comunicació s'anomena canal i es representa en C++ per la classe Channel.
Classe CanalCanal proporciona mètodes per gestionar la interacció dels objectes de subxarxa i connectar-hi nodes. Els desenvolupadors també poden especialitzar els canals en un sentit de programació orientada a objectes. L'especialització del canal pot modelar una cosa tan simple com un cable. Un canal dedicat també pot modelar coses complexes com un gran commutador Ethernet o un espai tridimensional ple d'obstacles en el cas de les xarxes sense fil.
Farem servir versions especialitzades del canal en aquest tutorial anomenat CsmaChannelCsmaChannel, PointToPointChannelPointToPointChannel и WifiChannelWifiChannel. CsmaChannel, per exemple, modela una versió d'una subxarxa de comunicacions que implementa un entorn de comunicacions d'accés múltiple amb sentit del portador. Això ens ofereix una funcionalitat semblant a Ethernet.
4.1.4 Dispositiu de xarxa
Abans, si es volia connectar un ordinador a una xarxa, calia comprar un cable de xarxa específic i un dispositiu de maquinari anomenat (en terminologia de PC) targeta perifèrica que calia instal·lar a l'ordinador. Si una targeta perifèrica implementava algunes funcions de xarxa, s'anomenaven targetes d'interfície de xarxa o targetes de xarxa. Avui dia, la majoria d'ordinadors inclouen maquinari d'interfície de xarxa integrat i els usuaris no els veuen com a dispositius separats.
Сетевая карта не будет работать без программного драйвера, управляющего её оборудованием. В Unix (или Linux), часть периферийного оборудования классифицируется как device. Устройства управляются с помощью драйверов устройств (device drivers), а сетевые устройства (NIC) управляются с использованием драйверов сетевых устройств (controladors de dispositiu de xarxa) i s'anomenen col·lectivament dispositius de xarxa (dispositius de xarxa). В Unix и Linux вы обращаетесь к сетевым устройствам по таким именам, как например eth0.
A ns-3, l'abstracció del dispositiu de xarxa cobreix tant el controlador de programari com el maquinari que s'està modelant. En la simulació, un dispositiu de xarxa s'"instal·la" en un node per permetre que es comuniqui amb altres nodes a través de canals. Igual que un ordinador real, un node es pot connectar a diversos canals mitjançant diversos dispositius NetDevices.
L'abstracció de xarxa d'un dispositiu es representa en C++ per la classe NetDevice. Classe NetDevice proporciona mètodes per gestionar les connexions als objectes Node i Canal; i pot ser especialitzat pels desenvolupadors en el sentit de programació orientada a objectes. En aquest tutorial utilitzarem diverses versions especialitzades de NetDevice anomenades CsmaNetDevice, PointToPointNetDevice и Dispositiu WifiNet. Igual que un adaptador de xarxa Ethernet està dissenyat per funcionar amb una xarxa Ethernet, CsmaNetDevice dissenyat per treballar-hi CsmaChannel, PointToPointNetDevice dissenyat per treballar-hi PointToPointChannelI Dispositiu WifiNet - Dissenyat per treballar-hi WifiChannel.
4.1.5 Ajudants topològics
En una xarxa real, trobareu ordinadors host amb targetes de xarxa afegides (o integrades). A ns-3 diríem que veureu nodes amb NetDevices connectats. En una gran xarxa simulada, haureu d'organitzar connexions entre molts objectes Node, NetDevice и Canal.
Des de connectar NetDevices a nodes, NetDevices a enllaços, assignar adreces IP, etc. a ns-3 són una tasca comuna, per fer-ho el més fàcil possible, oferim els anomenats ajudants de topologia. Per exemple, per crear un NetDevice, heu de realitzar moltes operacions del nucli ns-3, afegir una adreça MAC, instal·lar el dispositiu de xarxa al Node, configurar la pila de protocols del node i connectar el NetDevice al canal. Es necessitarà encara més treball per connectar diversos dispositius a enllaços multipunt i després connectar les xarxes individuals a una xarxa d'Internetworks. Oferim objectes d'ajuda de topologia que combinen aquestes moltes operacions en un model fàcil d'utilitzar per a la vostra comoditat.
4.2 Primer script ns-3
Si heu instal·lat el sistema tal com s'ha suggerit anteriorment, tindreu la versió ns-3 en un directori anomenat repos al vostre directori d'inici. Vés al directori alliberar
Si no teniu aquest directori, vol dir que no heu especificat el directori de sortida en crear la versió de llançament de ns-3, creeu així:
$ ./waf configure —build-profile=release —out=build/release,
$ ./waf build
allà hauríeu de veure una estructura de directoris semblant a la següent:
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.pycVés al directori exemples/tutorial. Hauríeu de veure un fitxer que es troba allà anomenat primer.cc. Aquest és un script que crearà una connexió simple punt a punt entre dos nodes i transmetrà un paquet entre els nodes. Mirem aquest script línia per línia per fer-ho, obriu first.cc al vostre editor preferit.
4.2.1 Codi normalitzat
La primera línia del fitxer és la línia del mode editor Emacs. Explica a emacs les convencions de format (estil de codificació) que fem servir al nostre codi font.
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */Aquest és sempre un tema bastant controvertit, per la qual cosa hem de posar el rècord clar per treure'l del camí de seguida. El projecte ns-3, com la majoria dels grans projectes, ha adoptat un estil de codificació al qual s'ha de conformar tot el codi aportat. Si voleu aportar el vostre codi al projecte, finalment haureu d'ajustar-vos a l'estàndard de codificació ns-3, tal com es descriu al fitxer doc/codingstd.txt o es mostra a la pàgina web del projecte: .
Us recomanem que us acostumeu a l'aspecte del codi ns-3 i apliqueu aquest estàndard sempre que treballeu amb el nostre codi. Tot l'equip de desenvolupament i els col·laboradors van acceptar això després d'algunes queixes. La línia del mode emacs de dalt fa que sigui fàcil de formatar correctament si utilitzeu l'editor emacs.
El simulador ns-3 té llicència d'ús GNU General Public License. Veureu la capçalera legal GNU adequada a cada fitxer de distribució ns-3. Sovint veureu un avís de drets d'autor d'una de les institucions participants en el projecte ns-3 a sobre del text GPL i de l'autor, que es mostra a continuació.
/*
* 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 Connectors
El codi en si comença amb una sèrie de declaracions d'inclusió (incloure).
#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"Per ajudar els nostres usuaris de scripts d'alt nivell a fer front a la gran quantitat de fitxers de capçalera presents al sistema, els agrupem segons el seu ús en mòduls grans. Proporcionem un únic fitxer de capçalera que carregarà de forma recursiva tots els fitxers de capçalera utilitzats en un mòdul determinat. En lloc d'haver de cercar exactament quina capçalera necessiteu i possiblement obtenir la llista correcta de dependències, us oferim la possibilitat de descarregar un grup de fitxers amb gran granularitat. No és l'enfocament més eficient, però sens dubte fa que escriure guions sigui molt més fàcil.
Cadascun dels fitxers d'inclusió ns-3 es col·loca en un directori anomenat ns3 (subdirectori de compilació) per evitar conflictes de noms de fitxer durant el procés de compilació. Dossier ns3/core-module.h correspon al mòdul ns-3, que trobareu al directori src/core a la versió que heu instal·lat. A la llista d'aquest directori trobareu un gran nombre de fitxers de capçalera. Quan fas el muntatge, Waf col·loca els fitxers de capçalera públics al directori ns3 en un subdirectori construir/depurar
Si no teniu aquest directori, vol dir que no heu especificat el directori de sortida en crear la versió de llançament de ns-3, creeu així:
$ ./waf configure --build-profile=debug --out=build/debug
$ ./waf build
o
$ ./waf configure --build-profile=optimitzat --out=build/optimized
$ ./waf build
o construir/optimitzar, depenent de la vostra configuració. Waf també generarà automàticament un fitxer d'inclusió del mòdul per carregar tots els fitxers de capçalera públics. Com que, per descomptat, seguiu aquesta guia religiosament, ja ho heu fet
$ ./waf -d debug --enable-examples --enable-tests configureper configurar el projecte per executar compilacions de depuració que incloguin exemples i proves. Tu també ho has fet
$ ./wafper muntar el projecte. Així que ara quan mireu al directori ../../build/debug/ns3, aleshores hi trobareu, entre d'altres, els fitxers de capçalera dels quatre mòduls mostrats anteriorment. Podeu consultar el contingut d'aquests fitxers i trobar que inclouen tots els fitxers públics utilitzats pels mòduls corresponents.
4.2.3 Espai de noms ns3
Següent línia del guió primer.cc és una declaració d'espai de noms.
using namespace ns3;El projecte ns-3 s'implementa en un espai de noms C++ anomenat ns3. Això agrupa totes les declaracions relacionades amb ns-3 en un àmbit fora de l'espai de noms global, que esperem ajudarà amb la integració amb un altre codi. L'ús de l'operador C++ introdueix l'espai de noms ns-3 a la regió declarativa (global) actual. Aquesta és una manera fantàstica de dir que després d'aquesta declaració, no haureu d'escriure l'operador de permís ns3::scope abans de tot el vostre codi ns-3 per utilitzar-lo. Si no esteu familiaritzat amb els espais de noms, consulteu gairebé qualsevol llibre de text de C++ i compareu l'espai de noms ns3 utilitzant l'espai de noms i la declaració std. using namespace std; en exemples de treball amb l'operador de sortida cout i rierols.
4.2.4 Registre
La següent línia del guió és,
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");Utilitzarem aquesta declaració com un lloc convenient per parlar del nostre sistema de documentació Oxigen. Si mireu el lloc web del projecte ns-3, trobareu un enllaç de documentació a la barra de navegació. Si feu clic a aquest enllaç se us dirigirà a la nostra pàgina de documentació. Hi ha un enllaç "Darrera versió" que us portarà a la documentació de la darrera versió estable de ns-3. Si seleccioneu l'enllaç "Documentació de l'API", se us dirigirà a la pàgina de documentació de l'API ns-3.
A la part esquerra de la pàgina trobareu una representació gràfica de l'estructura de la documentació. Un bon lloc per començar és el "llibre" dels mòduls ns-3 a l'arbre de navegació ns-3. Si reveles mòduls, veureu una llista de documentació dels mòduls ns-3. Com s'ha comentat anteriorment, el concepte de mòdul aquí està directament relacionat amb els fitxers inclosos al mòdul anterior. El subsistema de registre ns-3 es tracta a la secció Ús del mòdul de registre, així que hi tornarem més endavant en aquest tutorial, però podeu obtenir informació sobre la declaració anterior mirant el mòdul Nuclii després obrir el llibre Eines de depuraciói després seleccionant la pàgina Inici de sessió. Fer clic a Inici de sessió.
Ara hauríeu de revisar la documentació Oxigen per al mòdul Inici de sessió. A la llista de macros de la part superior de la pàgina, veureu una entrada per a NS_LOG_COMPONENT_DEFINE. Abans de fer clic a l'enllaç, assegureu-vos de mirar la "Descripció detallada" del mòdul de registre per entendre com funciona en general. Per fer-ho, podeu desplaçar-vos cap avall o seleccionar "Més..." a sota del gràfic.
Un cop tingueu una idea general del que està passant, aneu endavant i consulteu la documentació del NS_LOG_COMPONENT_DEFINE específic. No duplicaré la documentació aquí, però per resumir, aquesta línia declara un component de registre anomenat FirstScriptExample, que us permet activar o desactivar el registre de missatges de la consola per referència a un nom.
4.2.5 Funció principal
A les següents línies del guió veureu,
int
main (int argc, char *argv[])
{ Això és simplement una declaració de la funció principal del vostre programa (script). Com amb qualsevol programa C++, cal definir una funció principal, aquesta s'executa primer. Aquí no hi ha res especial. El vostre script ns-3 és només un programa C++. La línia següent estableix la resolució de temps en 1 nanosegon, que és el valor predeterminat:
Time::SetResolution (Time::NS);La resolució de temps, o simplement la resolució, és el valor de temps més petit que es pot utilitzar (la diferència representable més petita entre dos temps). Podeu canviar la resolució exactament una vegada. El mecanisme que proporciona aquesta flexibilitat consumeix memòria, de manera que un cop s'estableix explícitament la resolució, alliberem la memòria, evitant noves actualitzacions. (Si no configureu la resolució de manera explícita, serà d'un nanosegon per defecte i la memòria s'alliberarà quan comenci la simulació.)
Les dues línies d'script següents s'utilitzen per habilitar dos components de registre integrats a les aplicacions EchoClient и EchoServer:
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);Si llegiu la documentació del component Logging, veureu que hi ha diversos nivells de registre/granularitat que podeu activar a cada component. Aquestes dues línies de codi permeten el registre de depuració al nivell INFO per als clients i servidors d'eco. En aquest nivell, l'aplicació imprimirà missatges a mesura que envia i rep paquets durant la simulació.
Ara passarem al negoci de crear la topologia i executar la simulació. Utilitzem objectes auxiliars de topologia per fer que aquest treball sigui el més fàcil possible.
4.2.6 Ús d'assistents de topologia
Les dues línies de codi següents del nostre script crearan realment els objectes Node ns-3 que representaran els ordinadors de la simulació.
NodeContainer nodes;
nodes.Create (2);Abans de continuar, busquem la documentació de la classe NodeContainer. Una altra manera d'arribar a la documentació d'una classe determinada és a través de la pestanya classes a les pàgines Oxigen. Si ja teniu Doxygen obert, simplement desplaceu-vos fins a la part superior de la pàgina i seleccioneu la pestanya Classes. Hauríeu de veure un nou conjunt de pestanyes, una de les quals és una llista de classes. Sota aquesta pestanya veureu una llista de totes les classes ns-3. Desplaceu-vos cap avall fins a ns3::NodeContainer. Quan trobeu una classe, seleccioneu-la per anar a la documentació de la classe.
Com recordem, una de les nostres abstraccions clau és el node. Representa l'ordinador al qual afegirem coses com ara piles de protocols, aplicacions i targetes perifèriques. Auxiliar de topologia NodeContainer proporciona una manera còmoda de crear, gestionar i accedir a qualsevol objecte Node, que creem per executar la simulació. La primera línia anterior simplement declara NodeContainer, que anomenem nodes. La segona línia crida al mètode Create a l'objecte nodes i demana al contenidor que creï dos nodes. Tal com es descriu a Oxigen, el contenidor demana al sistema ns-3 que creï dos objectes Node i emmagatzema els punters a aquests objectes internament.
Els nodes creats a l'script encara no fan res. El següent pas per construir la topologia és connectar els nostres nodes a la xarxa. La forma més senzilla de xarxa que admetem és una connexió punt a punt entre dos nodes. Ara crearem aquesta connexió.
PointToPointHelper
Creem una connexió punt a punt mitjançant un patró familiar, utilitzant un objecte auxiliar de topologia per fer el treball de baix nivell necessari per a la connexió. Recordem que les nostres dues abstraccions clau NetDevice и Canal. En el món real, aquests termes corresponen aproximadament a targetes perifèriques i cables de xarxa. Normalment, aquestes dues coses estan estretament relacionades entre si, i ningú pot comptar amb compartir, per exemple, dispositius Ethernet a través d'un canal sense fil. Els nostres ajudants de topologia segueixen aquesta estreta relació i, per tant, utilitzareu un únic objecte en aquest escenari PointToPointHelper per configurar i connectar objectes ns-3 PointToPointNetDevice и PointToPointChannel. Les tres línies següents del guió:
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));Primera línia,
PointToPointHelper pointToPoint;crea una instància d'un objecte a la pila PointToPointHelper. Des d'un punt de vista de primer nivell la línia següent,
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));diu a l'objecte PointToPointHelper utilitzeu el valor "5 Mbit/s" (cinc megabits per segon) com a "Velocitat de dades».
Des d'un punt de vista més concret, la cadena "DataRate" correspon al que anomenem atribut PointToPointNetDevice. Si mireu Oxigen per a classe ns3::PointToPointNetDevice i a la documentació del mètode GetTypeId trobareu una llista d'atributs definits per al dispositiu. Entre ells hi haurà l'atribut “Velocitat de dades" La majoria dels objectes ns-3 visibles per l'usuari tenen llistes d'atributs similars. Utilitzem aquest mecanisme per configurar fàcilment la simulació sense recompilació, com veureu a la següent secció.
Semblant a "Velocitat de dades" a PointToPointNetDevice, trobareu l'atribut "Delay" associat al PointToPointChannel. La línia final
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));diu PointToPointHelper utilitzeu el valor "2 ms" (dos mil·lisegons) com a valor de retard de propagació per a l'enllaç punt a punt que es crea posteriorment.
NetDeviceContainer
De moment ho tenim al guió NodeContainer, que conté dos nodes. Tenim PointToPointHelper, que està preparat per crear objectes PointToPointNetDevices i connectar-los mitjançant un objecte PointToPointChannel. De la mateixa manera que hem utilitzat l'objecte auxiliar de topologia NodeContainer per crear nodes, preguntarem PointToPointHelper realitzar per nosaltres treballs relacionats amb la creació, configuració i instal·lació dels nostres dispositius. Necessitem una llista de tots els objectes creats NetDevice, així que fem servir NetDeviceContainer per emmagatzemar-los de la mateixa manera que hem utilitzat NodeContainer per emmagatzemar els nodes que hem creat. Les dues línies de codi següents,
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);Configuració completa del dispositiu i canal. La primera línia declara el contenidor del dispositiu esmentat anteriorment i la segona fa el treball principal. Mètode install objecte PointToPointHelper pren NodeContainer com a paràmetre. Dins NetDeviceContainer per a cada node situat a NodeContainer es crea (per a la comunicació punt a punt n'hi ha d'haver exactament dos) PointToPointNetDevice es crea i es desa al contenidor del dispositiu. PointToPointChannel es crea i s'hi adjunten dos PointToPointNetDevices. Després de crear objectes, els atributs s'emmagatzemen a PointToPointHelper, s'utilitzen per inicialitzar els atributs corresponents als objectes creats.
Després de fer una trucada pointToPoint.Install (nodes) tindrem dos nodes, cadascun amb un dispositiu de xarxa punt a punt instal·lat i un enllaç punt a punt entre ells. Tots dos dispositius estaran configurats per transmetre dades a una velocitat de cinc megabits per segon amb un retard de transmissió de dos mil·lisegons sobre el canal.
InternetStackHelper
Ara tenim nodes i dispositius configurats, però els nostres nodes no tenen piles de protocol instal·lades. Les dues línies de codi següents s'encarregaran d'això.
InternetStackHelper stack;
stack.Install (nodes);InternetStackHelper - és un ajudant de topologia per a piles d'Internet, similar a PointToPointHelper per a dispositius de xarxa punt a punt. Mètode install pren NodeContainer com a paràmetre. Quan s'executa, instal·larà la pila d'Internet (TCP, UDP, IP, etc.) a cada node de contenidor.
IPv4AddressHelper
Aleshores hem d'associar els nostres dispositius amb adreces IP. Oferim un assistent de topologia per gestionar l'assignació d'adreces IP. L'única API visible per a l'usuari és configurar l'adreça IP base i la màscara de xarxa que s'utilitzaran quan es fa la distribució d'adreces real (això es fa a un nivell inferior dins de l'ajudant). Les dues línies de codi següents del nostre script d'exemple primer.cc,
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");declareu l'objecte auxiliar d'adreces i digueu-li que hauria de començar a assignar adreces IP des de la xarxa 10.1.1.0, utilitzant la màscara de bits 255.255.255.0 per determinar-ho. Per defecte, les adreces assignades començaran a la una i augmentaran monòtonament, de manera que la primera adreça assignada des d'aquesta base serà 10.1.1.1, després 10.1.1.2, etc. En realitat, a un nivell baix, el sistema ns-3 recorda totes les adreces IP assignades i genera un error fatal si accidentalment es crea una situació en què es genera la mateixa adreça dues vegades (per cert, aquest error és difícil de depurar).
La següent línia de codi,
Ipv4InterfaceContainer interfaces = address.Assign (devices);realitza l'assignació real de l'adreça. A ns-3 establim una connexió entre una adreça IP i un dispositiu que utilitza l'objecte Interfície IPv4. De la mateixa manera que de vegades necessitem una llista de dispositius de xarxa creats per l'assistent per a un ús posterior, de vegades necessitem una llista d'objectes Interfície IPv4. IPv4InterfaceContainer proporciona aquesta funcionalitat.
Vam construir una xarxa punt a punt, amb piles instal·lades i adreces IP assignades. Ara necessitem aplicacions a cada node per generar trànsit.
4.2.7 Ús de l'aplicació
Una altra de les abstraccions principals del sistema ns-3 és Sol·licitud (aplicació). En aquest escenari estem utilitzant dues especialitzacions de classe base Sol·licitud ns-3 cridat Aplicació UdpEchoServer и UdpEchoClientApplication. Com en casos anteriors, utilitzem objectes auxiliars per configurar i gestionar els objectes base. Aquí fem servir UdpEchoServerHelper и UdpEchoClientHelper objectes per fer-nos la vida més fàcil.
UdpEchoServerHelper
Les següents línies de codi del nostre script d'exemple first.cc s'utilitzen per configurar una aplicació de servidor d'eco UDP en un dels nodes que hem creat anteriorment.
UdpEchoServerHelper echoServer (9);
ApplicationContainer serverApps = echoServer.Install (nodes.Get (1));
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));Es crea la primera línia de codi del fragment anterior UdpEchoServerHelper. Com és habitual, aquesta no és una aplicació en si, és un objecte que ens ajuda a crear aplicacions reals. Una de les nostres convencions és passar els atributs necessaris al constructor de l'objecte auxiliar. En aquest cas, l'ajudant no pot fer res útil tret que se li indiqui el número de port on el servidor escoltarà els paquets, aquest número també ha de ser conegut pel client. En aquest cas, passem el número de port al constructor auxiliar. El constructor, al seu torn, simplement ho fa SetAttribute amb el valor passat. Més tard, si ho desitja, podeu utilitzar SetAttribute per establir un valor diferent per a l'atribut Port.
Com molts altres objectes auxiliars, l'objecte UdpEchoServerHelper té un mètode install. L'execució d'aquest mètode de manera efectiva crea una aplicació bàsica de servidor d'eco i l'enllaça a l'amfitrió. Curiosament, el mètode install pren NodeContainer com a paràmetre igual que els altres install mètodes que hem vist.
La conversió implícita de C++ que treballa aquí pren el resultat del mètode node.Get(1) (que retorna un punter intel·ligent a l'objecte node - Ptr ) i l'utilitza al constructor per a l'objecte anònim NodeContainerque després es passa al mètode install. Si no podeu determinar al codi C++ quina signatura del mètode es compila i s'executa, mireu entre les conversions implícites.
Ara ho veiem echoServer.Install a punt d'instal·lar l'aplicació Aplicació UdpEchoServer on es troba a NodeContainerque fem servir per gestionar els nostres nodes, node amb índex 1. Mètode install retornarà un contenidor que conté punters a totes les aplicacions (en aquest cas, una, ja que hem passat un fitxer anònim NodeContainer, que conté un node) creat per l'ajudant.
Les aplicacions han d'especificar quan començar a generar trànsit "començar" i és possible que hagi d'especificar addicionalment un moment en què s'ha d'aturar "Atura". Oferim les dues opcions. Aquests horaris s'estableixen mitjançant els mètodes Contenidor d'aplicacions Començar и Stop. Aquests mètodes accepten paràmetres de tipus Temps. En aquest cas, utilitzem una seqüència explícita de conversions de C++ per prendre C++ doble 1.0 i convertiu-lo en un objecte de temps tns-3 que utilitza l'objecte Seconds per convertir-lo en segons. Recordeu que l'autor del model pot controlar les regles de conversió i que C++ té les seves pròpies regles, de manera que no sempre podeu comptar amb la conversió dels paràmetres de la manera que esperàveu. Dues línies
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));farà que l'aplicació del servidor d'eco s'iniciï (s'encengui automàticament) un segon després que s'iniciï la simulació i s'aturi (s'apagui) després de deu segons de la simulació. Com que hem declarat un esdeveniment de simulació (esdeveniment d'aturada d'aplicació), que s'executarà en deu segons, es simularan almenys deu segons de funcionament de la xarxa.
UdpEchoClientHelper
Aplicació client trobo configurat d'una manera gairebé semblant al servidor. Hi ha un objecte base UdpEchoClientApplication, que està controlada
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));;Tanmateix, per al client echo hem d'establir cinc atributs diferents. Els dos primers atributs s'estableixen en el moment de la creació UdpEchoClientHelper. Passem paràmetres que s'utilitzen (dins de l'ajudant) per establir els atributs "Adreça remota" и "Port remot" d'acord amb el nostre acord per passar els paràmetres necessaris al constructor auxiliar.
Recordem que vam fer servir IPv4InterfaceContainer per fer un seguiment de les adreces IP que hem assignat als nostres dispositius. La interfície nul·la del contenidor d'interfícies correspondrà a l'adreça IP del node nul del contenidor de nodes. La primera interfície del contenidor d'interfícies correspon a l'adreça IP del primer node del contenidor de nodes. Així, a la primera línia de codi (a dalt), creem un ajudant i li diem que l'adreça remota del client serà l'adreça IP assignada al node on es troba el servidor. També diem que hem d'organitzar que els paquets s'enviïn al port nou.
L'atribut "MaxPackets" indica al client el nombre màxim de paquets que podem enviar durant la simulació. L'atribut "Interval" indica al client quant de temps ha d'esperar entre paquets, i l'atribut "PacketSize" indica al client quant de gran hauria de ser la càrrega útil del paquet. Amb aquesta combinació d'atributs diem al client que enviï un sol paquet de 1024 bytes.
Igual que amb el servidor d'eco, establim els atributs del client d'eco Començar и Stop, però aquí iniciem el client un segon després d'encendre el servidor (dos segons després de l'inici de la simulació).
4.2.8 Simulador
En aquest punt hem d'executar la simulació. Això es fa mitjançant la funció global Simulador::Run.
Simulator::Run ();Quan abans anomenàvem mètodes,
serverApps.Start (Seconds (1.0));
serverApps.Stop (Seconds (10.0));
...
clientApps.Start (Seconds (2.0));
clientApps.Stop (Seconds (10.0));De fet, vam programar esdeveniments al simulador a 1,0 segons, 2,0 segons i dos esdeveniments a 10,0 segons. Després de la trucada Simulador::Run, el sistema començarà a veure la llista d'esdeveniments programats ia executar-los. Primer dispararà un esdeveniment després d'1,0 segons, que activarà l'aplicació del servidor d'eco (aquest esdeveniment pot programar molts altres esdeveniments). A continuació, dispararà un esdeveniment programat a t=2,0 segons que iniciarà l'aplicació client d'eco. Un cop més, aquest esdeveniment pot tenir molts més esdeveniments planificats. La implementació del client d'eco de l'esdeveniment d'inici començarà la fase de transferència de dades de la simulació enviant un paquet al servidor.
L'acte d'enviar un paquet al servidor desencadenarà una cadena d'esdeveniments que es programaran automàticament entre bastidors i que implementarà la mecànica d'enviament d'un paquet d'eco segons els paràmetres de temporització que hem establert a l'script.
Com a resultat, com que estem enviant només un paquet (recordeu, l'atribut MaxPackets s'ha establert en un), la cadena d'esdeveniments iniciada per aquest únic ping de client finalitzarà i la simulació passarà al mode d'espera. Un cop això passi, la resta d'esdeveniments programats seran els esdeveniments Stop per al servidor i el client. Quan s'executen aquests esdeveniments, no hi haurà cap esdeveniment per a un processament posterior i Simulador::Run tornarà el control. La simulació està completa.
Només queda netejar-se. Això es fa cridant a la funció global Simulador::Destrueix. Perquè es van cridar les funcions d'ajuda (o codi ns-3 de baix nivell), que s'organitzen de manera que s'insereixen ganxos al simulador per destruir tots els objectes que es van crear. No calia fer un seguiment de cap d'aquests objectes tu mateix; tot el que havies de fer era trucar Simulador::Destrueix i sortir. El sistema ns-3 farà aquest treball dur per vostè. Les línies restants del nostre primer script ns-3, first.cc, fan exactament això:
Simulator::Destroy ();
return 0;
}Quan s'aturarà el simulador?
ns-3 és un simulador d'esdeveniments discrets (DE). En aquest simulador, cada esdeveniment s'associa amb el seu temps d'execució, i la simulació continua processant els esdeveniments en l'ordre en què es produeixen a mesura que avança la simulació. Els esdeveniments poden fer que es programin esdeveniments futurs (per exemple, un temporitzador es pot reprogramar per acabar de comptar en el següent interval).
Els esdeveniments inicials solen ser iniciats per l'entitat, per exemple IPv6 programarà la descoberta de serveis a la xarxa, peticions de veïns, etc. L'aplicació programa el primer esdeveniment d'enviament de paquets, i així successivament. Quan es processa un esdeveniment, pot generar zero, un o més esdeveniments. A mesura que avança la simulació, es produeixen esdeveniments, ja siguin acabant o creant-ne de nous. La simulació s'aturarà automàticament si la cua d'esdeveniments està buida o es detecta un esdeveniment especial Stop. Esdeveniment Stop generada per la funció Simulador::Stop (temps de parada).
Hi ha un cas típic en què Simulator::Stop és absolutament necessari per aturar la simulació: quan hi ha esdeveniments autosostenibles. Els esdeveniments autosostenibles (o repetitius) són esdeveniments que sempre es reprograman. Com a conseqüència, sempre mantenen la cua d'esdeveniments no buida. Hi ha molts protocols i mòduls que contenen esdeveniments repetitius, per exemple:
• FlowMonitor: comprovació periòdica de paquets perduts;
• RIPng: emissió periòdica d'actualitzacions de la taula d'encaminament;
• etc.
En aquests casos Simulador::Stop necessari per aturar correctament la simulació. A més, quan ns-3 està en mode d'emulació, RealtimeSimulator s'utilitza per sincronitzar el rellotge de simulació amb el rellotge de la màquina i Simulador::Stop necessari per aturar el procés.
Molts dels programes de simulació del llibre de text no criden Simulador::Stop explícitament, ja que finalitzen automàticament quan s'esgoten els esdeveniments a la cua. Tanmateix, aquests programes també acceptaran la trucada Simulator::Stop. Per exemple, la següent instrucció addicional del primer programa d'exemple programaria una aturada explícita als 11 segons:
+ Simulator::Stop (Seconds (11.0));
Simulator::Run ();
Simulator::Destroy ();
return 0;
}L'anterior no canviarà realment el comportament d'aquest programa, ja que aquesta simulació en particular acaba naturalment després de 10 segons. Però si canvieu el temps d'aturada a la declaració anterior d'11 segons a 1 segon, notareu que la simulació s'atura abans que qualsevol sortida arribi a la pantalla (ja que la sortida es produeix després d'uns 2 segons de temps de simulació).
És important trucar a Simulator::Stop abans de trucar a Simulator::Run; en cas contrari, Simulator::Run no pot tornar mai el control al programa principal per executar l'aturada!
4.2.9 Creació del vostre script
Hem fet que la creació dels vostres scripts senzills sigui trivial. Tot el que heu de fer és posar el vostre script al directori scratch i es generarà automàticament si l'executeu Waf. Anem a provar. Torneu al directori de nivell superior i copieu-lo exemples/tutorial/first.cc al catàleg ratllar
$ cd ../..
$ cp examples/tutorial/first.cc scratch/myfirst.ccAra creeu el vostre primer script de mostra amb waf:
$ ./wafHauríeu de veure missatges que indiquen que el vostre primer exemple s'ha creat correctament.
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)Ara podeu executar l'exemple (tingueu en compte que si creeu el vostre programa al directori scratch, haureu d'executar-lo des de ratllar):
$ ./waf --run scratch/myfirstHauríeu de veure una sortida similar:
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.2Aquí podeu veure que el sistema de compilació verifica que el fitxer s'ha creat i després l'executa. Veu que l'entrada del component al client echo indica que va enviar un sol paquet de 1024 bytes al servidor d'eco 10.1.1.2. També veieu el component de registre al servidor d'eco per dir que va rebre 1024 bytes de 10.1.1.1. El servidor d'eco reprodueix el paquet en silenci i podeu veure al registre del client d'eco que ha rebut el paquet del servidor.
4.3 ns-3 Codi font
Ara que heu utilitzat alguns dels ajudants ns-3, podeu fer una ullada a alguns del codi font que implementa aquesta funcionalitat. L'últim codi es pot veure al nostre servidor web al següent enllaç: . Allà veureu la pàgina de resum de Mercurial per al nostre arbre de desenvolupament ns-3. A la part superior de la pàgina veureu diversos enllaços,
summary | shortlog | changelog | graph | tags | filesAneu endavant i seleccioneu l'enllaç dels fitxers. Així serà el nivell superior de la majoria dels nostres repositoris:
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 | annotateEls nostres scripts d'exemple es troben al directori exemples. Si feu clic als exemples veureu una llista de subdirectoris. Un dels fitxers del subdirectori tutorial - first.cc. Si feu clic a primer.cc veureu el codi que acabeu d'aprendre.
El codi font es troba principalment al directori src. Podeu veure el codi font fent clic al nom del directori o fent clic a l'enllaç dels fitxers a la dreta del nom del directori. Si feu clic al directori src, obtindreu una llista de subdirectoris src. Si feu clic al subdirectori principal, trobareu una llista de fitxers. El primer fitxer que veureu (en el moment d'escriure aquesta guia) és avortar.h. Si feu clic a l'enllaç avortar.h, se us enviarà al fitxer font per avortar.h, que conté macros útils per sortir dels scripts si es detecten condicions anormals. El codi font dels ajudants que hem utilitzat en aquest capítol es pot trobar al directori src/Aplicacions/helper. No dubteu a fer una ullada a l'arbre de directoris per esbrinar què és on i entendre l'estil dels programes ns-3.
Font: www.habr.com
