Урок за симулатор на мрежа ns-3. Глава 5

Урок за симулатор на мрежа ns-3. Глава 5
глава 1,2
Глава 3
Глава 4

5 Настройки
5.1 Използване на модула за регистриране
5.1.1 Преглед на регистриране
5.1.2 Активиране на регистриране
5.1.3 Добавяне на регистриране към вашия код
5.2 Използване на аргументи от командния ред
5.2.1 Замяна на стойностите на атрибутите по подразбиране
5.2.2 Улавяне на вашите собствени команди
5.3 Използване на системата за проследяване
5.3.1 ASCII проследяване
Разбор на ASCII следи
5.3.2 Проследяване на PCAP

Глава 5

регулиране

5.1 Използване на модула за регистриране

Вече разгледахме накратко модула за регистриране ns-3, като разгледахме скрипта първо.cc. В тази глава ще разгледаме по-подробно възможните приложения на подсистемата за регистриране.

5.1.1 Преглед на регистриране

Много големи системи поддържат някакво средство за регистриране на съобщения и ns-3 не е изключение. В някои случаи само съобщения за грешка се записват в "операторската конзола" (която обикновено е stderr на Unix-базирани системи). На други системи може да се показват предупредителни съобщения, както и по-подробна информация. В някои случаи се използват инструменти за регистриране за извеждане на съобщения за отстраняване на грешки, които могат бързо да замъглят изхода.

SubHRD, използван в ns-3, предполага, че всички тези нива на информационно съдържание са полезни и ние предоставяме селективен, многослоен подход към регистриране на съобщения. Регистрирането може да бъде деактивирано напълно, активирано за всеки компонент или глобално. За тази цел се използват регулируеми нива на информационно съдържание. Модулът за регистриране ns-3 предоставя сравнително лесен начин за получаване на полезна информация от вашата симулация.

Трябва да разберете, че ние предоставяме механизъм с общо предназначение – проследяване – за извличане на данни от вашите модели, което трябва да бъде предпочитаният изход за симулации (за повече информация относно нашата система за проследяване вижте раздел 5.3 на урока). Регистрирането трябва да бъде предпочитаният метод за получаване на информация за отстраняване на грешки, предупреждения, съобщения за грешки или за бързо извеждане на съобщения от вашите скриптове или модели по всяко време.

Понастоящем системата дефинира седем нива (типа) на регистрационните съобщения в нарастващ ред на информационното съдържание.

  • LOG_ERROR - регистриране на съобщения за грешки (свързан макрос: NS_LOG_ERROR);
  • LOG_WARN - Регистрирайте предупредителни съобщения (свързан макрос: NS_LOG_WARN);
  • LOG_DEBUG - Регистрирайте сравнително редки специални съобщения за отстраняване на грешки (свързан макрос: NS_LOG_DEBUG);
  • LOG_INFO - регистриране на информационни съобщения за напредъка на програмата (свързан макрос: NS_LOG_INFO);
  • LOG_FUNCTION - Регистрира съобщения, описващи всяка извикана функция (два свързани макроса: NS_LOG_FUNCTION, използван за членски функции, и NS_LOG_FUNCTION_NOARGS, използван за статични функции);
  • LOG_LOGIC - регистриране на съобщения, описващи логическия поток в рамките на функция (свързан макрос: NS_LOG_LOGIC);
  • LOG_ALL - Регистрира всичко, споменато по-горе (без свързан макрос).
    За всеки тип (LOG_TYPE) има и LOG_LEVEL_TYPE, който, ако се използва, позволява всички нива над него да бъдат регистрирани в допълнение към неговото собствено ниво. (Вследствие на това LOG_ERROR и LOG_LEVEL_ERROR, и LOG_ALL и LOG_LEVEL_ALL са функционално еквивалентни.) Например активирането на LOG_INFO ще позволи само съобщения, предоставени от макроса NS_LOG_INFO, докато активирането на LOG_LEVEL_INFO ще включва също съобщения, предоставени от макросите NS_LOG_DEBUG, NS_LOG_WARN и NS_LOG_ERROR.

Ние също така предоставяме безусловен макрос за регистриране, който винаги се показва, независимо от нивото на регистриране или компонента за избор.

  • NS_LOG_UNCOND - Безусловно регистриране на свързаното съобщение (без свързано ниво на регистриране).

Всяко ниво може да бъде заявено индивидуално или кумулативно. Регистрирането може да бъде конфигурирано с помощта на променливата на средата sh NS_LOG или чрез регистриране на извикване на системна функция. Както беше показано по-рано, системата за регистриране има документация на Doxygen и сега е подходящ момент да я прегледате, ако още не сте го направили.

Сега, след като прочетохте документацията много подробно, нека използваме това знание, за да извлечем интересна информация от примерния скрипт scratch/myfirst.ccкоито вече сте съставили.

5.1.2 Активиране на регистриране

Нека използваме променливата на средата NS_LOG, за да стартираме още регистрационни файлове, но първо, само за да се ориентирате, изпълнете последния скрипт, както направихте по-рано,

$ ./waf --run scratch/myfirst

Трябва да видите познатия изход от първата примерна програма 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.2

Оказва се, че „изпратените“ и „получените“ съобщения, които виждате по-горе, всъщност са регистрирани съобщения от UdpEchoClientApplication и UdpEchoServerApplication. Например, можем да поискаме от клиентското приложение да отпечата допълнителна информация, като зададе нивото на регистриране чрез променливата на средата NS_LOG.

Отсега нататък ще приема, че използвате sh-подобна обвивка, която използва синтаксиса "VARIABLE=value". Ако използвате обвивка, подобна на csh, тогава ще трябва да преобразувате моите примери в синтаксиса "setenv променлива стойност", изискван от тези обвивки.

В момента UDP ехо клиентското приложение отговаря на следния ред код в scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Той позволява нивото на регистриране LOG_LEVEL_INFO. Когато подадем флаг за ниво на регистриране, ние всъщност активираме това ниво и всички по-ниски нива. В този случай сме активирали NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN и NS_LOG_ERROR. Можем да увеличим нивото на регистриране и да получим повече информация, без промени в скрипта и повторно компилиране, като зададем променливата на средата NS_LOG, както следва:

$ export NS_LOG=UdpEchoClientApplication=level_all

Така че задаваме променливата на sh shell NS_LOG на следната стойност,

UdpEchoClientApplication=level_all

Лявата страна на присвояването е името на регистрирания компонент, който искаме да конфигурираме, а дясната страна е флагът, който искаме да приложим за него. В този случай ще активираме всички нива на отстраняване на грешки в приложението. Ако изпълните скрипта с NS_LOG, зададен по този начин, системата за регистриране на 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.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()

Допълнителната информация за отстраняване на грешки, предоставена от приложението, вече е на ниво NS_LOG_FUNCTION. Той показва всеки екземпляр на извикване на функция по време на изпълнение на скрипт. Като общо правило, във функциите на метода е за предпочитане да се използва (най-малко)NS_LOG_FUNCTION (this)... Използвайте NS_LOG_FUNCTION_NOARGS ()
само в статични функции. Обърнете внимание обаче, че не се изисква системата ns-3 да поддържа каквато и да е функция за регистриране. Решението за това колко информация се записва е оставено на отделния разработчик на модела. В случай на ехо приложения е налично голямо количество изход за регистриране.

Вече можете да видите регистър на извикванията на функции, направени от приложението. Ако се вгледате внимателно, ще забележите двоеточие между реда UdpEchoClientApplication и името на метода, където може да очаквате да видите C++ оператора за обхват (: :). Това е умишлено.

Това всъщност не е името на класа, а името на компонента за регистриране. Когато има съвпадение между изходен файл и клас, това обикновено е името на класа, но трябва да разберете, че всъщност не е името на класа и има едно двоеточие вместо двойно двоеточие. Това е начин да ви помогне концептуално да отделите името на регистриращия компонент от името на класа по сравнително фин начин.

В някои случаи обаче може да е трудно да се определи кой метод всъщност генерира съобщението в журнала. Ако погледнете текста по-горе, може би се чудите къде е редът "Received 1024 bytes from 10.1.1.2" Можете да разрешите този проблем, като зададете нивото prefix_func към променливата на средата NS_LOG. Опитайте следното:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Имайте предвид, че кавичките са необходими, тъй като вертикалната лента, която използваме за представяне на операцията ИЛИ, също е Unix конектор за тръба. Сега, ако стартирате скрипта, ще видите, че системата за регистриране гарантира, че всяко съобщение в даден журнал има префикс с името на компонента.

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

Сега можете да видите, че всички съобщения, идващи от клиентското приложение UDP echo, се идентифицират като такива. съобщение "Received 1024 bytes from 10.1.1.2" вече е ясно идентифициран като идващ от клиентското приложение за ехо. Оставащото съобщение трябва да идва от приложението на UDP ехо сървъра. Можем да активираме този компонент, като въведем разделен с двоеточие списък с компоненти в променливата на средата NS_LOG.

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

Предупреждение: В примерния текст по-горе ще трябва да премахнете знака за нов ред след двоеточието (:), той се използва за форматиране на документа. Сега, ако стартирате скрипта, ще видите всички регистрационни съобщения от приложенията за ехо на клиента и сървъра. Можете да видите, че това може да бъде много полезно при отстраняване на грешки.

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

Също така понякога е полезно да можете да видите времето на симулация, в което е генерирано лог съобщението. Можете да направите това, като добавите бита ИЛИ префикс_време:

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

Отново ще трябва да премахнете горния знак за нов ред. Ако сега стартирате скрипта, трябва да видите следния резултат:

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

Моля, имайте предвид, че конструкторът за UdpEchoServer беше извикан по време на симулация 0 секунди. Това всъщност се случва преди симулацията да започне, но времето се показва като нула секунди. Същото важи и за съобщението на конструктора 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()

Припомнете си, че сценарият драскотина/първо.cc стартира приложението на ехо сървъра една секунда преди началото на симулацията. Сега можете да видите, че методът Стартиране на приложението сървърът всъщност се извиква през първата секунда. Може също да забележите, че ехо клиентът стартира през втората секунда на симулацията, както поискахме в скрипта.

Вече можете да следите напредъка на симулацията при повикване ScheduleTransmit в клиента, който извиква обратното извикване HandleRead Send в приложението на ехо сървъра. Имайте предвид, че изминалото време за изпращане на пакет по връзка от точка до точка е 3,69 милисекунди. Можете да видите, че ехо сървърът регистрира съобщение, че е отговорил на пакета, и след това, след забавяне на канала, виждате, че ехо клиентът получава ехо пакета в своя метод HandleRead.

В тази симулация много неща се случват, без да забележите. Но можете да проследите целия процес много лесно, като активирате всички компоненти за регистриране в системата. Опитайте да зададете променливата NS_LOG на следната стойност,

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

Звездицата по-горе е заместващ знак за компонента за регистриране. Това ще включва всички записи във всички компоненти, използвани в симулацията. Няма да възпроизвеждам изхода тук (по време на писането той произвежда 1265 реда изход за един ехо пакет), но можете да пренасочите тази информация към файл и да го видите в любимия си редактор.

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

Аз лично използвам тази изключително многословна версия на регистриране, когато имам проблем и нямам представа къде нещата са се объркали. Мога да следя изпълнението на кода доста лесно, без да задавам точки на прекъсване и да преминавам през кода в програмата за отстраняване на грешки. Мога просто да редактирам резултата в любимия си редактор и да търся това, което очаквам, и да видя да се случва нещо, което не съм очаквал. След като имам обща представа какво не е наред, скачам в програмата за отстраняване на грешки, за да се задълбоча в проблема. Този тип изход може да бъде особено полезен, когато вашият скрипт направи нещо напълно неочаквано. Ако използвате само програмата за отстраняване на грешки, може да пропуснете изцяло обрат. Регистрацията прави такива обрати забележими.

5.1.3 Добавяне на регистриране към вашия код

Можете да добавяте нови записи към вашите симулации, като правите повиквания към компонента на регистрационния файл от множество макроси. Нека го направим в скрипт myfirst.cc, който имаме в директорията „чист“. Спомнете си, че дефинирахме компонент за регистриране в този сценарий:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Знаете, че можете да разрешите записването на всички съобщения от този компонент, като зададете променливата на средата NS_LOG на различни нива. Нека да продължим и да добавим някои записи към скрипта. Макросът, използван за добавяне на съобщения на ниво информация към журнала, е NS_LOG_INFO. Нека добавим съобщение (точно преди да започнем да създаваме възли), което ви казва, че скриптът е във фаза „Създаване на топология“. Това се прави в следния кодов фрагмент,
Отворен scratch/myfirst.cc в любимия си редактор и добавете реда,
NS_LOG_INFO ("Creating Topology");
точно преди редовете,

NodeContainer nodes;
nodes.Create (2);

Сега компилирайте скрипта, като използвате WAFи изчистете променливата NS_LOG, за да деактивирате потока за регистриране, който активирахме по-рано:

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

Няма да видите новото съобщение, защото свързаният компонент за регистриране (FirstScriptExample) не е активиран. За да видите вашето съобщение, трябва да активирате компонента за регистриране FirstScriptExample с ниво не по-ниско от NS_LOG_INFO. Ако просто искате да видите това конкретно ниво на регистриране, можете да го активирате по този начин,

$ export NS_LOG=FirstScriptExample=info

Ако стартирате скрипта сега, ще видите ново съобщение „Създаване на топология“,

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 Използване на аргументи от командния ред

5.2.1 Замяна на стойностите на атрибутите по подразбиране

Друг начин да промените поведението на ns-3 скриптове без редактиране или изграждане е да използвате аргументи на командния ред. Предоставяме механизъм за анализиране на аргументите на командния ред и автоматично задаване на локални и глобални променливи въз основа на резултатите.

Първата стъпка в използването на системата от аргументи на командния ред е да декларирате парсер на командния ред. Това е доста лесно да се направи (във вашата основна програма), както в следния код,

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

Този прост двуредов фрагмент всъщност е много полезен сам по себе си. Той отваря вратата към системата за глобални променливи и атрибути ns-3. Нека добавим два реда код в началото на функцията на главния скрипт scratch/myfirst.cc. Продължавайки напред, компилираме скрипта и го стартираме, когато стартираме, правим заявка за помощ, както следва,

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

Тази команда ще попита Waf стартирайте скрипт драскотина/myfirst и му предайте аргумент на командния ред — PrintHelp. Кавичките са необходими, за да покажат за коя програма е предназначен аргументът. Анализаторът на командния ред ще открие аргумента — 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.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.

Сега нека да разгледаме опцията — PrintAttributes. Вече споменахме системата за атрибути ns-3, когато изучавахме скрипта first.cc. Видяхме следните редове код,

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

и те казаха това Скорост на данните всъщност е атрибут PointToPointNetDevice. Нека използваме анализатора на аргументите на командния ред, за да видим атрибутите PointToPointNetDevice. Помощният списък казва какво трябва да предоставим TypeId. Това е името на класа, към който принадлежат интересуващите ни атрибути. В нашия случай ще бъде ns3::PointToPointNetDevice. Нека продължим напред, влезте,

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

Системата ще отпечата всички атрибути на този тип мрежово устройство. Ще видите, че сред атрибутите в списъка са,

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

Това е стойността по подразбиране, която ще се използва от системата при създаване на обекта PointToPointNetDevice. Ние ще заменим тази стойност по подразбиране с помощта на параметъра Атрибут в PointToPointHelper по-висок. Нека използваме стойностите по подразбиране за устройства и канали от точка до точка. За целта ще изтрием обажданията SetDeviceAttribute и SetChannelAttribute на myfirst.cc, които имаме в чиста директория.

Сега вашият скрипт трябва просто да декларира PointToPointHelper и не извършвайте никакви инсталационни операции, както е показано в примера по-долу,

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

Продължете и създайте нов скрипт с Waf (./waff) и нека се върнем и да включим някакъв запис от приложението на UDP ехо сървъра и да включим префикса за време.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Ако стартирате скрипта, трябва да видите следния резултат:

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

Спомнете си, че последният път, когато погледнахме времето за симулация, моментът, в който пакетът беше получен от ехо сървъра, беше 2,00369 секунди.

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

Сега той получава пакета за 2.25732 секунди. Това е така, защото ние просто нулираме скоростта на данни на PointToPointNetDevice от пет мегабита в секунда до стойността по подразбиране, която е 32768 бита в секунда. Ако трябваше да заменим нов DataRate с помощта на командния ред, бихме могли отново да ускорим нашата симулация. Ще направим това, както следва, съгласно формулата, подразбираща се от помощния елемент:

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

Това ще върне атрибута DataRate към стойността му по подразбиране от пет мегабита в секунда. Изненадан ли си от резултата? Оказва се, че за да върнем първоначалното поведение на скрипта, също трябва да настроим забавянето на канала да съответства на скоростта на светлината. Можем да поискаме от системата на командния ред да отпечата атрибутите на канала, точно както направихме за мрежовото устройство:

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

Ще открием, че атрибутът за забавяне на канала е зададен както следва:

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

След това можем чрез системата на командния ред да зададем и двете стойности по подразбиране.

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

в този случай ние възстановяваме времето, което имахме, когато изрично зададохме DataRate и Delay в скрипта:

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

Имайте предвид, че пакетът се получава от сървъра отново след 2,00369 секунди. Всъщност можем да зададем всеки от атрибутите, използвани в скрипта по този начин. По-специално, бихме могли да зададем атрибутите MaxPackets на стойности, различни от едно UdpEchoClient.

Как бихте го използвали? Пробвам. Не забравяйте, че трябва да коментирате мястото, където заместваме и изрично задаваме стойността на атрибута по подразбиране MaxPackets в сценария. След това трябва да изградите отново скрипта. Можете също да използвате командния ред, за да получите помощ за синтаксиса за задаване на нова стойност на атрибут по подразбиране. След като разберете това, можете да контролирате броя на пакетите, показвани в командния ред. Тъй като ние сме ученолюбиви хора, нашият команден ред трябва да изглежда по следния начин:

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

Естественият въпрос, който възниква в този момент, е как да разберем за съществуването на всички тези атрибути. Отново системата на командния ред има помощна функция по този въпрос. Ако поискаме помощ от командния ред, трябва да видим:

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

Ако изберете аргумента "PrintGroups", трябва да видите списък с всички регистрирани групи TypeId. Имената на групите съответстват на имената на модулите в изходната директория (макар и с главни букви). Отпечатването на цялата информация наведнъж би било твърде обемно, затова е наличен допълнителен филтър за отпечатване на информация по групи. И така, отново се фокусираме върху модула от точка до точка:

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

Тук можете да намерите налични имена на TypeId за търсения на атрибути, например в
--PrintAttributes = ns3 :: PointToPointChannelкакто е показано по-горе.

Друг начин да научите за атрибутите е чрез Doxygen ns‑3. Има страница, която изброява всички атрибути, регистрирани в симулатора.

5.2.2 Улавяне на вашите собствени команди

Можете също да добавите свои собствени кукички чрез системата на командния ред. Това се прави съвсем просто с помощта на метода на анализатора на командния ред Добави стойност.
Нека използваме тази функция, за да определим броя на пакетите, които да се показват по напълно различен начин. Нека добавим локална променлива, наречена nPackets във функция основен. Ще го зададем на едно, за да съответства на предишното ни поведение по подразбиране. За да позволим на анализатора на командния ред да промени тази стойност, трябва да уловим тази стойност в анализатора. Правим това, като добавим обаждане Добави стойност. Отиди и смени сценария scratch/myfirst.cc така че да започнем със следния код,

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

Превъртете надолу до точката в скрипта, където задаваме атрибута MaxPackets, и го променете, така че да е зададен на променливата nPackets вместо константата 1, както е показано по-долу.

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

Сега, ако изпълните скрипта и предоставите аргумента -PrintHelp, трябва да видите новия потребителски аргумент. изброени на екрана за помощ. въведете,

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

Ако искате да промените броя на предадените пакети, можете да го направите, като зададете аргумента на командния ред - -nPackets.

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

Сега трябва да видите

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

Сега изпратихте два пакета. Доста просто, нали?
Можете да видите, че като потребител на ns-3 можете да използвате системата от аргументи на командния ред, за да манипулирате глобалните стойности и атрибути. Ако вие сте авторът на модела, можете да добавите нови атрибути към вашите обекти и те ще бъдат автоматично достъпни за конфигуриране от вашите потребители чрез системата на командния ред. Ако сте автор на скрипт, можете да добавяте нови променливи към вашите скриптове и безпроблемно да ги включвате в системата на командния ред.

5.3 Използване на системата за проследяване

Целият смисъл на моделирането е да се генерират изходни данни за по-нататъшно изследване, а системата за проследяване ns-3 е основният механизъм за това. Тъй като ns-3 е C++ програма, могат да се използват стандартни средства за генериране на изход от C++ програма:

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

Можете дори да използвате модул за регистриране, за да добавите малко структура към вашето решение. Има много известни проблеми, причинени от този подход, и затова сме предоставили обща подсистема за проследяване на събития за разрешаване на тези проблеми.

Основните цели на системата за проследяване ns-3 са:

  • За основни задачи системата за проследяване трябва да позволява на потребителя да генерира стандартно проследяване за популярни източници и да избира обекти, които генерират проследяването;

  • Междинните потребители трябва да могат да разширят системата за проследяване, за да променят генерирания изходен формат или да вмъкват нови източници на проследяване, без да променят ядрото на симулатора;

  • Напредналите потребители могат да променят ядрото на симулатора, за да добавят нови източници и приемници на трасиране. Системата за проследяване ns-3 е изградена на принципите на независими източници и приемници за проследяване, както и унифициран механизъм за свързване на източници с потребители.

Системата за проследяване ns-3 е изградена на принципите на независими източници и приемници за проследяване, както и унифициран механизъм за свързване на източници към приемници. Източниците на проследяване са обекти, които могат да сигнализират за събития, възникващи в симулацията, и да осигурят достъп до основните данни, представляващи интерес. Например, източник на проследяване може да посочи кога мрежово устройство е получило пакет и да направи съдържанието на пакета достъпно за заинтересованите получатели на проследяване.

Източниците на проследяване сами по себе си са безполезни, освен ако не са "свързани" с други части на кода, които действително правят нещо полезно с информацията, предоставена от приемника. Трасерите са потребители на събития и данни, предоставени от източници на проследяване. Например, можете да създадете приемник на проследяване, който (когато е свързан към източника на проследяване от предишния пример) ще отпечата интересните части в получения пакет.

Обосновката за това изрично разделяне е да се позволи на потребителите да свързват нови типове приемници към съществуващи източници на проследяване, без да се налага да редактират и прекомпилират ядрото на симулатора. Така че в примера по-горе потребителят може да дефинира нов инструмент за проследяване в своя скрипт и да го свърже към съществуващ източник на проследяване, дефиниран в ядрото на симулацията, само чрез редактиране на потребителския скрипт.

В този урок ще разгледаме някои от предварително дефинираните източници и приемници и ще покажем как те могат да бъдат конфигурирани с най-малко усилия от страна на потребителя. Вижте ръководството за ns-3 или разделите с инструкции за информация относно разширена конфигурация на проследяване, включително разширяване на пространството на имената на проследяване и създаване на нови източници на проследяване.

5.3.1 ASCII проследяване

ns-3 предоставя помощна функционалност, която предоставя система за проследяване на ниско ниво, за да ви помогне с подробностите, когато настройвате прости проследявания на пакети. Ако активирате тази функция, ще видите изхода в ASCII файлове. За тези, които са запознати с изхода ns-2, този тип проследяване е подобен на out.tr, който се генерира от много скриптове.

Нека да се заемем с работата и да добавим някои ASCII проследяващи резултати към нашия скрипт scratch/myfirst.cc. Точно преди обаждането Simulator :: Run (), добавете следните редове код:
AsciiTraceHelper ascii;

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

Подобно на много други ns-3 идиоми, този код използва помощен обект за създаване на ASCII следи. Вторият ред съдържа две вложени извиквания на метод. Метод "вътре". CreateFileStream() използва идиома на анонимния обект, за да създаде обект на файлов поток в стека (без име на обект) и го предава на извикания метод. Ще се задълбочим в това в бъдеще, но всичко, което трябва да знаете на този етап е, че създавате обект, който представлява файл, наречен myfirst.tr и го прехвърлете на ns-3. Ние поверяваме на ns-3 да се грижи за създадения обект през целия му живот, през който той решава проблеми, причинени от малко известно (умишлено) ограничение, свързано с конструкторите за копиране на обекти на поток C++.

Външно повикване EnableAsciiAll() казва на асистента, че искате да включите ASCII проследяване във вашата симулация за всички връзки на устройство от точка до точка и че искате (посочени) приемници за проследяване да записват информация за движението на пакети в ASCII формат.

За тези, които са запознати с ns-2, проследяваните събития са еквивалентни на известните точки за проследяване, които регистрират събития "+", "-", "d" и "r".
Сега можете да създадете скрипта и да го стартирате от командния ред:

$ ./waf --run scratch/myfirst

Както много пъти преди, ще видите няколко съобщения от Waf и след това „„изграждането“ завърши успешно“ с някои съобщения от работещата програма.

Когато работи, програмата ще създаде файл с име myfirst.tr. Поради естеството на работата Waf, по подразбиране файлът се създава не в локалната директория, а в директорията от най-високо ниво на хранилището. Ако искате да промените пътя, където се записват следите, тогава можете да използвате параметъра Waf, за да го посочите --cwd. Не сме направили това, така че за да разгледаме ASCII проследяващия файл myfirst.tr в любимия ви редактор, ще трябва да отидем до директорията от най-високо ниво на нашето хранилище.

Разбор на ASCII следи

Там има много информация в доста плътна форма, но първото нещо, което трябва да забележите е, че файлът се състои от отделни редове. Това ще стане ясно видимо, ако разширите прозореца за гледане.

Всеки ред във файла съответства на събитие за проследяване. В този случай ние проследяваме събития в опашката за предаване, присъстващи във всяко мрежово устройство от точка до точка в симулацията. Опашката за предаване е опашката, през която трябва да премине всеки пакет за връзка от точка до точка. Имайте предвид, че всеки ред във файла за проследяване започва с един знак (и има интервал след него). Този символ ще има следното значение:

+: извършена е операция на опашка на опашката на устройството;
-: извършена е операция за извличане на елемент в опашката на устройството;
d: пакетът е изпуснат, обикновено защото опашката е пълна;
r: Пакетът е получен от мрежово устройство.

Нека разгледаме по-отблизо първия ред във файла за проследяване. Ще го разделя на части (с вдлъбнатини за яснота) и номера на реда отляво:

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)

Първият раздел на това разширено събитие за проследяване (ред 0) е операцията. Тук имаме символ +, който съответства на операцията на опашка за предаване. Вторият раздел (ред 1) е времето за симулация, изразено в секунди. Може би си спомняте какво питахме UdpEchoClientApplication започнете да изпращате пакети след две секунди. Тук виждаме потвърждение, че това наистина се случва.

Следващият раздел на примера за проследяване (от ред 2) показва кой източник на проследяване е генерирал това събитие (посочвайки проследяването на пространството от имена). Можете да мислите за пространството от имена на трасиране много като пространство от имена на файлова система. Коренът на пространството от имена е NodeList. Това съответства на контейнера, управляван в основния код ns-3. Той съдържа всички възли, които са създадени в скрипта. Точно както файловата система може да има директории в основата си, NodeList можем да имаме много възли. Така че редът /NodeList/0 се отнася до нулевия възел в NodeList, който обикновено смятаме за "възел 0". Всеки възел има списък с устройства, които са инсталирани. Този списък се намира следващият в пространството на имената. Можете да видите, че това проследяващо събитие идва от Списък на устройствата/0, което е нулевото устройство, инсталирано в възела.

Следващ подниз, $ ns3 :: PointToPointNetDevice, казва кое устройство е на позиция нула: списъкът с устройства на възел нула. Спомнете си, че операцията +, намерена в ред 0, означава, че е добавен елемент към опашката за предаване на устройството. Това е отразено в последните сегменти на „трасето“: TxQueue/Enqueue.

Останалите секции в проследяването трябва да са доста интуитивни. Редове 3-4 показват, че пакетът е капсулиран в протокол от точка до точка. Редове 5-7 показват, че пакетът има заглавка на IP4 версия и произхожда от IP адреса 10.1.1.1 и е предназначен за 10.1.1.2. Редове 8-9 показват, че този пакет има UDP хедър и накрая ред 10 показва, че полезният товар е очакваните 1024 байта.

Следващият ред във файла за проследяване показва, че същият пакет е бил изтеглен от опашката за предаване на същия възел.

Третият ред във файла за проследяване показва, че пакетът е получен от мрежово устройство на хоста на ехо сървъра. Възпроизвеждам събитието по-долу.

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)

Имайте предвид, че операцията за проследяване вече е r и времето за симулация е увеличено до 2,25732 секунди. Ако сте следвали внимателно урока, това означава, че сте оставили DataRate и Link Delay на мрежовите устройства на техните стойности по подразбиране. Това време трябва да ви е познато, както видяхте в предишния раздел.

Записът в пространството от имена на източника на проследяване (ред 2) е променен, за да отрази, че това събитие произхожда от възел 1 (/NodeList/1) и пакетът се получава от източника на проследяване (/MacRx). Трябва да ви е сравнително лесно да проследите движението на пакета през топологията, като погледнете останалите следи във файла.

5.3.2 Проследяване на PCAP

Помощниците за устройства ns-3 могат също да се използват за създаване на файлове за проследяване във формат .pcap. акроним pcap (обикновено се пише с малки букви) означава улавяне на пакети и всъщност е API, който включва дефиниране на файловия формат .pcap. Най-популярната програма, която може да чете и показва този формат е Wireshark (наричан по-рано ефирен). Има обаче много анализатори за проследяване на трафика, които използват този пакетен формат. Насърчаваме потребителите да използват многото налични инструменти за анализиране на pcap следи. В този урок ще се съсредоточим върху прегледа на pcap следи с помощта на tcpdump.

Активирането на проследяването на pcap се извършва с един ред код.

pointToPoint.EnablePcapAll ("myfirst");

Поставете този ред код след ASCII кода за проследяване, който току-що добавихме scratch/myfirst.cc. Имайте предвид, че предадохме само низа "myfirst", а не "myfirst.pcap" или нещо подобно. Това е така, защото параметърът е префикс, а не пълно име на файл. По време на симулацията асистентът всъщност ще създаде файл за проследяване за всяко устройство от точка до точка. Имената на файловете ще бъдат конструирани с помощта на префикса, номера на възела, номера на устройството и суфикса ".pcap".

За нашия примерен скрипт в крайна сметка ще видим файлове с име "myfirst-0-0.pcap"И"myfirst-1-0.pcap", които са следи на pcap съответно за възел 0-устройство 0 и възел 1-устройство 0. След като добавите реда от код, за да активирате проследяването на pcap, можете да стартирате скрипта по обичайния начин:

$ ./waf --run scratch/myfirst

Ако погледнете в директорията от най-високо ниво на вашата дистрибуция, трябва да видите три файла: ASCII файл за проследяване myfirst.tr, които преди това проучихме, файлове myfirst-0-0.pcap и myfirst-1-0.pcap - нови pcap файлове, които току-що генерирахме.

Четене на изход с tcpdump

Засега най-лесният начин за преглед на pcap файлове е да използвате 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

В бунището myfirst-0-0.pcap (клиентско устройство) можете да видите, че ехо пакетът е изпратен след 2 секунди симулация. Ако погледнете второто изхвърляне (myfirst-1-0.pcap), ще видите, че пакетът е получен на 2,257324 секунди. Ще видите във втория дъмп, че пакетът е върнат на 2.257324 секунди и накрая, че пакетът е получен обратно от клиента при първия дъмп на 2.514648 секунди.

Четене на изход с Wireshark

Ако не сте запознати с Wireshark, има уебсайт, от който можете да изтеглите програми и документация: http://www.wireshark.org/. Wireshark е GUI, който може да се използва за показване на тези файлове за проследяване. Ако имате Wireshark, можете да отворите всеки от файловете за проследяване и да покажете съдържанието, сякаш сте уловили пакетите с помощта на снифър за пакети.

Източник: www.habr.com

Добавяне на нов коментар