poradnik dotyczący symulatora sieci ns-3. Rozdział 5

poradnik dotyczący symulatora sieci ns-3. Rozdział 5
Rozdział 1,2
rozdział 3
rozdział 4

5 Ustawienia
5.1 Korzystanie z modułu logowania
5.1.1 Przegląd rejestrowania
5.1.2 Włącz rejestrowanie
5.1.3 Dodanie logowania do kodu
5.2 Używanie argumentów wiersza poleceń
5.2.1 Zastępowanie domyślnych wartości atrybutów
5.2.2 Przechwytywanie własnych poleceń
5.3 Korzystanie z systemu śledzenia
5.3.1 Śledzenie ASCII
Analizowanie śladów ASCII
5.3.2 Śledzenie PCAP

Rozdział 5

regulacja

5.1 Korzystanie z modułu logowania

Przyjrzeliśmy się już pokrótce modułowi logowania ns-3, patrząc na skrypt pierwszy.cc. W tym rozdziale przyjrzymy się bliżej możliwym zastosowaniom podsystemu rejestrowania.

5.1.1 Przegląd rejestrowania

Wiele dużych systemów obsługuje pewien rodzaj funkcji rejestrowania komunikatów i ns-3 nie jest wyjątkiem. W niektórych przypadkach w „konsoli operatora” (która zwykle jest stderr w systemach uniksowych) zapisywane są tylko komunikaty o błędach. W innych systemach mogą być wyświetlane komunikaty ostrzegawcze oraz bardziej szczegółowe informacje. W niektórych przypadkach narzędzia rejestrujące służą do wysyłania komunikatów debugowania, które mogą szybko zamazać dane wyjściowe.

SubHRD zastosowany w ns-3 zakłada, że ​​wszystkie te poziomy zawartości informacyjnej są przydatne, a my zapewniamy selektywne, warstwowe podejście do rejestrowania komunikatów. Rejestrowanie można całkowicie wyłączyć, włączyć dla poszczególnych komponentów lub globalnie. W tym celu stosuje się regulowane poziomy zawartości informacyjnej. Moduł rejestrowania ns-3 zapewnia stosunkowo prosty sposób uzyskania przydatnych informacji z symulacji.

Powinieneś zrozumieć, że zapewniamy mechanizm ogólnego przeznaczenia – śledzenie – do wydobywania danych z modeli, które powinny być preferowanym wyjściem dla symulacji (więcej informacji na temat naszego systemu śledzenia znajdziesz w samouczku, sekcja 5.3). Rejestrowanie powinno być preferowaną metodą uzyskiwania informacji o debugowaniu, ostrzeżeń, komunikatów o błędach lub szybkiego wysyłania komunikatów ze skryptów lub modeli w dowolnym momencie.

Obecnie system definiuje siedem poziomów (rodzajów) komunikatów logów w kolejności rosnącej zawartości informacyjnej.

  • LOG_ERROR - rejestrowanie komunikatów o błędach (powiązane makro: NS_LOG_ERROR);
  • LOG_WARN - Loguj komunikaty ostrzegawcze (powiązane makro: NS_LOG_WARN);
  • LOG_DEBUG - Rejestruje stosunkowo rzadkie specjalne komunikaty debugowania (powiązane makro: NS_LOG_DEBUG);
  • LOG_INFO - rejestracja komunikatów informacyjnych o postępie programu (powiązane makro: NS_LOG_INFO);
  • LOG_FUNCTION - Rejestruje komunikaty opisujące każdą wywołaną funkcję (dwa powiązane makra: NS_LOG_FUNCTION, używane dla funkcji składowych i NS_LOG_FUNCTION_NOARGS, używane dla funkcji statycznych);
  • LOG_LOGIC - logowanie komunikatów opisujących przebieg logiczny w ramach funkcji (powiązane makro: NS_LOG_LOGIC);
  • LOG_ALL — rejestruje wszystko, o czym mowa powyżej (bez powiązanego makra).
    Dla każdego typu (LOG_TYPE) istnieje również LOG_LEVEL_TYPE, który, jeśli jest używany, umożliwia rejestrowanie wszystkich poziomów powyżej niego, oprócz własnego poziomu. (W konsekwencji LOG_ERROR i LOG_LEVEL_ERROR oraz LOG_ALL i LOG_LEVEL_ALL są funkcjonalnie równoważne.) Na przykład włączenie LOG_INFO pozwoli tylko na komunikaty dostarczane przez makro NS_LOG_INFO, natomiast włączenie LOG_LEVEL_INFO obejmie także komunikaty dostarczane przez makra NS_LOG_DEBUG, NS_LOG_WARN i NS_LOG_ERROR.

Udostępniamy również makro bezwarunkowego rejestrowania, które jest zawsze wyświetlane, niezależnie od poziomu rejestrowania lub komponentu wyboru.

  • NS_LOG_UNCOND - Bezwarunkowe rejestrowanie powiązanej wiadomości (brak powiązanego poziomu rejestrowania).

Każdy poziom można sprawdzać indywidualnie lub łącznie. Rejestrowanie można skonfigurować za pomocą zmiennej środowiskowej sh NS_LOG lub rejestrując wywołanie funkcji systemowej. Jak pokazano wcześniej, system logowania posiada dokumentację Doxygen i teraz jest dobry moment, aby ją przejrzeć, jeśli jeszcze tego nie zrobiłeś.

Teraz, gdy już szczegółowo przeczytałeś dokumentację, wykorzystajmy tę wiedzę, aby uzyskać interesujące informacje z przykładowego skryptu Scratch/myfirst.ccktóre już skompilowałeś.

5.1.2 Włącz rejestrowanie

Użyjmy zmiennej środowiskowej NS_LOG, aby uruchomić więcej dzienników, ale najpierw, aby się zorientować, uruchom ostatni skrypt, tak jak zrobiłeś to wcześniej,

$ ./waf --run scratch/myfirst

Powinieneś zobaczyć znajome wyjście z pierwszego przykładowego programu 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

Okazuje się, że „wysłane” i „odbrane” wiadomości, które widzisz powyżej, są w rzeczywistości wiadomościami zarejestrowanymi Aplikacja UdpEchoClient и Aplikacja UdpEchoServer. Na przykład możemy poprosić aplikację kliencką o wydrukowanie dodatkowych informacji, ustawiając poziom rejestrowania za pomocą zmiennej środowiskowej NS_LOG.

Od tej chwili założę, że używasz powłoki podobnej do sh, która używa składni „zmienna=wartość”. Jeśli używasz powłoki podobnej do csh, będziesz musiał przekonwertować moje przykłady na składnię „wartość zmiennej setenv” wymaganą przez te powłoki.

Obecnie aplikacja kliencka UDP echo odpowiada na następujący wiersz kodu w formacie Scratch/myfirst.cc,

LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);

Włącza poziom logowania LOG_LEVEL_INFO. Kiedy przekazujemy flagę poziomu rejestrowania, faktycznie włączamy ten poziom i wszystkie niższe poziomy. W tym przypadku włączyliśmy NS_LOG_INFO, NS_LOG_DEBUG, NS_LOG_WARN i NS_LOG_ERROR. Możemy zwiększyć poziom rejestrowania i uzyskać więcej informacji bez zmiany skryptu i rekompilacji, ustawiając zmienną środowiskową NS_LOG w następujący sposób:

$ export NS_LOG=UdpEchoClientApplication=level_all

Ustawiliśmy więc zmienną powłoki sh NS_LOG na następującą wartość:

UdpEchoClientApplication=level_all

Lewa strona przypisania to nazwa logowanego komponentu, który chcemy skonfigurować, a prawa strona to flaga, którą chcemy dla niego zastosować. W tym przypadku włączymy wszystkie poziomy debugowania w aplikacji. Jeśli uruchomisz skrypt z ustawionym w ten sposób NS_LOG, system rejestrowania ns-3 zaakceptuje zmiany i powinieneś zobaczyć następujące dane wyjściowe:

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

Dodatkowe informacje debugowania dostarczane przez aplikację są teraz na poziomie NS_LOG_FUNCTION. Pokazuje każdą instancję wywołania funkcji podczas wykonywania skryptu. Z reguły w funkcjach metod lepiej jest używać (przynajmniej)NS_LOG_FUNCTION (this)... Posługiwać się NS_LOG_FUNCTION_NOARGS ()
tylko w funkcjach statycznych. Należy jednak pamiętać, że system ns-3 nie musi obsługiwać żadnej funkcji rejestrowania. Decyzję o tym, ile informacji jest rejestrowanych, pozostawia się indywidualnemu twórcy modelu. W przypadku aplikacji echa dostępna jest duża ilość wyników rejestrowania.

Możesz teraz przeglądać dziennik wywołań funkcji wykonanych przez aplikację. Jeśli przyjrzysz się uważnie, zauważysz dwukropek między liniami Aplikacja UdpEchoClient oraz nazwę metody, w której możesz spodziewać się operatora zakresu C++ (: :). To jest zamierzone.

W rzeczywistości nie jest to nazwa klasy, ale nazwa komponentu rejestrującego. Kiedy występuje dopasowanie pomiędzy plikiem źródłowym i klasą, jest to zwykle nazwa klasy, ale powinieneś zdać sobie sprawę, że w rzeczywistości nie jest to nazwa klasy i zamiast podwójnego dwukropka występuje pojedynczy dwukropek. Jest to sposób, który pomaga w stosunkowo subtelny sposób oddzielić koncepcyjnie nazwę komponentu rejestrującego od nazwy klasy.

Jednak w niektórych przypadkach ustalenie, która metoda faktycznie generuje komunikat dziennika, może być trudne. Jeśli spojrzysz na powyższy tekst, możesz zastanawiać się, gdzie jest wiersz „Received 1024 bytes from 10.1.1.2" Możesz rozwiązać ten problem, ustawiając poziom prefix_funkcja do zmiennej środowiskowej NS_LOG. Spróbuj wykonać następujące czynności:

$ export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'

Należy pamiętać, że cudzysłowy są konieczne, ponieważ pionowa kreska, której używamy do przedstawienia operacji OR, jest również złączem rurowym Uniksa. Teraz, jeśli uruchomisz skrypt, zobaczysz, że system logowania dba o to, aby każda wiadomość w danym logu była poprzedzona nazwą komponentu.

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

Teraz możesz zobaczyć, że wszystkie wiadomości przychodzące z aplikacji klienckiej UDP echo są identyfikowane jako takie. Wiadomość "Received 1024 bytes from 10.1.1.2" jest teraz wyraźnie zidentyfikowany jako pochodzący z aplikacji klienckiej echo. Pozostała wiadomość musi pochodzić z aplikacji serwera echa UDP. Możemy włączyć ten komponent, wprowadzając listę komponentów rozdzielonych dwukropkami w zmiennej środowiskowej NS_LOG.

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

Ostrzeżenie: W powyższym przykładowym tekście konieczne będzie usunięcie znaku nowej linii po dwukropku (:), który służy do formatowania dokumentu. Teraz, jeśli uruchomisz skrypt, zobaczysz wszystkie komunikaty dziennika z aplikacji echa klienta i serwera. Jak widać, może to być bardzo przydatne podczas debugowania.

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

Czasami przydatna jest także możliwość sprawdzenia czasu symulacji, w którym wygenerowano komunikat dziennika. Można to zrobić dodając bit OR prefiks_czas:

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

Ponownie będziesz musiał usunąć powyższy znak nowej linii. Jeśli teraz uruchomisz skrypt, powinieneś zobaczyć następujące dane wyjściowe:

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

Należy pamiętać, że konstruktor for Serwer UdpEcho został wywołany podczas symulacji 0 sekund. Dzieje się to faktycznie przed rozpoczęciem symulacji, ale czas jest pokazywany jako zero sekund. To samo dotyczy komunikatu konstruktora Klient UdpEcho.

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

Przypomnijmy, że skrypt podstaw/pierwsze.cc uruchomił aplikację serwera echa na sekundę przed rozpoczęciem symulacji. Teraz widać, że to metoda Uruchom aplikację serwer jest faktycznie wywoływany w pierwszej sekundzie. Możesz także zauważyć, że klient echa uruchamia się w drugiej sekundzie symulacji, tak jak prosiliśmy w skrypcie.

Możesz teraz śledzić postęp symulacji na bieżąco Zaplanuj transmisję w kliencie wywołującym wywołanie zwrotne HandleRead Send w aplikacji serwera echa. Należy pamiętać, że czas potrzebny na wysłanie pakietu łączem punkt-punkt wynosi 3,69 milisekundy. Można zobaczyć, że serwer echa rejestruje komunikat, że odpowiedział na pakiet, a następnie, po opóźnieniu kanału, klient echa odbiera pakiet echa za pomocą swojej metody HandleRead.

W tej symulacji wiele dzieje się niezauważenie. Można jednak bardzo łatwo śledzić cały proces, włączając wszystkie komponenty rejestrujące w systemie. Spróbuj ustawić zmienną NS_LOG na następującą wartość:

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

Gwiazdka powyżej to znak wieloznaczny dla komponentu rejestrującego. Będzie to obejmować wszystkie wpisy we wszystkich komponentach używanych w symulacji. Nie będę tutaj reprodukował wyniku (w momencie pisania tego tekstu dla pojedynczego pakietu echa powstaje 1265 linii wyniku), ale możesz przekierować te informacje do pliku i wyświetlić je w swoim ulubionym edytorze.

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

Osobiście używam tej niezwykle szczegółowej wersji rejestrowania, gdy mam problem i nie mam pojęcia, gdzie coś poszło nie tak. Mogę dość łatwo śledzić wykonanie kodu bez ustawiania punktów przerwania i przeglądania kodu w debugerze. Mogę po prostu edytować dane wyjściowe w moim ulubionym edytorze i szukać tego, czego się spodziewam, i zobaczyć, że dzieje się coś, czego się nie spodziewałem. Kiedy już mam ogólne pojęcie o tym, co się dzieje nie tak, wskakuję do debugera, aby zgłębić problem. Ten typ danych wyjściowych może być szczególnie przydatny, gdy skrypt wykonuje coś zupełnie nieoczekiwanego. Jeśli użyjesz tylko debugera, możesz całkowicie przegapić zwrot akcji. Rejestracja sprawia, że ​​takie zakręty są zauważalne.

5.1.3 Dodanie logowania do kodu

Możesz dodawać nowe wpisy do swoich symulacji, wykonując wywołania komponentu dziennika z wielu makr. Zróbmy to w skrypcie mójpierwszy.cc, który mamy w katalogu „clean”. Przypomnijmy, że w tym scenariuszu zdefiniowaliśmy komponent rejestrowania:

NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");

Wiesz, że możesz włączyć rejestrowanie wszystkich wiadomości z tego komponentu, ustawiając zmienną środowiskową NS_LOG na różnych poziomach. Przejdźmy dalej i dodajmy kilka wpisów do skryptu. Makro używane do dodawania komunikatów poziomu informacyjnego do dziennika to NS_LOG_INFO. Dodajmy wiadomość (tuż przed rozpoczęciem tworzenia węzłów), która poinformuje Cię, że skrypt jest w fazie „Tworzenia topologii”. Odbywa się to w następującym fragmencie kodu,
Otwórz Scratch/myfirst.cc w swoim ulubionym edytorze i dodaj linijkę,
NS_LOG_INFO ("Creating Topology");
tuż przed liniami,

NodeContainer nodes;
nodes.Create (2);

Teraz skompiluj skrypt za pomocą WAFi wyczyść zmienną NS_LOG, aby wyłączyć strumień rejestrowania, który włączyliśmy wcześniej:

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

Nie zobaczysz nowego komunikatu, ponieważ powiązany składnik rejestrowania (FirstScriptExample) nie został włączony. Aby zobaczyć swoją wiadomość, musisz włączyć moduł rejestrowania Pierwszy przykład skryptu z poziomem nie niższym niż NS_LOG_INFO. Jeśli chcesz tylko zobaczyć ten konkretny poziom rejestrowania, możesz go włączyć w ten sposób:

$ export NS_LOG=FirstScriptExample=info

Jeśli teraz uruchomisz skrypt, zobaczysz nowy komunikat „Tworzenie topologii”,

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 Używanie argumentów wiersza poleceń

5.2.1 Zastępowanie domyślnych wartości atrybutów

Innym sposobem zmiany zachowania skryptów ns-3 bez edycji lub budowania jest użycie argumentów wiersza poleceń. Udostępniamy mechanizm analizowania argumentów wiersza poleceń i automatycznego ustawiania zmiennych lokalnych i globalnych na podstawie wyników.

Pierwszym krokiem w użyciu systemu argumentów wiersza poleceń jest zadeklarowanie parsera wiersza poleceń. Jest to całkiem łatwe do zrobienia (w głównym programie), jak w poniższym kodzie:

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

Ten prosty, dwuwierszowy fragment jest w rzeczywistości bardzo przydatny sam w sobie. Otwiera drzwi do globalnego systemu zmiennych i atrybutów ns-3. Dodajmy dwie linie kodu na początek głównej funkcji skryptu Scratch/myfirst.cc. Idąc dalej, kompilujemy skrypt i uruchamiamy go, podczas uruchamiania wysyłamy prośbę o pomoc w następujący sposób,

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

To polecenie zapyta Waf uruchom skrypt Scratch / mój pierwszy i przekaż mu argument wiersza poleceń —Drukuj pomoc. Znaki cudzysłowu są wymagane, aby wskazać program, dla którego argument jest przeznaczony. Parser wiersza poleceń wykryje argument —Drukuj pomoc i wyświetli odpowiedź,

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.

Teraz spójrzmy na opcję —Drukuj atrybuty. O systemie atrybutów ns-3 wspominaliśmy już podczas studiowania skryptu First.cc. Widzieliśmy następujące linie kodu,

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

i tak powiedzieli Prędkość transmisji danych jest właściwie atrybutem Urządzenie PointToPointNet. Użyjmy parsera argumentów wiersza poleceń, aby wyświetlić atrybuty Urządzenie PointToPointNet. Lista pomocy mówi, co musimy zapewnić TypId. Jest to nazwa klasy, do której należą interesujące nas atrybuty. W naszym przypadku tak będzie ns3::PointToPointNetDevice. Idźmy dalej, wejdź,

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

System wydrukuje wszystkie atrybuty tego typu urządzenia sieciowego. Zobaczysz, że wśród atrybutów na liście znajdują się:

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

Jest to wartość domyślna, która będzie stosowana przez system podczas tworzenia obiektu Urządzenie PointToPointNet. Zastąpimy tę wartość domyślną za pomocą parametru Atrybut в Pomocnik PointToPoint wyższy. Użyjmy wartości domyślnych dla urządzeń i kanałów typu punkt-punkt. W tym celu usuniemy połączenia Ustaw atrybut urządzenia и Ustaw atrybut kanału z mójpierwszy.cc, który mamy w czystym katalogu.

Twój skrypt powinien teraz po prostu zadeklarować Pomocnik PointToPoint i nie wykonuj żadnych operacji instalacyjnych, jak pokazano w poniższym przykładzie,

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

Śmiało, utwórz nowy skrypt za pomocą Waf (./waff) i wróćmy i dołączmy wpis z aplikacji serwera echa UDP oraz przedrostek czasu.

$ export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'

Jeśli uruchomisz skrypt, powinieneś zobaczyć następujące dane wyjściowe:

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

Przypomnijmy, że ostatnim razem, gdy patrzyliśmy na czas symulacji, moment odebrania pakietu przez serwer echa wynosił 2,00369 sekundy.

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

Teraz odbiera pakiet w 2.25732 sekundy. Dzieje się tak, ponieważ po prostu resetujemy szybkość transmisji danych PointToPointNetDevice z pięciu megabitów na sekundę do wartości domyślnej, która wynosi 32768 bitów na sekundę. Gdybyśmy zastąpili nową wartość DataRate za pomocą wiersza poleceń, moglibyśmy ponownie przyspieszyć naszą symulację. Zrobimy to w następujący sposób, zgodnie ze wzorem implikowanym przez element pomocy:

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

Spowoduje to przywrócenie domyślnej wartości atrybutu DataRate wynoszącej pięć megabitów na sekundę. Czy jesteś zaskoczony wynikiem? Okazuje się, że aby przywrócić oryginalne zachowanie skryptu, musimy także ustawić opóźnienie kanału tak, aby odpowiadało prędkości światła. Możemy poprosić system wiersza poleceń o wydrukowanie atrybutów kanału, tak jak zrobiliśmy to w przypadku urządzenia sieciowego:

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

Przekonamy się, że atrybut opóźnienia kanału jest ustawiony w następujący sposób:

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

Możemy następnie za pomocą wiersza poleceń ustawić obie wartości domyślne.

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

w tym przypadku przywracamy czas, który mieliśmy, gdy jawnie ustawiliśmy w skrypcie DataRate i 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()

Należy pamiętać, że pakiet zostanie odebrany przez serwer ponownie po 2,00369 sekundach. Właściwie moglibyśmy ustawić w ten sposób dowolny atrybut używany w skrypcie. W szczególności moglibyśmy ustawić atrybuty MaxPackets na wartości inne niż jedna Klient UdpEcho.

Jak byś tego użył? Spróbuj. Pamiętaj, że musisz zakomentować miejsce, w którym nadpisujemy domyślną wartość atrybutu i jawnie ją ustawiamy MaxPakiety w skrypcie. Następnie musisz odbudować skrypt. Możesz także użyć wiersza poleceń, aby uzyskać pomoc dotyczącą składni dotyczącą ustawiania nowej domyślnej wartości atrybutu. Gdy to zrozumiesz, możesz kontrolować liczbę pakietów wyświetlanych w wierszu poleceń. Ponieważ jesteśmy pilnymi ludźmi, nasza linia poleceń powinna wyglądać mniej więcej tak:

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

Naturalnym pytaniem, które się w tym miejscu pojawia, jest to, jak dowiedzieć się o istnieniu wszystkich tych atrybutów. Ponownie, system wiersza poleceń ma funkcję pomocy w tej sprawie. Jeśli poprosimy linię poleceń o pomoc, powinniśmy zobaczyć:

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

Jeżeli wybierzesz argument "PrintGroups", powinieneś zobaczyć listę wszystkich zarejestrowanych grup TypId. Nazwy grup są zgodne z nazwami modułów w katalogu źródłowym (aczkolwiek pisanymi wielkimi literami). Wydrukowanie wszystkich informacji na raz zajęłoby zbyt dużo miejsca, dlatego dostępny jest dodatkowy filtr umożliwiający drukowanie informacji według grup. Zatem ponownie skupiając się na module punkt-punkt:

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

Tutaj możesz znaleźć dostępne nazwy TypeId do wyszukiwania atrybutów, na przykład w
--PrintAttributes = ns3 :: PointToPointChanneljak wyżej.

Innym sposobem poznania atrybutów jest Doxygen ns-3. Istnieje strona zawierająca listę wszystkich atrybutów zarejestrowanych w symulatorze.

5.2.2 Przechwytywanie własnych poleceń

Możesz także dodawać własne hooki za pomocą systemu wiersza poleceń. Odbywa się to po prostu za pomocą metody parsera wiersza poleceń Dodać wartość.
Wykorzystajmy tę funkcję, aby określić liczbę pakietów, które mają być wyświetlane w zupełnie inny sposób. Dodajmy zmienną lokalną o nazwie nPakiety w funkcję główny. Ustawimy go na taki, który będzie odpowiadał naszemu poprzedniemu domyślnemu zachowaniu. Aby umożliwić parserowi wiersza poleceń zmianę tej wartości, musimy przechwycić tę wartość w parserze. Robimy to poprzez dodanie wywołania Dodać wartość. Idź i zmień scenariusz Scratch/myfirst.cc więc zacznij od następującego kodu,

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

Przewiń w dół do punktu w skrypcie, w którym ustawiamy atrybut MaxPackets i zmieniamy go tak, aby był ustawiony na zmienną nPackets zamiast na stałą 1, jak pokazano poniżej.

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

Teraz, jeśli uruchomisz skrypt i podasz argument -PrintHelp, powinieneś zobaczyć nowy argument użytkownika. wymienione na ekranie pomocy. Wchodzić,

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

Jeśli chcesz zmienić liczbę przesyłanych pakietów, możesz to zrobić ustawiając argument wiersza poleceń - -nPackets.

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

Teraz powinieneś teraz zobaczyć

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

Wysłałeś już dwie paczki. Całkiem proste, prawda?
Widać, że jako użytkownik ns-3 możesz używać systemu argumentów wiersza poleceń do manipulowania globalnymi wartościami i atrybutami. Jeśli jesteś autorem modelu, możesz dodać nowe atrybuty do swoich obiektów, a będą one automatycznie dostępne do konfiguracji przez użytkowników za pośrednictwem systemu wiersza poleceń. Jeśli jesteś autorem skryptu, możesz dodawać nowe zmienne do swoich skryptów i bezproblemowo podłączać je do systemu wiersza poleceń.

5.3 Korzystanie z systemu śledzenia

Celem modelowania jest wygenerowanie wyników do dalszych badań, a system śledzenia ns-3 jest głównym mechanizmem służącym do tego. Ponieważ ns-3 jest programem C++, można zastosować standardowe sposoby generowania danych wyjściowych z programu C++:

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

Możesz nawet użyć modułu rejestrowania, aby dodać niewielką strukturę do swojego rozwiązania. Istnieje wiele znanych problemów spowodowanych tym podejściem, dlatego udostępniliśmy ogólny podsystem śledzenia zdarzeń, aby rozwiązać te problemy.

Główne cele systemu śledzenia ns-3 to:

  • W przypadku podstawowych zadań system śledzenia powinien umożliwiać użytkownikowi wygenerowanie standardowego śladu dla popularnych źródeł i wybranie obiektów generujących ślad;

  • Użytkownicy średniozaawansowani powinni mieć możliwość rozszerzenia systemu śledzenia w celu zmiany wygenerowanego formatu wyjściowego lub wstawienia nowych źródeł śledzenia, bez modyfikowania rdzenia symulatora;

  • Zaawansowani użytkownicy mogą modyfikować rdzeń symulatora, aby dodać nowe źródła śledzenia i ujścia. System śledzenia ns-3 zbudowany jest w oparciu o zasady niezależnych źródeł śledzenia i odbiorników, a także ujednolicony mechanizm łączenia źródeł z odbiorcami.

System śledzenia ns-3 zbudowany jest w oparciu o zasady niezależnego śledzenia źródeł i odbiorników oraz ujednoliconego mechanizmu łączenia źródeł z odbiornikami. Źródła śledzenia to obiekty, które mogą sygnalizować zdarzenia zachodzące w symulacji i zapewniać dostęp do istotnych danych. Na przykład źródło śledzenia może wskazywać, kiedy urządzenie sieciowe odebrało pakiet i udostępniać zawartość pakietu zainteresowanym odbiorcom śledzenia.

Źródła śledzenia same w sobie są bezużyteczne, chyba że zostaną „połączone” z innymi częściami kodu, które faktycznie robią coś przydatnego z informacjami dostarczonymi przez ujście. Elementy śledzące są konsumentami zdarzeń i danych dostarczanych przez źródła śledzenia. Można na przykład utworzyć ujście śledzenia, które (po podłączeniu do źródła śledzenia z poprzedniego przykładu) wydrukuje interesujące części odebranego pakietu.

Uzasadnieniem tego wyraźnego oddzielenia jest umożliwienie użytkownikom łączenia nowych typów ujścia z istniejącymi źródłami śledzenia bez konieczności edytowania i ponownej kompilacji rdzenia symulatora. Zatem w powyższym przykładzie użytkownik może zdefiniować nowy moduł śledzący w swoim skrypcie i połączyć go z istniejącym źródłem śledzenia zdefiniowanym w rdzeniu symulacji jedynie poprzez edycję skryptu użytkownika.

W tym samouczku omówimy niektóre predefiniowane źródła i ujścia oraz pokażemy, jak można je skonfigurować przy minimalnym wysiłku ze strony użytkownika. Zobacz podręcznik ns-3 lub sekcje z instrukcjami, aby uzyskać informacje na temat zaawansowanej konfiguracji śledzenia, w tym rozszerzania przestrzeni nazw śledzenia i tworzenia nowych źródeł śledzenia.

5.3.1 Śledzenie ASCII

ns-3 zapewnia funkcję pomocniczą, która zapewnia system śledzenia niskiego poziomu, który pomaga w szczegółach podczas konfigurowania prostych śladów pakietów. Jeśli włączysz tę funkcję, zobaczysz dane wyjściowe w plikach ASCII. Dla osób zaznajomionych z wyjściem ns-2 ten typ śledzenia jest podobny do out.tr, który jest generowany przez wiele skryptów.

Przejdźmy do rzeczy i dodajmy wyniki śledzenia ASCII do naszego skryptu Scratch/myfirst.cc. Tuż przed rozmową Simulator :: Run (), dodaj następujące linie kodu:
AsciiTraceHelper ascii;

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

Podobnie jak wiele innych idiomów ns-3, ten kod wykorzystuje obiekt pomocniczy do tworzenia śladów ASCII. Druga linia zawiera dwa zagnieżdżone wywołania metod. Metoda „wewnątrz”. Utwórz strumień pliku() używa idiomu obiektu anonimowego do utworzenia obiektu strumienia plików na stosie (bez nazwy obiektu) i przekazuje go do wywoływanej metody. Zajmiemy się tym głębiej w przyszłości, ale w tym momencie jedyne, co musisz wiedzieć, to to, że tworzysz obiekt reprezentujący plik o nazwie mójpierwszy.tr i przenieś go do ns-3. Powierzamy ns-3 opiekę nad stworzonym obiektem przez cały czas jego życia, podczas którego rozwiązuje problemy spowodowane mało znanym (celowym) ograniczeniem związanym z konstruktorami kopiującymi obiekty strumieniowe C++.

Połączenie zewnętrzne WłączAsciiAll() informuje asystenta, że ​​chcesz uwzględnić śledzenie ASCII w swojej symulacji dla wszystkich połączeń urządzeń punkt-punkt i że chcesz, aby (określone) odbiorniki śledzenia rejestrowały informacje o ruchu pakietów w formacie ASCII.

Dla osób zaznajomionych z ns-2 śledzone zdarzenia są równoważne znanym punktom śledzenia, które rejestrują zdarzenia „+”, „-”, „d” i „r”.
Teraz możesz zbudować skrypt i uruchomić go z wiersza poleceń:

$ ./waf --run scratch/myfirst

Podobnie jak wiele razy wcześniej, zobaczysz kilka komunikatów od Wafa, a następnie „kompilacja zakończyła się pomyślnie” wraz z kilkoma komunikatami od uruchomionego programu.

Po uruchomieniu program utworzy plik o nazwie mójpierwszy.tr. Ze względu na charakter pracy Waf, domyślnie plik jest tworzony nie w katalogu lokalnym, ale w katalogu najwyższego poziomu repozytorium. Jeśli chcesz zmienić ścieżkę, w której zapisywane są ślady, możesz użyć parametru Waf, aby to określić --cwd. Nie zrobiliśmy tego, więc aby sprawdzić plik śledzenia ASCII myfirst.tr w Twoim ulubionym edytorze, musimy przejść do katalogu najwyższego poziomu naszego repozytorium.

Analizowanie śladów ASCII

Jest tam sporo informacji w dość gęstej formie, jednak pierwszą rzeczą, na którą trzeba zwrócić uwagę, jest to, że plik składa się z pojedynczych linijek. Stanie się to wyraźnie widoczne, jeśli szerzej rozszerzysz okno podglądu.

Każda linia w pliku odpowiada zdarzeniu śledzenia. W tym przypadku śledzimy zdarzenia w kolejce transmisji występującej w każdym urządzeniu sieciowym typu punkt-punkt biorącym udział w symulacji. Kolejka transmisji to kolejka, przez którą musi przejść każdy pakiet, aby uzyskać połączenie punkt-punkt. Należy pamiętać, że każda linia pliku śledzenia zaczyna się od pojedynczego znaku (po którym następuje spacja). Symbol ten będzie miał następujące znaczenie:

+: wystąpiła operacja kolejkowania w kolejce urządzenia;
-: wystąpiła operacja pobrania elementu w kolejce urządzeń;
d: pakiet został odrzucony, zwykle z powodu zapełnienia kolejki;
r: Pakiet został odebrany przez urządzenie sieciowe.

Przyjrzyjmy się bliżej pierwszej linii pliku śledzenia. Podzielę to na części (z wcięciami dla przejrzystości) i numer wiersza po lewej stronie:

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)

Pierwszą sekcją tego rozszerzonego zdarzenia śledzenia (linia 0) jest operacja. Mamy tu symbol +, który odpowiada operacji kolejkowania do transmisji. Druga część (linia 1) to czas symulacji wyrażony w sekundach. Być może pamiętasz, o co pytaliśmy Aplikacja UdpEchoClient rozpocznij wysyłanie pakietów w ciągu dwóch sekund. Tutaj widzimy potwierdzenie, że tak się rzeczywiście dzieje.

Następna sekcja przykładu śledzenia (z wiersza 2) pokazuje, które źródło śledzenia wygenerowało to zdarzenie (wskazując ślad przestrzeni nazw). O przestrzeni nazw śledzenia można myśleć podobnie jak o przestrzeni nazw systemu plików. Korzeń przestrzeni nazw to Lista węzłów. Odpowiada to kontenerowi zarządzanemu w głównym kodzie ns-3. Zawiera wszystkie węzły utworzone w skrypcie. Podobnie jak system plików może mieć katalogi w swoim katalogu głównym, Lista węzłów możemy mieć wiele węzłów. Zatem linia /NodeList/0 odnosi się do węzła zerowego na liście NodeList, o którym zwykle myślimy jako o „węźle 0”. Każdy węzeł posiada listę zainstalowanych urządzeń. Lista ta znajduje się obok w przestrzeni nazw. Widać, że pochodzi to zdarzenie śledzenia Lista urządzeń/0, czyli urządzenie zerowe zainstalowane w węźle.

Następny podciąg, $ ns3 :: PointToPointNetDevice, informuje, które urządzenie znajduje się na pozycji zerowej: lista urządzeń węzła zerowego. Przypomnijmy, że operacja + znaleziona w linii 0 oznaczała, że ​​element został dodany do kolejki nadawczej urządzenia. Znajduje to odzwierciedlenie w ostatnich odcinkach „ścieżki toru”: TxQueue/Kolejka.

Pozostałe sekcje śladu powinny być dość intuicyjne. Linie 3-4 wskazują, że pakiet jest hermetyzowany w protokole punkt-punkt. Linie 5-7 pokazują, że pakiet ma nagłówek w wersji IP4 i pochodzi z adresu IP 10.1.1.1 i przeznaczone dla 10.1.1.2. Linie 8-9 pokazują, że ten pakiet ma nagłówek UDP, a linia 10 pokazuje, że ładunek ma oczekiwane 1024 bajty.

Następny wiersz pliku śledzenia pokazuje, że ten sam pakiet został pobrany z kolejki transmisji w tym samym węźle.

Trzecia linia pliku śledzenia pokazuje, że pakiet został odebrany przez urządzenie sieciowe na hoście serwera echa. Poniżej odtworzyłem wydarzenie.

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)

Należy zauważyć, że operacja śledzenia wynosi teraz r, a czas symulacji został zwiększony do 2,25732 sekundy. Jeśli dokładnie wykonałeś samouczek, oznacza to, że parametry DataRate i Link Delay urządzeń sieciowych pozostawiłeś na wartościach domyślnych. Ten czas powinien być Ci znany, jak widziałeś w poprzedniej sekcji.

Wpis przestrzeni nazw źródła śledzenia (wiersz 2) został zmodyfikowany, aby odzwierciedlić fakt, że to zdarzenie pochodzi z węzła 1 (/Lista węzłów/1) i pakiet zostaje odebrany przez źródło śledzenia (/MacRx). Śledzenie ruchu pakietu w topologii powinno być dość łatwe, patrząc na pozostałe ślady w pliku.

5.3.2 Śledzenie PCAP

Pomocników urządzeń ns-3 można także używać do tworzenia plików śledzenia w formacie .pcap. Akronim PCAP (zwykle pisane małymi literami) oznacza przechwytywanie pakietów i w rzeczywistości jest interfejsem API obejmującym definiowanie formatu pliku .pcap. Najpopularniejszym programem, który potrafi czytać i wyświetlać ten format jest Wireshark (wcześniej tzw Eteryczny). Istnieje jednak wiele analizatorów śledzenia ruchu, które korzystają z tego formatu pakietu. Zachęcamy użytkowników do korzystania z wielu dostępnych narzędzi do analizy śladów pcap. W tym samouczku skupimy się na przeglądaniu śladów pcap za pomocą tcpdump.

Włączenie śledzenia pcap odbywa się za pomocą jednego wiersza kodu.

pointToPoint.EnablePcapAll ("myfirst");

Wklej tę linię kodu po właśnie dodanym kodzie śledzenia ASCII Scratch/myfirst.cc. Zauważ, że przekazaliśmy tylko ciąg „myfirst”, a nie „myfirst.pcap” lub coś podobnego. Dzieje się tak, ponieważ parametr jest przedrostkiem, a nie pełną nazwą pliku. Podczas symulacji asystent utworzy plik śledzenia dla każdego urządzenia typu punkt-punkt. Nazwy plików będą tworzone przy użyciu przedrostka, numeru węzła, numeru urządzenia i przyrostka „.PCAP".

W naszym przykładowym skrypcie zobaczymy pliki o nazwach „mójpierwszy-0-0.pcap"A"mójpierwszy-1-0.pcap", które są śladami pcap odpowiednio dla węzła 0-urządzenie 0 i węzła 1-urządzenie 0. Po dodaniu linii kodu umożliwiającej śledzenie pcap możesz uruchomić skrypt w zwykły sposób:

$ ./waf --run scratch/myfirst

Jeśli zajrzysz do katalogu najwyższego poziomu swojej dystrybucji, powinieneś zobaczyć trzy pliki: plik śledzenia ASCII mójpierwszy.tr, które wcześniej badaliśmy, pliki mójpierwszy-0-0.pcap и mójpierwszy-1-0.pcap - nowe pliki pcap, które właśnie wygenerowaliśmy.

Odczytywanie danych wyjściowych za pomocą tcpdump

Na razie najłatwiejszym sposobem przeglądania plików pcap jest użycie 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

Na wysypisku mójpierwszy-0-0.pcap (urządzenie klienckie) widać, że pakiet echa został wysłany po 2 sekundach symulacji. Jeśli spojrzysz na drugi zrzut (mójpierwszy-1-0.pcap), zobaczysz, że pakiet został odebrany po 2,257324 sekundach. W drugim zrzucie zobaczysz, że pakiet został zwrócony po 2.257324 sekundy, a na koniec, że pakiet został odebrany przez klienta w pierwszym zrzucie po 2.514648 sekundzie.

Odczytywanie danych wyjściowych za pomocą Wireshark

Jeśli nie jesteś zaznajomiony Wireshark, istnieje strona internetowa, z której można pobrać programy i dokumentację: http://www.wireshark.org/. Wireshark to graficzny interfejs użytkownika, którego można używać do wyświetlania plików śledzenia. Jeśli masz Wireshark, możesz otworzyć dowolny plik śledzenia i wyświetlić jego zawartość tak, jakbyś przechwycił pakiety za pomocą sniffera pakietów.

Źródło: www.habr.com

Dodaj komentarz