
5 Configuració
5.1 Ús del mòdul de registre
5.1.1 Visió general del registre
5.1.2 Habilita el registre
5.1.3 Afegir registre al vostre codi
5.2 Ús d'arguments de línia d'ordres
5.2.1 Anulació dels valors d'atribut predeterminats
5.2.2 Capturar les vostres pròpies ordres
5.3 Ús del sistema de traçat
5.3.1 Traçat ASCII
Anàlisi de traces ASCII
5.3.2 Traça PCAP
Capítol 5
ajust
5.1 Ús del mòdul de registre
Ja vam mirar breument el mòdul de registre ns-3 mirant l'script primer.cc. En aquest capítol, analitzarem més de prop els possibles usos del subsistema de registre.
5.1.1 Visió general del registre
Molts sistemes grans admeten algun tipus de funció de registre de missatges, i ns-3 no és una excepció. En alguns casos, només s'escriuen missatges d'error a la "consola de l'operador" (que normalment és stderr en sistemes basats en Unix). En altres sistemes, es poden mostrar missatges d'advertència així com informació més detallada. En alguns casos, s'utilitzen eines de registre per generar missatges de depuració que poden desenfocar ràpidament la sortida.
El subHRD utilitzat a ns-3 assumeix que tots aquests nivells de contingut d'informació són útils i oferim un enfocament selectiu i en capes per al registre de missatges. El registre es pot desactivar completament, activar-se per component o globalment. Amb aquesta finalitat, s'utilitzen nivells ajustables de contingut d'informació. El mòdul de registre ns-3 proporciona una manera relativament senzilla d'obtenir informació útil de la vostra simulació.
Hauríeu d'entendre que proporcionem un mecanisme de propòsit general - traça - per extreure dades dels vostres models, que hauria de ser la sortida preferida per a les simulacions (per obtenir més informació sobre el nostre sistema de traça, vegeu la secció del tutorial 5.3). El registre hauria de ser el mètode preferit per obtenir informació de depuració, avisos, missatges d'error o per enviar ràpidament missatges dels vostres scripts o models en qualsevol moment.
Actualment, el sistema defineix set nivells (tipus) de missatges de registre en ordre creixent de contingut d'informació.
- LOG_ERROR - missatges d'error de registre (macro relacionada: NS_LOG_ERROR);
- LOG_WARN: registre dels missatges d'advertència (macro relacionada: NS_LOG_WARN);
- LOG_DEBUG: registre missatges especials de depuració relativament rars (macro relacionada: NS_LOG_DEBUG);
- LOG_INFO - registre de missatges d'informació sobre el progrés del programa (macro relacionada: NS_LOG_INFO);
- LOG_FUNCTION: registra missatges que descriuen cada funció cridada (dues macros relacionades: NS_LOG_FUNCTION, utilitzada per a funcions membre, i NS_LOG_FUNCTION_NOARGS, utilitzada per a funcions estàtiques);
- LOG_LOGIC - missatges de registre que descriuen el flux lògic dins d'una funció (macro relacionada: NS_LOG_LOGIC);
- LOG_ALL: registra tot el que s'ha esmentat anteriorment (no hi ha macro associada).
Per a cada tipus (LOG_TYPE) també hi ha un LOG_LEVEL_TYPE que, si s'utilitza, permet registrar tots els nivells superiors a més del seu propi nivell. (Com a conseqüència, LOG_ERROR i LOG_LEVEL_ERROR, i LOG_ALL i LOG_LEVEL_ALL són funcionalment equivalents.) Per exemple, l'habilitació de LOG_INFO només permetrà els missatges proporcionats per la macro NS_LOG_INFO, mentre que l'habilitació de LOG_LEVEL_INFO també inclourà els missatges proporcionats per les macros NS_LOGNS_DE_W_GARN i ERROR.
També oferim una macro de registre incondicional que sempre es mostra, independentment del nivell de registre o del component de selecció.
- NS_LOG_UNCOND - Registre incondicional del missatge associat (sense nivell de registre associat).
Cada nivell es pot consultar de manera individual o acumulada. El registre es pot configurar mitjançant la variable d'entorn sh NS_LOG o registrant una trucada de funció del sistema. Com s'ha mostrat anteriorment, el sistema de registre té documentació de Doxygen i ara és un bon moment per revisar-la si encara no ho heu fet.
Ara que heu llegit la documentació amb molt de detall, utilitzem aquest coneixement per obtenir informació interessant de l'script d'exemple scratch/myfirst.ccque ja has compilat.
5.1.2 Habilita el registre
Utilitzem la variable d'entorn NS_LOG per executar alguns registres més, però primer, només per orientar-vos, executeu l'últim script com vau fer abans,
$ ./waf --run scratch/myfirstHauríeu de veure la sortida familiar del primer programa d'exemple ns-3
$ 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.413s)
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.2Resulta que els missatges "enviats" i "rebuts" que veieu més amunt són en realitat missatges registrats de UdpEchoClientApplication и Aplicació UdpEchoServer. Per exemple, podem demanar a l'aplicació client que imprimeixi informació addicional establint el seu nivell de registre mitjançant la variable d'entorn NS_LOG.
A partir d'ara, suposaré que esteu utilitzant un shell semblant a sh que utilitza la sintaxi "VARIABLE=valor". Si utilitzeu un intèrpret d'ordres semblant a csh, haureu de convertir els meus exemples a la sintaxi "setenv variable value" requerida per aquests intèrprets d'ordre.
Actualment, l'aplicació client d'eco UDP respon a la següent línia de codi scratch/myfirst.cc,
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);Habilita el nivell de registre LOG_LEVEL_INFO. Quan passem un indicador de nivell de registre, en realitat activem aquest nivell i tots els nivells inferiors. En aquest cas, hem habilitat NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN i NS_LOG_ERROR. Podem augmentar el nivell de registre i obtenir més informació, sense canvis d'script i recompilació, establint la variable d'entorn NS_LOG de la següent manera:
$ export NS_LOG=UdpEchoClientApplication=level_allAixí que establim la variable de l'intèrpret d'ordres sh NS_LOG al valor següent,
UdpEchoClientApplication=level_allEl costat esquerre de l'assignació és el nom del component registrat que volem configurar, i el costat dret és la bandera que volem aplicar-hi. En aquest cas, habilitarem tots els nivells de depuració de l'aplicació. Si executeu l'script amb NS_LOG configurat d'aquesta manera, el sistema de registre ns-3 acceptarà els canvis i hauríeu de veure la sortida següent:
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.404s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()La informació addicional de depuració proporcionada per l'aplicació es troba ara al nivell NS_LOG_FUNCTION. Mostra cada instància d'una trucada de funció durant l'execució de l'script. Com a regla general, a les funcions del mètode és preferible utilitzar (com a mínim)NS_LOG_FUNCTION (this). Ús NS_LOG_FUNCTION_NOARGS ()
només en funcions estàtiques. Tanmateix, tingueu en compte que el sistema ns-3 no és necessari per admetre cap funcionalitat de registre. La decisió sobre quanta informació es registra es deixa al desenvolupador del model individual. En el cas de les aplicacions d'eco, hi ha disponible una gran quantitat de sortida de registre.
Ara podeu veure un registre de les trucades de funcions que l'aplicació ha fet. Si us fixeu bé, notareu un dos punts entre la línia UdpEchoClientApplication i el nom del mètode, on podríeu esperar veure l'operador d'àmbit C++ (: :). Això és intencionat.
Aquest no és realment el nom de la classe, sinó el nom del component de registre. Quan hi ha una coincidència entre un fitxer font i una classe, normalment és el nom de la classe, però hauríeu d'adonar-vos que en realitat no és el nom de la classe, i hi ha dos punts únics en lloc de dos punts dobles. Aquesta és una manera d'ajudar-vos a separar conceptualment el nom del bean de registre del nom de la classe d'una manera relativament subtil.
Tanmateix, en alguns casos pot ser difícil determinar quin mètode està generant realment el missatge de registre. Si mireu el text anterior, potser us preguntareu on és la línia "Received 1024 bytes from 10.1.1.2" Podeu resoldre aquest problema establint el nivell prefix_func a la variable d'entorn NS_LOG. Proveu el següent:
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'Tingueu en compte que les cometes són necessàries perquè la barra vertical que fem servir per indicar l'operació OR també és un connector de canonada Unix. Ara, si executeu l'script, veureu que el sistema de registre assegura que tots els missatges d'un registre determinat tenen el prefix del nom del component.
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.417s)
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()Ara podeu veure que tots els missatges procedents de l'aplicació client d'eco UDP s'identifiquen com a tal. Missatge "Received 1024 bytes from 10.1.1.2" ara s'identifica clarament com a provinent de l'aplicació client echo. El missatge restant ha de provenir de l'aplicació del servidor d'eco UDP. Podem habilitar aquest component introduint una llista de components separats per dos punts a la variable d'entorn NS_LOG.
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
UdpEchoServerApplication=level_all|prefix_func'Advertència: al text d'exemple anterior, haureu d'eliminar el caràcter de nova línia després dels dos punts (:), que s'utilitza per formatar el document. Ara, si executeu l'script, veureu tots els missatges de registre de les aplicacions d'eco client i servidor. Podeu veure que això pot ser molt útil a l'hora de depurar.
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.406s)
UdpEchoServerApplication:UdpEchoServer()
UdpEchoClientApplication:UdpEchoClient()
UdpEchoClientApplication:SetDataSize(1024)
UdpEchoServerApplication:StartApplication()
UdpEchoClientApplication:StartApplication()
UdpEchoClientApplication:ScheduleTransmit()
UdpEchoClientApplication:Send()
UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
UdpEchoServerApplication:HandleRead(): Echoing packet
UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
UdpEchoServerApplication:StopApplication()
UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()De vegades també és útil poder veure l'hora de simulació en què es va generar el missatge de registre. Podeu fer-ho afegint el bit OR prefix_time:
$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: UdpEchoServerApplication=level_all|prefix_func|prefix_time'De nou, haureu d'eliminar el caràcter de nova línia anterior. Si ara executeu l'script, hauríeu de veure la sortida següent:
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)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()Tingueu en compte que el constructor de UdpEchoServer es va cridar durant la simulació 0 segons. Això passa realment abans que comenci la simulació, però el temps es mostra com a zero segons. El mateix passa amb el missatge del constructor UdpEchoClient.
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)
0s UdpEchoServerApplication:UdpEchoServer()
0s UdpEchoClientApplication:UdpEchoClient()
0s UdpEchoClientApplication:SetDataSize(1024)
1s UdpEchoServerApplication:StartApplication()
2s UdpEchoClientApplication:StartApplication()
2s UdpEchoClientApplication:ScheduleTransmit()
2s UdpEchoClientApplication:Send()
2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
10s UdpEchoClientApplication:StopApplication()
UdpEchoClientApplication:DoDispose()
UdpEchoServerApplication:DoDispose()
UdpEchoClientApplication:~UdpEchoClient()
UdpEchoServerApplication:~UdpEchoServer()Recordem que el guió scratch/first.cc va iniciar l'aplicació del servidor d'eco un segon abans de l'inici de la simulació. Ara podeu veure que el mètode Inicia l'aplicació el servidor es crida realment en el primer segon. També podeu notar que el client d'eco s'inicia al segon segon de la simulació, tal com vam demanar a l'script.
Ara podeu seguir el progrés de la simulació en trucada ScheduleTransmit al client que crida a la devolució de trucada HandleRead Send a l'aplicació del servidor d'eco. Tingueu en compte que el temps transcorregut per enviar un paquet a través d'un enllaç punt a punt és de 3,69 mil·lisegons. Podeu veure que el servidor d'eco registra un missatge que ha respost al paquet i, després d'un retard del canal, veureu que el client d'eco rep el paquet d'eco amb el seu mètode HandleRead.
En aquesta simulació, passen moltes coses sense que us adoneu. Però podeu fer un seguiment de tot el procés molt fàcilment activant tots els components de registre del sistema. Proveu d'establir la variable NS_LOG al valor següent,
$ export 'NS_LOG=*=level_all|prefix_func|prefix_time'L'asterisc de dalt és un caràcter comodí per al component de registre. Això inclourà totes les entrades de tots els components utilitzats en la simulació. No reproduiré la sortida aquí (en el moment d'escriure produeix 1265 línies de sortida per a un sol paquet d'eco), però podeu redirigir aquesta informació a un fitxer i veure-la al vostre editor preferit.
$ ./waf --run scratch/myfirst > log.out 2>&1Jo personalment faig servir aquesta versió extremadament detallada del registre quan tinc un problema i no tinc ni idea d'on han anat malament les coses. Puc seguir l'execució del codi amb força facilitat sense establir punts d'interrupció i passar pel codi al depurador. Només puc editar la sortida al meu editor preferit i buscar el que espero i veure que passa alguna cosa que no esperava. Un cop tinc una idea general del que va malament, passo al depurador per aprofundir en el problema. Aquest tipus de sortida pot ser especialment útil quan el vostre script fa alguna cosa completament inesperada. Si només utilitzeu el depurador, és possible que us perdeu un gir completament. El registre fa que aquests girs es notin.
5.1.3 Afegir registre al vostre codi
Podeu afegir noves entrades a les vostres simulacions fent trucades al component de registre des de diverses macros. Fem-ho en un guió myfirst.cc, que tenim al directori "net". Recordeu que hem definit un component de registre en aquest escenari:
NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");Sabeu que podeu habilitar el registre de tots els missatges d'aquest component establint la variable d'entorn NS_LOG a diferents nivells. Anem endavant i afegim algunes entrades al guió. La macro que s'utilitza per afegir missatges de nivell d'informació al registre és NS_LOG_INFO. Afegim un missatge (just abans de començar a crear nodes) que us digui que l'script es troba en la fase de "Creació de la topologia". Això es fa en el següent fragment de codi,
Obriu-ho scratch/myfirst.cc al vostre editor preferit i afegiu la línia,
NS_LOG_INFO ("Creating Topology");
just abans de les línies,
NodeContainer nodes;
nodes.Create (2);Ara compileu l'script utilitzant waf, i desactiveu la variable NS_LOG per desactivar el flux de registre que vam habilitar anteriorment:
$ ./waf
$ export NS_LOG=
Теперь, если вы запустите скрипт,
$ ./waf --run scratch/myfirstNo veureu el missatge nou perquè el component de registre associat (FirstScriptExample) no s'ha habilitat. Per veure el vostre missatge, heu d'activar el component de registre FirstScriptExample amb un nivell no inferior a NS_LOG_INFO. Si només voleu veure aquest nivell de registre específic, podeu activar-lo així,
$ export NS_LOG=FirstScriptExample=infoSi executeu l'script ara, veureu un missatge nou "Creant una topologia",
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.404s)
Creating Topology
Sent 1024 bytes to 10.1.1.2
Received 1024 bytes from 10.1.1.1
Received 1024 bytes from 10.1.1.25.2 Ús d'arguments de línia d'ordres
5.2.1 Anulació dels valors d'atribut predeterminats
Una altra manera de canviar el comportament dels scripts ns-3 sense editar ni construir és utilitzar arguments de línia d'ordres. Proporcionem un mecanisme per analitzar els arguments de la línia d'ordres i establir automàticament variables locals i globals en funció dels resultats.
El primer pas per utilitzar el sistema d'arguments de línia d'ordres és declarar un analitzador de línia d'ordres. Això és bastant fàcil de fer (al vostre programa principal), com en el codi següent,
int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}Aquest senzill fragment de dues línies és realment molt útil per si mateix. Obre la porta al sistema d'atributs i variables globals ns-3. Afegim dues línies de codi al començament de la funció d'script principal scratch/myfirst.cc. Seguint, compilem l'script i l'executem, quan executem fem una sol·licitud d'ajuda de la següent manera:
$ ./waf --run "scratch/myfirst --PrintHelp"Aquesta comanda preguntarà Waf executa l'script rascar/el meu primer i passar-li un argument de línia d'ordres —Imprimeix Ajuda. Les cometes són necessàries per indicar a quin programa està destinat l'argument. L'analitzador de la línia d'ordres detectarà l'argument —Imprimeix Ajuda i mostrarà la resposta,
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.413s)
TcpL4Protocol:TcpStateMachine()
CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.Ara mirem l'opció —Atributs d'impressió. Ja hem esmentat el sistema d'atributs ns-3 quan estudiem l'script first.cc. Hem vist les següents línies de codi,
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));i ho van dir Velocitat de dades és en realitat un atribut PointToPointNetDevice. Utilitzem l'analitzador d'arguments de la línia d'ordres per veure els atributs PointToPointNetDevice. La llista d'ajuda diu què hem de proporcionar TypeId. Aquest és el nom de la classe a la qual pertanyen els atributs d'interès. En el nostre cas serà així ns3::PointToPointNetDevice. Seguim avançant, entra,
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"El sistema imprimirà tots els atributs d'aquest tipus de dispositiu de xarxa. Veureu que entre els atributs de la llista hi ha,
--ns3::PointToPointNetDevice::DataRate=[32768bps]:
The default data rate for point to point linksAquest és el valor predeterminat que utilitzarà el sistema en crear l'objecte PointToPointNetDevice. Invalidarem aquest valor per defecte mitjançant el paràmetre Atribut в PointToPointHelper més alt. Utilitzem els valors predeterminats per a dispositius i canals punt a punt. Per fer-ho, esborrarem les trucades SetDeviceAttribute и SetChannelAttribute d' myfirst.cc, que tenim en un directori net.
El vostre script ara simplement hauria de declarar PointToPointHelper i no realitzeu cap operació d'instal·lació com es mostra a l'exemple següent,
...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...Avança i crea un script nou amb Waf (./waf) i tornem enrere i incloem alguna entrada de l'aplicació del servidor d'eco UDP i incloem el prefix de temps.
$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'Si executeu l'script, hauríeu de veure la sortida següent:
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.405s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Recordeu que l'última vegada que vam mirar el temps de simulació, en el moment en què el servidor d'eco va rebre el paquet, va ser de 2,00369 segons.
2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1Ara rep el paquet en 2.25732 segons. Això es deu al fet que simplement restablim la velocitat de dades de PointToPointNetDevice de cinc megabits per segon al valor predeterminat, que és de 32768 bits per segon. Si haguéssim de substituir un nou DataRate mitjançant la línia d'ordres, podríem tornar a accelerar la nostra simulació. Ho farem de la següent manera, segons la fórmula que implica l'element d'ajuda:
$ ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"Això tornarà l'atribut DataRate al seu valor predeterminat de cinc megabits per segon. Us sorprèn el resultat? Resulta que per tornar el comportament original del guió, també hem d'establir el retard del canal perquè coincideixi amb la velocitat de la llum. Podem demanar al sistema de línia d'ordres que imprimeixi els atributs del canal, tal com vam fer per al dispositiu de xarxa:
$ ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"Trobarem que l'atribut de retard del canal s'estableix de la següent manera:
--ns3::PointToPointChannel::Delay=[0ns]:
Transmission delay through the channelAleshores, mitjançant el sistema de línia d'ordres, podem establir aquests dos valors per defecte.
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms"en aquest cas, restaurem el temps que teníem quan vam establir explícitament DataRate i Delay a l'script:
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.417s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.00369s Received 1024 bytes from 10.1.1.1
2.00369s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Tingueu en compte que el servidor torna a rebre el paquet després de 2,00369 segons. De fet, podríem establir qualsevol dels atributs utilitzats a l'script d'aquesta manera. En particular, podríem establir els atributs MaxPackets a valors que no siguin un UdpEchoClient.
Com l'utilitzaries? Prova-ho. Recordeu que heu de comentar el lloc on substituïm el valor de l'atribut predeterminat i l'establim explícitament MaxPackets al guió. Aleshores heu de reconstruir l'script. També podeu utilitzar la línia d'ordres per obtenir ajuda de sintaxi per establir un nou valor d'atribut predeterminat. Un cop entengueu això, podeu controlar el nombre de paquets que es mostren a la línia d'ordres. Com que som gent estudiosa, la nostra línia d'ordres hauria de semblar a això:
$ ./waf --run "scratch/myfirst
--ns3::PointToPointNetDevice::DataRate=5Mbps
--ns3::PointToPointChannel::Delay=2ms
--ns3::UdpEchoClient::MaxPackets=2"La pregunta natural que sorgeix en aquest punt és com saber sobre l'existència de tots aquests atributs. De nou, el sistema de línia d'ordres té una funció d'ajuda per a aquest tema. Si demanem ajuda a la línia d'ordres, hauríem de veure:
$ ./waf --run "scratch/myfirst --PrintHelp"
myfirst [Program Arguments] [General Arguments]
General Arguments:
--PrintGlobals: Print the list of globals.
--PrintGroups: Print the list of groups.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintTypeIds: Print all TypeIds.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintHelp: Print this help message.Si seleccioneu l'argument "PrintGroups", hauríeu de veure una llista de tots els grups registrats TypeId. Els noms dels grups són coherents amb els noms dels mòduls del directori font (encara que en majúscula). Imprimir tota la informació alhora seria massa voluminós, de manera que hi ha disponible un filtre addicional per imprimir informació per grup. Per tant, centrant-nos de nou en el mòdul punt a punt:
./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in group PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeaderAquí podeu trobar noms de TypeId disponibles per a cerques d'atributs, per exemple a
--PrintAttributes = ns3 :: PointToPointChannelcom es mostra més amunt.
Una altra manera d'aprendre sobre els atributs és mitjançant Doxygen ns-3. Hi ha una pàgina que enumera tots els atributs registrats al simulador.
5.2.2 Capturar les vostres pròpies ordres
També podeu afegir els vostres propis ganxos mitjançant el sistema de línia d'ordres. Això es fa senzillament utilitzant el mètode analitzador de línia d'ordres Afegeix valor.
Utilitzem aquesta característica per especificar el nombre de paquets que es mostraran d'una manera completament diferent. Afegim una variable local anomenada nPaquets en una funció principal. L'establirem a un perquè coincideixi amb el nostre comportament predeterminat anterior. Per permetre que l'analitzador de la línia d'ordres canviï aquest valor, hem de capturar aquest valor a l'analitzador. Ho fem afegint una trucada Afegeix valor. Aneu i canvieu el guió scratch/myfirst.cc així que per començar amb el codi següent,
int
main (int argc, char *argv[])
{
uint32_t nPackets = 1;
CommandLine cmd;
cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
cmd.Parse (argc, argv);
...Desplaceu-vos cap avall fins al punt de l'script on establim l'atribut MaxPackets i el canviem de manera que s'estableixi a la variable nPackets en lloc de la constant 1, tal com es mostra a continuació.
echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));Ara, si executeu l'script i proporcioneu l'argument -PrintHelp, hauríeu de veure el nou argument d'usuari. que apareix a la pantalla d'ajuda. Entra,
$ ./waf --run "scratch/myfirst --PrintHelp"
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.403s)
--PrintHelp: Print this help message.
--PrintGroups: Print the list of groups.
--PrintTypeIds: Print all TypeIds.
--PrintGroup=[group]: Print all TypeIds of group.
--PrintAttributes=[typeid]: Print all attributes of typeid.
--PrintGlobals: Print the list of globals.
User Arguments:
--nPackets: Number of packets to echoSi voleu canviar el nombre de paquets transmesos, podeu fer-ho configurant l'argument de la línia d'ordres -nPackets.
$ ./waf --run "scratch/myfirst --nPackets=2"Ara hauríeu de veure
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.404s)
0s UdpEchoServerApplication:UdpEchoServer()
1s UdpEchoServerApplication:StartApplication()
Sent 1024 bytes to 10.1.1.2
2.25732s Received 1024 bytes from 10.1.1.1
2.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
Sent 1024 bytes to 10.1.1.2
3.25732s Received 1024 bytes from 10.1.1.1
3.25732s Echoing packet
Received 1024 bytes from 10.1.1.2
10s UdpEchoServerApplication:StopApplication()
UdpEchoServerApplication:DoDispose()
UdpEchoServerApplication:~UdpEchoServer()Ara heu enviat dos paquets. Bastant senzill, no?
Podeu veure que com a usuari ns-3, podeu utilitzar el sistema d'arguments de línia d'ordres per manipular valors i atributs globals. Si sou l'autor del model, podeu afegir nous atributs als vostres objectes i estaran disponibles automàticament per a la configuració dels vostres usuaris mitjançant el sistema de línia d'ordres. Si sou un autor d'scripts, podeu afegir noves variables als vostres scripts i connectar-los perfectament al vostre sistema de línia d'ordres.
5.3 Ús del sistema de traçat
L'objectiu de la modelització és generar resultats per a un estudi posterior, i el sistema de traça ns-3 és el mecanisme principal per a això. Com que ns-3 és un programa C++, es poden utilitzar els mitjans estàndard per generar la sortida d'un programa C++:
#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}Fins i tot podeu utilitzar un mòdul de registre per afegir una petita estructura a la vostra solució. Hi ha molts problemes coneguts causats per aquest enfocament i, per tant, hem proporcionat un subsistema general de seguiment d'esdeveniments per resoldre aquests problemes.
Els objectius principals del sistema de traça ns-3 són:
Per a les tasques bàsiques, el sistema de traça hauria de permetre a l'usuari generar una traça estàndard per a fonts populars i seleccionar objectes que generen la traça;
Els usuaris intermedis haurien de poder ampliar el sistema de traça per canviar el format de sortida generat o inserir noves fonts de traça, sense modificar el nucli del simulador;
Els usuaris avançats poden modificar el nucli del simulador per afegir noves fonts de traça i embornals. El sistema de traça ns-3 es basa en els principis de fonts i receptors de seguiment independents, així com un mecanisme unificat per connectar les fonts als consumidors.
El sistema de traça ns-3 es basa en els principis de fonts i receptors de traça independents, així com un mecanisme unificat per connectar fonts amb receptors. Les fonts de traça són objectes que poden assenyalar esdeveniments que es produeixen a la simulació i proporcionar accés a les dades subjacents d'interès. Per exemple, una font de traça pot indicar quan un dispositiu de xarxa ha rebut un paquet i posar el contingut del paquet a disposició dels receptors de traça interessats.
Les fonts de traça per si soles són inútils tret que estiguin "acoblades" amb altres parts del codi que realment fan alguna cosa útil amb la informació proporcionada per la pica. Els traçadors són consumidors d'esdeveniments i dades proporcionades per fonts de traça. Per exemple, podeu crear un dipòsit de traça que (quan estigui connectat a la font de traça de l'exemple anterior) imprimirà les parts d'interès del paquet rebut.
La justificació d'aquesta separació explícita és permetre als usuaris connectar nous tipus de lavabo a fonts de traça existents sense haver d'editar i recompilar el nucli del simulador. Així, a l'exemple anterior, l'usuari pot definir un traçador nou al seu script i connectar-lo a una font de traça existent definida al nucli de simulació només editant l'script d'usuari.
En aquest tutorial, repassarem algunes de les fonts i embornals predefinits i mostrarem com es poden configurar amb el mínim esforç per part de l'usuari. Consulteu el manual ns-3 o les seccions d'instruccions per obtenir informació sobre la configuració avançada de traça, inclosa l'ampliació de l'espai de noms de traça i la creació de noves fonts de traça.
5.3.1 Traçat ASCII
ns-3 proporciona una funcionalitat d'ajuda que proporciona un sistema de traça de baix nivell per ajudar-vos amb els detalls quan configureu rastres de paquets simples. Si activeu aquesta funció, veureu la sortida en fitxers ASCII. Per a aquells que estiguin familiaritzats amb la sortida ns-2, aquest tipus de traça és similar a fora.tr, que és generat per molts scripts.
Anem a treballar i afegim alguns resultats de traça ASCII al nostre script scratch/myfirst.cc. Just abans de la trucada Simulator :: Run (), afegiu les següents línies de codi:
AsciiTraceHelper ascii;
pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));Com molts altres modismes ns-3, aquest codi utilitza un objecte auxiliar per crear traces ASCII. La segona línia conté dues trucades de mètode imbricades. Mètode "dins". CreateFileStream() utilitza l'idioma d'objecte anònim per crear un objecte de flux de fitxers a la pila (sense nom d'objecte) i el passa al mètode anomenat. Aprofundirem en això en el futur, però tot el que necessiteu saber en aquest moment és que esteu creant un objecte que representa un fitxer anomenat myfirst.tr i transferir-lo a ns-3. Confiem a ns-3 per cuidar l'objecte creat durant tota la seva vida útil, durant la qual resol problemes causats per una limitació poc coneguda (intencionada) associada als constructors de còpia d'objectes de flux C++.
Trucada externa EnableAsciiAll() indica a l'assistent que voleu incloure el traçat ASCII a la vostra simulació per a totes les connexions de dispositiu punt a punt i que voleu que els receptors de traça (especificats) enregistrin la informació del moviment de paquets en format ASCII.
Per a aquells que estiguin familiaritzats amb ns-2, els esdeveniments rastrejats són equivalents als punts de traça coneguts que registren esdeveniments "+", "-", "d" i "r".
Ara podeu crear l'script i executar-lo des de la línia d'ordres:
$ ./waf --run scratch/myfirstCom moltes vegades abans, veureu diversos missatges de Waf i, a continuació, "'build' s'ha acabat correctament" amb alguns missatges del programa en execució.
Quan s'executa, el programa crearà un fitxer anomenat myfirst.tr. Per la naturalesa de l'obra Waf, per defecte el fitxer no es crea al directori local, sinó al directori de nivell superior del dipòsit. Si voleu canviar el camí on es guarden les traces, podeu utilitzar el paràmetre Waf per especificar-lo --cwd. No ho hem fet, així que per mirar el fitxer de traça ASCII myfirst.tr al vostre editor preferit, haurem d'anar al directori de nivell superior del nostre dipòsit.
Anàlisi de traces ASCII
Hi ha molta informació allà en una forma força densa, però el primer que heu de notar és que el fitxer consta de línies individuals. Això serà clarament visible si amplieu la finestra de visualització més àmplia.
Cada línia del fitxer correspon a un esdeveniment de traça. En aquest cas, tracem els esdeveniments a la cua de transmissió present a cada dispositiu de xarxa punt a punt de la simulació. La cua de transmissió és la cua per la qual ha de passar cada paquet per a un enllaç punt a punt. Tingueu en compte que cada línia del fitxer de traça comença amb un sol caràcter (i té un espai després). Aquest símbol tindrà el significat següent:
+: s'ha produït una operació de cua a la cua del dispositiu;
-: s'ha produït una operació de recuperació d'elements a la cua del dispositiu;
d: el paquet es va deixar caure, normalment perquè la cua estava plena;
r: el paquet l'ha rebut un dispositiu de xarxa.
Fem una ullada més de prop a la primera línia del fitxer de traça. Ho dividiré en parts (amb sagnies per a més claredat) i el número de línia de l'esquerra:
0 +
1 2
2 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
3 ns3::PppHeader (
4 Point-to-Point Protocol: IP (0x0021))
6 ns3::Ipv4Header (
7 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
8 length: 1052 10.1.1.1 > 10.1.1.2)
9 ns3::UdpHeader (
10 length: 1032 49153 > 9)
11 Payload (size=1024)La primera secció d'aquest esdeveniment de traça estès (línia 0) és l'operació. Aquí tenim un símbol +, que correspon a l'operació de posar en cua per a la transmissió. La segona secció (línia 1) és el temps de simulació, expressat en segons. Potser recordeu el que vam demanar UdpEchoClientApplication començar a enviar paquets en dos segons. Aquí veiem la confirmació que això està passant.
La secció següent de l'exemple de traça (de la línia 2) mostra quina font de traça ha generat aquest esdeveniment (indicant la traça de l'espai de noms). Podeu pensar en l'espai de noms de traça com ho faríeu amb un espai de noms de sistema de fitxers. L'arrel de l'espai de noms és NodeList. Això correspon al contenidor gestionat al codi ns-3 principal. Conté tots els nodes que es creen a l'script. De la mateixa manera que un sistema de fitxers pot tenir directoris a l'arrel, NodeList podem tenir molts nodes. Així, la línia /NodeList/0 fa referència al node nul de la NodeList, que normalment pensem com a "node 0". Cada node té una llista de dispositius que s'han instal·lat. Aquesta llista es troba a continuació a l'espai de noms. Podeu veure que aquest esdeveniment traça prové DeviceList/0, que és el dispositiu nul instal·lat al node.
següent subcadena, $ ns3 :: PointToPointNetDevice, indica quin dispositiu està a la posició zero: la llista de dispositius del node zero. Recordeu que l'operació + trobada a la línia 0 significava que s'ha afegit un element a la cua de transmissió del dispositiu. Això es reflecteix en els últims segments del "camí de la pista": TxQueue/Enqueue.
Les seccions restants de la traça haurien de ser bastant intuïtives. Les línies 3-4 indiquen que el paquet està encapsulat en un protocol punt a punt. Les línies 5-7 mostren que el paquet té una capçalera de versió IP4 i s'origina a l'adreça IP 10.1.1.1 i està destinat a 10.1.1.2. Les línies 8-9 mostren que aquest paquet té una capçalera UDP i, finalment, la línia 10 mostra que la càrrega útil és dels 1024 bytes esperats.
La següent línia del fitxer de traça mostra que el mateix paquet es va extreure de la cua de transmissió al mateix node.
La tercera línia del fitxer de traça mostra que el paquet va ser rebut per un dispositiu de xarxa a l'amfitrió del servidor d'eco. He reproduït l'esdeveniment a continuació.
0 r
1 2.25732
2 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx
3 ns3::Ipv4Header (
4 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
5 length: 1052 10.1.1.1 > 10.1.1.2)
6 ns3::UdpHeader (
7 length: 1032 49153 > 9)
8 Payload (size=1024)Tingueu en compte que l'operació de traça és ara r i el temps de simulació s'ha augmentat a 2,25732 segons. Si heu seguit el tutorial amb atenció, això vol dir que heu deixat DataRate i Link Delay dels dispositius de xarxa amb els seus valors predeterminats. Aquest temps ha de ser familiar, com heu vist a l'apartat anterior.
L'entrada de l'espai de noms de la font de traça (línia 2) s'ha modificat per reflectir que aquest esdeveniment prové del node 1 (/NodeList/1) i la font de traça rep el paquet (/MacRx). Hauria de ser bastant fàcil seguir el moviment del paquet a través de la topologia mirant les traces restants del fitxer.
5.3.2 Traça PCAP
Els auxiliars de dispositiu ns-3 també es poden utilitzar per crear fitxers de traça en format .pcap. Acrònim pcap (normalment escrit en minúscula) significa captura de paquets i en realitat és una API que inclou definir el format de fitxer .pcap. El programa més popular que pot llegir i mostrar aquest format és Wireshark (anteriorment anomenat Etéreo). Tanmateix, hi ha molts analitzadors de traça de trànsit que utilitzen aquest format de paquet. Animem als usuaris a utilitzar les nombroses eines disponibles per analitzar les traces de pcap. En aquest tutorial ens centrarem a veure les traces pcap utilitzant tcpdump.
L'habilitació del seguiment de pcap es fa amb una línia de codi.
pointToPoint.EnablePcapAll ("myfirst");Enganxeu aquesta línia de codi després del codi de traça ASCII que acabem d'afegir scratch/myfirst.cc. Tingueu en compte que només hem passat la cadena "myfirst", no "myfirst.pcap" ni res semblant. Això es deu al fet que el paràmetre és un prefix, no un nom de fitxer complet. Durant la simulació, l'assistent crearà un fitxer de traça per a cada dispositiu punt a punt. Els noms dels fitxers es crearan amb el prefix, el número de node, el número de dispositiu i el sufix ".pcap».
Per al nostre script d'exemple, acabarem veient fitxers anomenats "myfirst-0-0.pcap"I"myfirst-1-0.pcap", que són traces pcap per al node 0-dispositiu 0 i node 1-dispositiu 0, respectivament. Un cop hàgiu afegit la línia de codi per habilitar el seguiment de pcap, podeu executar l'script de la manera habitual:
$ ./waf --run scratch/myfirstSi mireu al directori de nivell superior de la vostra distribució, hauríeu de veure tres fitxers: un fitxer de traça ASCII myfirst.tr, que hem estudiat anteriorment, fitxers myfirst-0-0.pcap и myfirst-1-0.pcap - nous fitxers pcap que acabem de generar.
Llegint la sortida amb tcpdump
De moment, la manera més senzilla de veure fitxers pcap és utilitzar tcpdump.
$ tcpdump -nn -tt -r myfirst-0-0.pcap
reading from file myfirst-0-0.pcap, link-type PPP (PPP)
2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
tcpdump -nn -tt -r myfirst-1-0.pcap
reading from file myfirst-1-0.pcap, link-type PPP (PPP)
2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024A l'abocador myfirst-0-0.pcap (dispositiu client) podeu veure que el paquet d'eco s'envia després de 2 segons de simulació. Si mireu el segon abocador (myfirst-1-0.pcap), veureu que el paquet es rep als 2,257324 segons. Veureu al segon abocament que el paquet es retorna als 2.257324 segons i, finalment, que el client va rebre el paquet en el primer abocament als 2.514648 segons.
Sortida de lectura amb Wireshark
Si no estàs familiaritzat amb Wireshark, hi ha un lloc web des del qual podeu descarregar programes i documentació: . Wireshark és una GUI que es pot utilitzar per mostrar aquests fitxers de traça. Si teniu Wireshark, podeu obrir qualsevol dels fitxers de traça i mostrar el contingut com si haguéssiu capturat els paquets mitjançant un rastrejador de paquets.
Font: www.habr.com
