Handledning för ns-3 nätverkssimulator. Kapitel 5

Handledning för ns-3 nätverkssimulator. Kapitel 5
kapitel 1,2
kapitel 3
kapitel 4

5 Inställningar
5.1 Använda loggningsmodulen
5.1.1 Loggningsöversikt
5.1.2 Aktivera loggning
5.1.3 Lägga till loggning i din kod
5.2 Använda kommandoradsargument
5.2.1 Åsidosättande av standardvärden för attribut
5.2.2 Fånga dina egna kommandon
5.3 Använda spårningssystemet
5.3.1 ASCII-spårning
Parsar ASCII-spår
5.3.2 PCAP-spårning

Kapitel 5

justering

5.1 Använda loggningsmodulen

Vi har redan kort tittat på ns-3-loggningsmodulen genom att titta på skriptet första.cc. I det här kapitlet kommer vi att titta närmare på möjliga användningsområden för loggningsdelsystemet.

5.1.1 Loggningsöversikt

Många stora system stöder någon form av meddelandeloggningsfunktion, och ns-3 är inget undantag. I vissa fall skrivs bara felmeddelanden till "operatörskonsolen" (som vanligtvis är stderr på Unix-baserade system). På andra system kan varningsmeddelanden visas samt mer detaljerad information. I vissa fall används loggningsverktyg för att mata ut felsökningsmeddelanden som snabbt kan göra utdata suddiga.

SubHRD som används i ns-3 förutsätter att alla dessa nivåer av informationsinnehåll är användbara, och vi tillhandahåller en selektiv, skiktad metod för meddelandeloggning. Loggning kan inaktiveras helt, aktiveras per komponent eller globalt. För detta ändamål används justerbara nivåer av informationsinnehåll. Loggningsmodulen ns-3 ger ett relativt enkelt sätt att få användbar information från din simulering.

Du bör förstå att vi tillhandahåller en allmän mekanism - spårning - för att extrahera data från dina modeller, vilket bör vara den föredragna utgången för simuleringar (för mer information om vårt spårningssystem, se självstudieavsnitt 5.3). Loggning bör vara den föredragna metoden för att få felsökningsinformation, varningar, felmeddelanden eller för att snabbt mata ut meddelanden från dina skript eller modeller när som helst.

För närvarande definierar systemet sju nivåer (typer) av loggmeddelanden i ökande ordning av informationsinnehåll.

  • LOG_ERROR - loggning av felmeddelanden (relaterat makro: NS_LOG_ERROR);
  • LOG_WARN - Logga varningsmeddelanden (relaterat makro: NS_LOG_WARN);
  • LOG_DEBUG - Logga relativt sällsynta speciella felsökningsmeddelanden (relaterat makro: NS_LOG_DEBUG);
  • LOG_INFO - registrering av informationsmeddelanden om programmets framsteg (relaterat makro: NS_LOG_INFO);
  • LOG_FUNCTION - Loggar meddelanden som beskriver varje funktion som kallas (två relaterade makron: NS_LOG_FUNCTION, används för medlemsfunktioner och NS_LOG_FUNCTION_NOARGS, används för statiska funktioner);
  • LOG_LOGIC - loggning av meddelanden som beskriver det logiska flödet inom en funktion (relaterat makro: NS_LOG_LOGIC);
  • LOG_ALL - Loggar allt som nämns ovan (inget associerat makro).
    För varje typ (LOG_TYPE) finns det också en LOG_LEVEL_TYPE som, om den används, tillåter att alla nivåer ovanför den loggas förutom sin egen nivå. (Som en konsekvens är LOG_ERROR och LOG_LEVEL_ERROR, och LOG_ALL och LOG_LEVEL_ALL funktionellt likvärdiga.) Till exempel kommer att aktivera LOG_INFO endast att tillåta meddelanden som tillhandahålls av makrot NS_LOG_INFO, medan aktivering av LOG_LEVEL_INFO även inkluderar meddelanden som tillhandahålls av makrona LOG_DE_LOGRN_LOGRNS, LOG_DE_LOGRN_LOGRNS och WAOR_LOGRNS.

Vi tillhandahåller även ett ovillkorligt loggningsmakro som alltid visas, oavsett loggningsnivå eller urvalskomponent.

  • NS_LOG_UNCOND - Ovillkorlig loggning av det associerade meddelandet (ingen associerad loggningsnivå).

Varje nivå kan frågas individuellt eller kumulativt. Loggning kan konfigureras med sh miljövariabel NS_LOG eller genom att logga ett systemfunktionsanrop. Som visats tidigare har loggningssystemet Doxygen-dokumentation och nu är det ett bra tillfälle att granska den om du inte redan har gjort det.

Nu när du har läst dokumentationen i detalj, låt oss använda den kunskapen för att få lite intressant information från exempelskriptet scratch/myfirst.ccsom du redan har sammanställt.

5.1.2 Aktivera loggning

Låt oss använda miljövariabeln NS_LOG för att köra några fler loggar, men först, bara för att få din orientering, kör det sista skriptet som du gjorde tidigare,

$ ./waf --run scratch/myfirst

Du bör se den välbekanta utgången från det första ns-3-exempelprogrammet

$ 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.2

Det visar sig att de "skickade" och "mottagna" meddelandena du ser ovan faktiskt är loggade meddelanden från UdpEchoClientApplication и UdpEchoServerApplication. Till exempel kan vi be klientapplikationen att skriva ut ytterligare information genom att ställa in dess loggningsnivå via miljövariabeln NS_LOG.

Från och med nu kommer jag att anta att du använder ett sh-liknande skal som använder syntaxen "VARIABLE=värde". Om du använder ett csh-liknande skal, måste du konvertera mina exempel till syntaxen "setenv variabelvärde" som krävs av dessa skal.

För närvarande svarar UDP echo-klientapplikationen på följande kodrad in scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Den aktiverar loggningsnivån LOG_LEVEL_INFO. När vi passerar en loggningsnivåflagga, aktiverar vi faktiskt den nivån och alla lägre nivåer. I det här fallet har vi aktiverat NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN och NS_LOG_ERROR. Vi kan öka loggningsnivån och få mer information, utan skriptändringar och omkompilering, genom att ställa in miljövariabeln NS_LOG enligt följande:

$ export NS_LOG=UdpEchoClientApplication=level_all

Så vi ställer in sh-skalvariabeln NS_LOG till följande värde,

UdpEchoClientApplication=level_all

Den vänstra sidan av uppdraget är namnet på den loggade komponenten vi vill konfigurera, och den högra sidan är flaggan vi vill använda för den. I det här fallet kommer vi att aktivera alla nivåer av felsökning i applikationen. Om du kör skriptet med NS_LOG inställt på detta sätt, kommer ns-3-loggningssystemet att acceptera ändringarna och du bör se följande utdata:

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()

Ytterligare felsökningsinformation från programmet finns nu på NS_LOG_FUNCTION-nivån. Den visar varje instans av ett funktionsanrop under skriptkörning. Som en allmän regel, i metodfunktioner är det att föredra att använda (minst)NS_LOG_FUNCTION (this). Använda sig av NS_LOG_FUNCTION_NOARGS ()
endast i statiska funktioner. Observera dock att ns-3-systemet inte krävs för att stödja någon loggningsfunktion. Beslutet om hur mycket information som registreras överlåts till den enskilde modellutvecklaren. När det gäller ekoapplikationer finns en stor mängd loggningsutdata tillgänglig.

Du kan nu se en logg över funktionsanrop som gjordes av applikationen. Om du tittar noga kommer du att märka ett kolon mellan linjen UdpEchoClientApplication och namnet på metoden, där du kan förvänta dig att se C++ scope-operatorn (: :). Detta är avsiktligt.

Detta är faktiskt inte namnet på klassen, utan namnet på loggningskomponenten. När det finns en matchning mellan en källfil och en klass är det vanligtvis namnet på klassen, men du bör inse att det faktiskt inte är namnet på klassen, och det finns ett enda kolon istället för ett dubbelt kolon. Det här är ett sätt att hjälpa dig att konceptuellt skilja loggningsbönans namn från klassnamnet på ett relativt subtilt sätt.

Men i vissa fall kan det vara svårt att avgöra vilken metod som faktiskt genererar loggmeddelandet. Om du tittar på texten ovan kanske du undrar var linjen "Received 1024 bytes from 10.1.1.2" Du kan lösa detta problem genom att ställa in nivån prefix_func till miljövariabeln NS_LOG. Prova följande:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Observera att citattecken är nödvändiga eftersom den vertikala stapeln vi använder för att representera ELLER-operationen också är en Unix-rörkoppling. Om du nu kör skriptet kommer du att se att loggningssystemet ser till att varje meddelande i en given logg har prefixet med komponentnamnet.

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()

Nu kan du se att alla meddelanden som kommer från UDP echo-klientapplikationen identifieras som sådana. Meddelande "Received 1024 bytes from 10.1.1.2" är nu tydligt identifierad som kommer från echo-klientapplikationen. Det återstående meddelandet måste komma från UDP-ekoserverapplikationen. Vi kan aktivera denna komponent genom att ange en kolonseparerad lista med komponenter i miljövariabeln NS_LOG.

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

Varning: I exemplet ovan måste du ta bort nyradstecknet efter kolon (:), det används för att formatera dokumentet. Om du nu kör skriptet kommer du att se alla loggmeddelanden från klient- och serverekoapplikationerna. Du kan se att detta kan vara mycket användbart vid felsökning.

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()

Det är också ibland användbart att kunna se simuleringstiden då loggmeddelandet genererades. Du kan göra detta genom att lägga till OR-biten prefix_time:

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

Återigen måste du ta bort ovanstående nyradstecken. Om du nu kör skriptet bör du se följande utdata:

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()

Observera att konstruktören för UdpEchoServer anropades under simulering 0 sekunder. Detta händer faktiskt innan simuleringen startar, men tiden visas som noll sekunder. Detsamma gäller för konstruktormeddelandet 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()

Kom ihåg att manuset scratch/first.cc startade ekoserverapplikationen en sekund innan simuleringen startade. Nu kan du se att metoden StartApplication servern anropas faktiskt i första sekunden. Du kanske också märker att ekoklienten startar i den andra sekunden av simuleringen, som vi frågade i skriptet.

Du kan nu följa simuleringsförloppet på samtal Schemaöverföring i klienten som anropar HandleRead callback Send i ekoserverapplikationen. Observera att den tid som förflutit för att skicka ett paket över en punkt-till-punkt-länk är 3,69 millisekunder. Du kan se att ekoservern loggar ett meddelande om att den har svarat på paketet och sedan, efter en kanalfördröjning, ser du att ekoklienten tar emot ekopaketet i sin HandleRead-metod.

I den här simuleringen händer mycket utan att du märker det. Men du kan spåra hela processen väldigt enkelt genom att aktivera alla loggningskomponenter i systemet. Försök att ställa in variabeln NS_LOG till följande värde,

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

Asterisken ovan är ett jokertecken för loggningskomponenten. Detta kommer att inkludera alla poster i alla komponenter som används i simuleringen. Jag kommer inte att reproducera utdata här (i skrivande stund producerar den 1265 rader utdata för ett enda ekopaket), men du kan omdirigera denna information till en fil och visa den i din favoritredigerare.

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

Jag använder personligen denna extremt utförliga version av loggning när jag har ett problem och inte har någon aning om var det gick fel. Jag kan följa kodexekveringen ganska enkelt utan att ställa in brytpunkter och gå igenom koden i debuggern. Jag kan bara redigera resultatet i min favoritredigerare och leta efter vad jag förväntar mig och se något hända som jag inte förväntade mig. När jag har en allmän uppfattning om vad som går fel, hoppar jag in i felsökaren för att gå in i problemet. Den här typen av utdata kan vara särskilt användbar när ditt skript gör något helt oväntat. Om du bara använder felsökaren kan du missa en twist helt. Registrering gör att sådana svängar märks.

5.1.3 Lägga till loggning i din kod

Du kan lägga till nya poster i dina simuleringar genom att göra anrop till loggkomponenten från flera makron. Låt oss göra det i ett manus min första.cc, som vi har i katalogen "ren". Kom ihåg att vi definierade en loggningskomponent i detta scenario:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Du är medveten om att du kan aktivera loggning av alla meddelanden från denna komponent genom att ställa in miljövariabeln NS_LOG på olika nivåer. Låt oss gå vidare och lägga till några poster i manuset. Makrot som används för att lägga till meddelanden på informationsnivå i loggen är NS_LOG_INFO. Låt oss lägga till ett meddelande (precis innan vi börjar skapa noder) som talar om att skriptet är i fasen "Skapa topologi". Detta görs i följande kodavsnitt,
Öppna upp scratch/myfirst.cc i din favoritredigerare och lägg till raden,
NS_LOG_INFO ("Creating Topology");
precis före raderna,

NodeContainer nodes;
nodes.Create (2);

Kompilera nu skriptet med hjälp av WAF, och rensa variabeln NS_LOG för att inaktivera loggningsströmmen som vi aktiverade tidigare:

$ ./waf
$ export NS_LOG=
Теперь, если вы запустите скрипт,
$ ./waf --run scratch/myfirst

Du kommer inte att se det nya meddelandet eftersom den associerade loggningskomponenten (FirstScriptExample) inte har aktiverats. För att se ditt meddelande måste du aktivera loggningskomponenten FirstScriptExample med en nivå som inte är lägre än NS_LOG_INFO. Om du bara vill se den här specifika loggningsnivån kan du aktivera den så här,

$ export NS_LOG=FirstScriptExample=info

Om du kör skriptet nu kommer du att se ett nytt meddelande "Creating Topology",

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.2

5.2 Använda kommandoradsargument

5.2.1 Åsidosättande av standardvärden för attribut

Ett annat sätt att ändra beteendet hos ns-3-skript utan att redigera eller bygga är att använda kommandoradsargument. Vi tillhandahåller en mekanism för att analysera kommandoradsargument och automatiskt ställa in lokala och globala variabler baserat på resultaten.

Det första steget i att använda kommandoradsargumentsystemet är att deklarera en kommandoradsparser. Detta är ganska lätt att göra (i ditt huvudprogram), som i följande kod,

int
main (int argc, char *argv[])
{
...
CommandLine cmd;
cmd.Parse (argc, argv);
...
}

Det här enkla utdraget med två rader är faktiskt väldigt användbart i sin egen rätt. Det öppnar dörren till det globala variabel- och attributsystemet ns-3. Låt oss lägga till två rader kod i början av huvudskriptfunktionen scratch/myfirst.cc. Vi går vidare, kompilerar vi skriptet och kör det, när vi kör gör vi en hjälpbegäran enligt följande,

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

Detta kommando kommer att fråga WAF kör skript repa/min första och skicka det ett kommandoradsargument — Utskriftshjälp. Citattecken krävs för att indikera vilket program argumentet är avsett för. Kommandoradstolkaren kommer att upptäcka argumentet — Utskriftshjälp och kommer att visa svaret,

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.

Låt oss nu titta på alternativet —PrintAttributes. Vi har redan nämnt ns-3-attributsystemet när vi studerade first.cc-skriptet. Vi har sett följande kodrader,

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

och de sa det Datahastighet är faktiskt ett attribut PointToPointNetDevice. Låt oss använda kommandoradens argumentparser för att se attributen PointToPointNetDevice. Hjälplistan säger vad vi måste tillhandahålla TypId. Detta är namnet på den klass som attributen av intresse tillhör. I vårt fall kommer det att bli det ns3::PointToPointNetDevice. Låt oss fortsätta framåt, gå in,

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

Systemet kommer att skriva ut alla attribut för denna nätverksenhetstyp. Du kommer att se att bland attributen i listan finns,

--ns3::PointToPointNetDevice::DataRate=[32768bps]:
The default data rate for point to point links

Detta är standardvärdet som kommer att användas av systemet när objektet skapas PointToPointNetDevice. Vi kommer att åsidosätta detta standardvärde med hjälp av parametern Attribut в PointToPointHelper högre. Låt oss använda standardvärdena för punkt-till-punkt-enheter och kanaler. För att göra detta kommer vi att radera samtal SetDeviceAttribute и SetChannelAttribute av min första.cc, som vi har i en ren katalog.

Ditt skript ska nu bara deklarera PointToPointHelper och utför inga installationsoperationer som visas i exemplet nedan,

...
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
...

Fortsätt och skapa ett nytt skript med WAF (./svaff) och låt oss gå tillbaka och inkludera någon post från UDP-ekoserverapplikationen och inkludera tidsprefixet.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Om du kör skriptet bör du se följande utdata:

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()

Kom ihåg att förra gången vi tittade på simuleringstiden, när paketet togs emot av ekoservern, var det 2,00369 sekunder.

2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1

Nu tar han emot paketet på 2.25732 sekunder. Detta beror på att vi helt enkelt återställer PointToPointNetDevice-datahastigheten från fem megabit per sekund till standardvärdet, vilket är 32768 bitar per sekund. Om vi ​​skulle ersätta en ny DataRate med hjälp av kommandoraden, skulle vi kunna påskynda vår simulering igen. Vi kommer att göra detta enligt formeln som antyds av hjälpelementet:

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

Detta återställer DataRate-attributet till dess standardvärde på fem megabit per sekund. Är du förvånad över resultatet? Det visar sig att för att återställa det ursprungliga beteendet för skriptet måste vi också ställa in kanalfördröjningen för att matcha ljusets hastighet. Vi kan be kommandoradssystemet att skriva ut kanalattributen, precis som vi gjorde för nätverksenheten:

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

Vi kommer att upptäcka att kanalfördröjningsattributet är inställt enligt följande:

--ns3::PointToPointChannel::Delay=[0ns]:
Transmission delay through the channel

Vi kan sedan, genom kommandoradssystemet, ställa in båda dessa standardvärden.

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

i det här fallet återställer vi den tid vi hade när vi uttryckligen ställde in DataRate och Delay i skriptet:

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()

Observera att paketet tas emot av servern igen efter 2,00369 sekunder. Vi skulle faktiskt kunna ställa in vilka attribut som helst som används i skriptet på detta sätt. I synnerhet kan vi ställa in MaxPackets-attributen till icke-ett-värden UdpEchoClient.

Hur skulle du använda den? Ge det ett försök. Kom ihåg att du måste kommentera platsen där vi åsidosätter standardattributvärdet och uttryckligen ställer in MaxPackets i manuset. Sedan måste du bygga om skriptet. Du kan också använda kommandoraden för att få syntaxhjälp för att ställa in ett nytt standardvärde för attribut. När du förstår detta kan du kontrollera antalet paket som visas på kommandoraden. Eftersom vi är flitiga människor bör vår kommandorad se ut ungefär så här:

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

Den naturliga frågan som uppstår vid denna tidpunkt är hur man vet om existensen av alla dessa attribut. Återigen, kommandoradssystemet har en hjälpfunktion för denna fråga. Om vi ​​ber kommandoraden om hjälp bör vi se:

$ ./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.

Om du väljer argumentet "PrintGroups" bör du se en lista över alla registrerade grupper TypId. Gruppnamnen överensstämmer med namnen på modulerna i källkatalogen (även om det är versaler). Att skriva ut all information på en gång skulle vara för omfattande, så ett extra filter finns tillgängligt för att skriva ut information per grupp. Så, återigen med fokus på punkt-till-punkt-modulen:

./waf --run "scratch/myfirst --PrintGroup=PointToPoint"
TypeIds in group PointToPoint:
ns3::PointToPointChannel
ns3::PointToPointNetDevice
ns3::PointToPointRemoteChannel
ns3::PppHeader

Här kan du hitta tillgängliga TypeId-namn för attributsökningar, till exempel i
--PrintAttributes = ns3 :: PointToPointChannelsom visas ovan.

Ett annat sätt att lära sig om attribut är genom Doxygen ns-3. Det finns en sida som listar alla attribut som är registrerade i simulatorn.

5.2.2 Fånga dina egna kommandon

Du kan också lägga till dina egna krokar via kommandoradssystemet. Detta görs helt enkelt med hjälp av kommandoradsparsermetoden Lägg till värde.
Låt oss använda den här funktionen för att specificera antalet paket som ska visas på ett helt annat sätt. Låt oss lägga till en lokal variabel som heter nPacket till en funktion huvudsakliga. Vi ställer in den på ett för att matcha vårt tidigare standardbeteende. För att tillåta kommandoradsparsern att ändra detta värde måste vi fånga detta värde i parsern. Det gör vi genom att lägga till ett samtal Lägg till värde. Gå och ändra skriptet scratch/myfirst.cc så för att börja med följande kod,

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);
...

Scrolla ner till den punkt i skriptet där vi ställer in MaxPackets-attributet och ändrar det så att det ställs in på variabeln nPackets istället för konstanten 1, som visas nedan.

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

Om du nu kör skriptet och anger argumentet -PrintHelp, bör du se det nya användarargumentet. listas på hjälpdisplayen. Stiga på,

$ ./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 echo

Om du vill ändra antalet överförda paket kan du göra det genom att ställa in kommandoradsargumentet - -nPackets.

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

Nu ska du nu se

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()

Du har nu skickat två paket. Ganska enkelt, eller hur?
Du kan se att som en ns-3-användare kan du använda kommandoradsargumentsystemet för att manipulera globala värden och attribut. Om du är modellförfattaren kan du lägga till nya attribut till dina objekt och de blir automatiskt tillgängliga för konfigurering av dina användare via kommandoradssystemet. Om du är skriptförfattare kan du lägga till nya variabler till dina skript och sömlöst koppla in dem i ditt kommandoradssystem.

5.3 Använda spårningssystemet

Hela poängen med modellering är att generera utdata för vidare studier, och ns-3-spårsystemet är huvudmekanismen för detta. Eftersom ns-3 är ett C++-program kan standardmetoder för att generera utdata från ett C++-program användas:

#include <iostream>
...
int main ()
{
...
std::cout << "The value of x is " << x << std::endl;
...
}

Du kan till och med använda en loggningsmodul för att lägga till lite struktur till din lösning. Det finns många kända problem som orsakas av detta tillvägagångssätt, och därför har vi tillhandahållit ett undersystem för allmän händelsespårning för att lösa dessa problem.

Huvudmålen med ns-3-spårningssystemet är:

  • För grundläggande uppgifter bör spårningssystemet tillåta användaren att generera ett standardspår för populära källor och välja objekt som genererar spåret;

  • Mellanliggande användare bör kunna utöka spårningssystemet för att ändra det genererade utdataformatet eller för att infoga nya spårkällor, utan att modifiera simulatorkärnan;

  • Avancerade användare kan modifiera simulatorkärnan för att lägga till nya spårkällor och sänkor. ns-3-spårningssystemet är byggt på principerna för oberoende spårningskällor och mottagare, samt en enhetlig mekanism för att ansluta källor till konsumenter.

ns-3 spårningssystemet är byggt på principerna för oberoende spårningskällor och mottagare, samt en enhetlig mekanism för att ansluta källor till mottagare. Spårkällor är objekt som kan signalera händelser som inträffar i simuleringen och ge tillgång till underliggande data av intresse. Till exempel kan en spårningskälla indikera när en nätverksenhet tog emot ett paket och göra innehållet i paketet tillgängligt för intresserade spårningsmottagare.

Spårkällor i sig är värdelösa såvida de inte är "kopplade" med andra delar av koden som faktiskt gör något användbart med informationen från diskbänken. Spårare är konsumenter av händelser och data som tillhandahålls av spårkällor. Till exempel kan du skapa en spårningssänk som (när den är ansluten till spårkällan i föregående exempel) kommer att skriva ut de delar av intresse i det mottagna paketet.

Skälet för denna explicita separation är att tillåta användare att ansluta nya sänktyper till befintliga spårkällor utan att behöva redigera och kompilera om simulatorkärnan. Så i exemplet ovan kan användaren definiera en ny spårare i sitt skript och koppla den till en befintlig spårningskälla definierad i simuleringskärnan endast genom att redigera användarskriptet.

I den här handledningen går vi igenom några av de fördefinierade källorna och sänkorna och visar hur de kan konfigureras med minsta möjliga ansträngning från användarens sida. Se ns-3-manualen eller instruktionssektionerna för information om avancerad spårningskonfiguration, inklusive att utöka spårningsnamnutrymmet och skapa nya spårningskällor.

5.3.1 ASCII-spårning

ns-3 tillhandahåller hjälpfunktioner som ger ett spårningssystem på låg nivå för att hjälpa dig med detaljerna när du ställer in enkla paketspårningar. Om du aktiverar den här funktionen kommer du att se utdata i ASCII-filer. För de som är bekanta med ns-2-utgång liknar denna typ av spårning ut.tr, som genereras av många skript.

Låt oss börja jobba och lägga till några ASCII-spårningsresultat till vårt scratch/myfirst.cc-skript. Precis innan samtalet Simulator :: Run (), lägg till följande kodrader:
AsciiTraceHelper ascii;

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

Liksom många andra ns-3 idiom använder den här koden ett hjälpobjekt för att skapa ASCII-spår. Den andra raden innehåller två kapslade metodanrop. "Inside"-metoden CreateFileStream() använder det anonyma objektspråket för att skapa ett filströmsobjekt på stacken (utan ett objektnamn) och skickar det till den anropade metoden. Vi kommer att gå djupare in på detta i framtiden, men allt du behöver veta just nu är att du skapar ett objekt som representerar en fil som heter myfirst.tr och överför den till ns-3. Vi anförtror ns-3 att ta hand om det skapade objektet under hela dess livstid, under vilket det löser problem som orsakas av en föga känd (avsiktlig) begränsning associerad med C++-strömobjektkopieringskonstruktörer.

Externt samtal EnableAsciiAll() talar om för assistenten att du vill inkludera ASCII-spårning i din simulering för alla punkt-till-punkt-enhetsanslutningar och att du vill att (specificerade) spårningsmottagare ska registrera paketrörelseinformation i ASCII-format.

För de som är bekanta med ns-2 är spårade händelser ekvivalenta med de kända spårpunkterna som loggar händelser "+", "-", "d" och "r".
Nu kan du bygga skriptet och köra det från kommandoraden:

$ ./waf --run scratch/myfirst

Som många gånger tidigare kommer du att se flera meddelanden från Waf, och sedan "bygga" färdigt med några meddelanden från det pågående programmet.

När programmet körs skapar programmet en fil med namnet myfirst.tr. På grund av arbetets karaktär WAF, som standard skapas filen inte i den lokala katalogen, utan i den översta katalogen i förvaret. Om du vill ändra sökvägen där spåren sparas, kan du använda parametern Waf för att specificera den --cwd. Vi har inte gjort det här, så för att titta på ASCII-spårningsfilen myfirst.tr i din favoritredigerare måste vi navigera till katalogen på toppnivån i vårt arkiv.

Parsar ASCII-spår

Det finns mycket information där i en ganska tät form, men det första du behöver lägga märke till är att filen består av enskilda rader. Detta blir tydligt om du utökar visningsfönstret bredare.

Varje rad i filen motsvarar en spårningshändelse. I det här fallet spårar vi händelser i överföringskön som finns i varje punkt-till-punkt nätverksenhet i simuleringen. Sändningskön är den kö genom vilken varje paket måste passera för en punkt-till-punkt-länk. Observera att varje rad i spårningsfilen börjar med ett enda tecken (och har ett mellanslag efter sig). Denna symbol kommer att ha följande betydelse:

+: en köoperation inträffade på enhetskön;
-: en elementhämtningsoperation inträffade i enhetskön;
d: paketet släpptes, vanligtvis för att kön var full;
r: Paketet togs emot av en nätverksenhet.

Låt oss ta en närmare titt på den första raden i spårningsfilen. Jag delar upp det i delar (med indrag för tydlighetens skull) och radnumret till vänster:

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)

Den första delen av denna utökade spårningshändelse (rad 0) är operationen. Vi har en +-symbol här, vilket motsvarar driften av att köa för överföring. Den andra sektionen (rad 1) är simuleringstiden, uttryckt i sekunder. Du kanske kommer ihåg vad vi frågade UdpEchoClientApplication börja skicka paket om två sekunder. Här ser vi en bekräftelse på att detta verkligen sker.

Nästa avsnitt av spårningsexemplet (från rad 2) visar vilken spårningskälla som genererade denna händelse (som indikerar namnområdesspåret). Du kan tänka på spårningsnamnutrymmet ungefär som ett filsystemnamnområde. Roten till namnutrymmet är NodeList. Detta motsvarar behållaren som hanteras i ns-3-huvudkoden. Den innehåller alla noder som skapas i skriptet. Precis som ett filsystem kan ha kataloger i roten, NodeList vi kan ha många noder. Så raden /NodeList/0 refererar till nollnoden i NodeList, som vi vanligtvis tänker på som "nod 0". Varje nod har en lista över enheter som har installerats. Den här listan finns bredvid i namnområdet. Du kan se att denna spårhändelse kommer från Enhetslista/0, som är nollenheten som är installerad i noden.

Nästa delsträng, $ ns3 :: PointToPointNetDevice, talar om vilken enhet som är i position noll: enhetslistan för nod noll. Kom ihåg att +-operationen på rad 0 innebar att ett element lades till enhetens sändningskö. Detta återspeglas i de sista segmenten av "spårvägen": TxQueue/Enqueue.

De återstående avsnitten i spåret bör vara ganska intuitiva. Raderna 3-4 indikerar att paketet är inkapslat i ett punkt-till-punkt-protokoll. Raderna 5-7 visar att paketet har en IP4-versionshuvud och har sitt ursprung i IP-adressen 10.1.1.1 och avsedd för 10.1.1.2. Raderna 8-9 visar att detta paket har ett UDP-huvud och slutligen visar rad 10 att nyttolasten är de förväntade 1024 byte.

Nästa rad i spårningsfilen visar att samma paket drogs från överföringskön på samma nod.

Den tredje raden i spårningsfilen visar att paketet togs emot av en nätverksenhet på ekoservervärden. Jag har återgett händelsen nedan.

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)

Observera att spårningsoperationen nu är r och simuleringstiden har ökat till 2,25732 sekunder. Om du följde handledningen noggrant betyder det att du lämnade nätverksenheternas DataRate och Link Delay på deras standardvärden. Denna tid bör vara bekant, som du såg i föregående avsnitt.

Spårkällans namnområdespost (rad 2) har modifierats för att återspegla att denna händelse kommer från nod 1 (/NodeList/1) och paketet tas emot av spårkällan (/MacRx). Det borde vara ganska enkelt för dig att följa paketets rörelse genom topologin genom att titta på de återstående spåren i filen.

5.3.2 PCAP-spårning

ns-3 Device Helpers kan också användas för att skapa spårningsfiler i .pcap-format. Akronym pcap (vanligtvis skrivet med gemener) står för packet capture och är faktiskt ett API som inkluderar definition av .pcap-filformatet. Det mest populära programmet som kan läsa och visa detta format är Wireshark (kallades tidigare Eterisk). Det finns dock många trafikspårningsanalysatorer som använder detta paketformat. Vi uppmuntrar användare att använda de många tillgängliga verktygen för att analysera pcap-spår. I den här handledningen kommer vi att fokusera på att se pcap-spår med hjälp av tcpdump.

Aktivering av pcap-spårning görs med en rad kod.

pointToPoint.EnablePcapAll ("myfirst");

Klistra in denna kodrad efter ASCII-spårningskoden som vi precis lade till scratch/myfirst.cc. Observera att vi bara skickade strängen "myfirst", inte "myfirst.pcap" eller något liknande. Detta beror på att parametern är ett prefix, inte ett fullständigt filnamn. Under simuleringen kommer assistenten faktiskt att skapa en spårningsfil för varje punkt-till-punkt-enhet. Filnamn kommer att konstrueras med prefix, nodnummer, enhetsnummer och suffix ".pcap".

För vårt exempelskript kommer vi att se filer med namnet "myfirst-0-0.pcap"Och"myfirst-1-0.pcap", som är pcap-spår för nod 0-enhet 0 respektive nod 1-enhet 0. När du har lagt till kodraden för att aktivera pcap-spårning kan du köra skriptet på vanligt sätt:

$ ./waf --run scratch/myfirst

Om du tittar i den översta katalogen i din distribution bör du se tre filer: en ASCII-spårningsfil myfirst.tr, som vi tidigare studerat, filer myfirst-0-0.pcap и myfirst-1-0.pcap - nya pcap-filer som vi just genererat.

Läser utdata med tcpdump

För närvarande är det enklaste sättet att visa pcap-filer att använda 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 1024

I soptippen myfirst-0-0.pcap (klientenhet) kan du se att ekopaketet skickas efter 2 sekunders simulering. Om du tittar på den andra soptippen (myfirst-1-0.pcap), kommer du att se att paketet tas emot vid 2,257324 sekunder. Du kommer att se i den andra dumpningen att paketet returneras vid 2.257324 sekunder, och slutligen att paketet togs emot tillbaka av klienten i den första dumpningen vid 2.514648 sekunder.

Läsutgång med Wireshark

Om du inte är bekant med Wireshark, det finns en webbplats från vilken du kan ladda ner program och dokumentation: http://www.wireshark.org/. Wireshark är ett GUI som kan användas för att visa dessa spårningsfiler. Om du har Wireshark kan du öppna någon av spårningsfilerna och visa innehållet som om du hade fångat paketen med en paketsniffer.

Källa: will.com

Lägg en kommentar