Joanna Domańska, Krzysztof Grochla, Sławomir Nowak. Symulator. OMNeT++ dla studentów i inżynierów

Wielkość: px
Rozpocząć pokaz od strony:

Download "Joanna Domańska, Krzysztof Grochla, Sławomir Nowak. Symulator. OMNeT++ dla studentów i inżynierów"

Transkrypt

1 Joanna Domańska, Krzysztof Grochla, Sławomir Nowak Symulator OMNeT++ dla studentów i inżynierów WSB Dąbrowa Górnicza, 2009

2 ii

3 Spis treści 1 Wprowadzenie teoretyczne Podstawowe definicje Wprowadzenie do symulacji zdarzeń dyskretnych Symulacja sieci komputerowych Budowa symulatora zdarzeń dyskretnych Przegląd dostępnych symulatorów sieciowych Pakiet OMNeT Koncepcja budowy modelu symulacyjnego Hierarchiczność modelu Połączenia, bramki, komunikaty Definicja modułów i tworzenie topologii połączeń modelu Składnia języka NED Definicja modułów prostych Definicja modułów złożonych Wyrażenia w języku NED Określanie parametrów połączeń Szczegółowe zasady przesyłu komunikatów Definiowanie funkcji użytkownika Definicja sieci symulacyjnej Właściwości graficzne komponentów Graficzny edytor GNED Plik konfiguracyjny omnetpp.ini Zaawansowane parametryzowanie modułów Środowisko uruchomieniowe symulacji Środowisko tekstowe Cmdenv Środowisko graficzne TkEnv Programowanie aktywnych modułów (C++) Symulacja zdarzeń dyskretnych w OMNeT Czas symulowany Wymiana informacji ze środowiskiem symulacji Definiowanie modułów prostych w C Metoda handlemessage(cmessage *msg) Obsługa bram i połączeń Komunikaty iii

4 iv SPIS TREŚCI Wysyłanie komunikatów Definiowanie własnych klas komunikatów (pliki.msg) Parametry Dostęp do parametrów modułu Identyfikacja i dostęp do hierarchii modułów Zbieranie i przetwarzanie wyników symulacji Klasa wektorów coutvector Klasa statystyk cstatistic Kontrola parametrów w oknie środowiska TkEnv Wewnętrzne struktury danych: listy, kolejki Kolejki Tablice Generatory liczb losowych Biblioteka klas OMNeT Kompilacja i tworzenie bibliotek symulacyjnych Podsumowanie Przykłady zastosowania Uproszczony model przesyłania pakietów pomiędzy węzłami tictoc tictoc tictoc tictoc tictoc tictoc tictoc tictoc tictoc tictoc tictoc tictoc

5 SPIS TREŚCI 1 Wstęp Problematyka związana z sieciami komputerowymi jest integralną częścią informatyki jako dziedziny nauki. Podobnie infrastruktura sieciowa jest istotnym elementem technicznej infrastruktury systemów informatyki. Dlatego też dogłębne zrozumienie zagadnień związanych z sieciami komputerowymi jest jednym z najważniejszych elementów edukacji na kierunkach informatycznych, jako wiedza niezbędna dla inżynierów. Ważnym elementem kształcenia jest wiedza praktyczna, uzyskana dzięki bezpośrednim eksperymentom i pracy z wykorzystaniem fizycznej infrastruktury sieciowej. W przypadku jednak pewnych złożonych zagadnień, specyficznych konfiguracji i rozbudowanych topologii trudna, kosztowna lub wręcz niemożliwa jest praca z fizycznymi urządzeniami. Wówczas niezastąpionym narzędziem stają się symulacje komputerowe. Ich znaczenie nie ogranicza się tylko od zagadnień związanych z edukacją. Są one w praktyce używane podczas projektowania, konfiguracji i rozbudowy sieci komputerowych. Niniejsza książka przybliży Czytelnikowi praktyczne i teoretyczne podstawy pracy z wykorzystaniem jednego z najbardziej popularnych pakietów do symulacji komputerowych OMNeT++. Przedstawione zostaną także przykłady wykorzystania pakietu do tworzenia modeli symulacyjnych wybranych mechanizmów sieciowych oraz analiza wyników symulacji. Autorzy książki od wielu lat zajmują się problematyką modelowania,symulacji i oceny efektywności systemów komputerowych. W swojej pracy wykorzystują także opisywany pakiet OMNeT++. Prowadzą także zajęcia dydaktyczne związane z tą dziedziną. Studenci zwracali przy tym uwagę na brak pozycji podejmujących tę tematykę na rynku wydawniczym. Książka ta jest odpowiedzią na to zapotrzebowanie. W założeniu książka kierowane jest do studentów studiów informatycznych jako pomoc dla przedmiotów związanych z modelowaniem i symulacją sieci systemów komputerowych. Może być także pomocna dla specjalistów zajmujących się projektowaniem i analizą sieci komputerowych, którzy w swej pracy wykorzystują symulacje sieci komputerowych.

6 2 SPIS TREŚCI

7 Rozdział 1 Wprowadzenie teoretyczne 1.1 Podstawowe definicje W praktycznie wszystkich dziedzinach, co do których człowiek przejawia jakiekolwiek zainteresowanie, zachodzi konieczność przeprowadzania różnego rodzaju badań. Składają się na to eksperymenty, gromadzenie i analiza danych oraz wyciąganie wniosków. Badania mogą koncentrować się wokół pewnych rzeczywistych zjawisk, obiektów lub systemów. Mówimy wtedy, że przedmiotem badań jest system fizyczny (rzeczywisty). Takie badania niosą ze sobą znaczną wartość poznawczą, a eksperymenty przeprowadzane na rzeczywistych systemach uchodzą za najbardziej wiarygodne, potwierdzając naszą intuicję i przewidywania. Aby nasze badania nabrały bardziej uniwersalnego, naukowego charakteru, konieczne jest odpowiednie opisanie interesującego nas aspektu rzeczywistości. Systemem rzeczywistym nazywamy część świata rzeczywistego, naturalnego lub w pewnych przypadkach także sztucznego, będącą przedmiotem zainteresowania badawczego w modelowaniu i symulacji. Opis systemu rzeczywistego, wyrażony poprzez zbiór założeń, pojęć i zależności nazywamy modelem. Odwzorowuje on tę rzeczywistość zazwyczaj w sposób przybliżony. Przybliżenie to wynika z niedoskonałości naszego aparatu poznawczego, niedokładności lub zbyt wąskiego zakresu przeprowadzonych eksperymentów, lub choćby z potrzeby ograniczenia stopnia złożoności tego modelu. Model taki najczęściej wyrażamy w języku matematyki (model matematyczny, model analityczny), jako zbiór zmiennych i układ równań, wiążących te zmienne. Zmienne reprezentują parametry modelowanego układu, jak np. temperatura, przepustowość, moc sygnału itp. Istotną korzyścią wynikającą ze znajomości modelu jest możliwość przeprowadzania badań bez konieczności posiadania dostępu do rzeczywistego układu. Na przykład Francja zakończyła w roku 1996 serię testów broni jądrowej, ogłaszając że posiada już odpowiedni model i dalsze badania mogą być już prowadzone teoretycznie. W tym wypadku prowadzenie fizycznych eksperymentów było niezwykle kosztowne a próby jądrowe budzą społeczny sprzeciw. Czasami przedmiotem badań jest jedynie nasze wyobrażenie, przewidywania co do rzeczywistego układu. Tego typu badania prowadzi się na przykład w nanotechnologii molekularnej, badając układy, których wytworzenie nie jest możliwe na obecnym poziomie technologicznym. Gdyby jednak udało się je wytworzyć, byłyby poprawne pod względem chemicznym (wiązania wartościowość), przejawiając właściwości określone w wyniku teoretycznych przewidywań. W pewnych przypadkach rzeczywisty układ jest dostępny, jednak chcemy przetestować specyficzną konfigurację lub określone parametry, a modyfikacja układu jest z różnych względów trudna lub czaso- 3

8 4 ROZDZIAŁ 1. WPROWADZENIE TEORETYCZNE chłonna. Taka potrzeba występuje na przykład dla współczesnych procesów produkcyjnych, w przypadku gdy chcemy wprowadzić do produkcji nowy produkt lub zmodyfikować proces, w celu uzyskania optymalnych cech wytrzymałościowych produktu. Badania przeprowadzone z wykorzystaniem modelu nazywa się modelowaniem. Jest to więc działanie mające na celu odtworzenie najważniejszych właściwości układu rzeczywistego na podstawie modelu. Korzystając z modelu matematycznego (analitycznego) jesteśmy w stanie, poprzez przeprowadzenie odpowiednich obliczeń, dokładnie przewidzieć wszystkie właściwości układu, oczywiście w granicach wyznaczonych przez poprawność samego modelu. Rozwiązanie to pozwala na przykład oszacować prawdopodobieństwo wystąpienia wszystkich przypadków szczególnych, nawet takich, których wystąpienie można określić jako praktycznie niemożliwe. Korzystanie jednak z metod analitycznych często wiąże się z ogromnym nakładem obliczeniowym, nawet dla stosunkowo prostych modeli, związanym np. z koniecznością rozwiązywania układów złożonych z miliardów równań. W wielu przypadkach uzyskanie takiej dokładności nie jest nawet potrzebne. Wówczas pomocne okaże się skorzystanie z metod symulacyjnych, które znajdują szerokie zastosowanie w niemal każdej dziedzinie nauki i techniki, a w wielu przypadkach jest to też jedyne możliwe rozwiązanie. Symulację (simulare, łac. - udawać, upodabniać się) można określić jako szczególny przypadek modelowania, w którym nasze badanie ma charakter przybliżony, ograniczony w czasie i do określonych, typowych konfiguracji. Bardziej szczegółowo, symulację definiujemy jako technikę numeryczną służącą do dokonywania eksperymentów na pewnych rodzajach modeli matematycznych, które opisują przy pomocy maszyny cyfrowej zachowanie się złożonego systemu w ciągu długiego okresu czasu [Naylor 1975, s. 21]. W definicji pojawia się określenie długiego czasu. Długi czas jest oczywiście pojęciem względnym, bo w przypadku niektórych systemów wystarczająco długi czas są to milisekundy, w innych obserwacji może być prowadzona przez dni, miesiące czy nawet lata. Istotne jest to, że czas obserwacji jest ograniczony, co stanowi cechę modeli badań symulacyjnych. Jeśli proces symulacji zapisany jest w postaci programu komputerowego, wówczas mówimy o symulacji komputerowej. Wyjaśnienia wymaga pojęcie czasu. Z systemem rzeczywistym związany jest czas rzeczywisty. Odzwierciedleniem czasu rzeczywistego w systemie symulacyjnym jest czas symulowany. Innym określeniem jest czas symulacji, to jest czas rzeczywisty w którym zanotowano określony upływ czasu symulowanego. W określeniu do symulacji komputerowych używa się także określenia czas zegarowy. Warto zwrócić uwagę na różnice w tych określeniach. Wśród metod symulacji komputerowej można wyróżnić symulacje ciągłe i dyskretne. W symulacjach ciągłych zmiana stanów systemu na charakter ciągły (jest funkcją ciągłą). W szczególności zmiana czasu symulowanego jest funkcją ciągłą lub dyskretną w takim zakresie, aby najlepiej odwzorowywała funkcję ciągłą (niewielkie zmiany czasu symulowanego). W symulacjach dyskretnych zmiana stanów systemu i czasu symulowanego ma charakter dyskretny. Zmiana czasu symulowanego może być wynikiem wykonania tzw. dyskretnego kroku czasowego lub być następstwem zdarzeń, o charakterze dyskretnym. Wówczas mamy do czynienia z symulacją zdarzeń dyskretnych. W książce opisywany jest ten ostatni przypadek metod symulacyjnych, czyli symulacja zdarzeń dyskretnych. Podsumowując należy wspomnieć o niezwykle istotnym aspekcie. Zgodnie z przedstawioną definicją, model jest przybliżeniem rzeczywistości. Prowadząc badania z wykorzystaniem modelu należy zawsze przeprowadzić oszacowanie co do dokładności tego przybliżenia. Proces sprawdzenia dokładności modelu nazywa się weryfikacją modelu. Weryfikacji poświęcone są odpowiednie metody, zależnie od konkretnego przypadku. Wykorzystując gotowe modele lub analizując badania przeprowadzone z ich wykorzystaniem można często spotkać się z analizą takiej poprawności. Zdarzają się także poważne opracowania naukowe, w których pominięto taką analizę, co naraża jednak autorów na zarzut niewystarczającej rzetelności

9 1.2. WPROWADZENIE DO SYMULACJI ZDARZEŃ DYSKRETNYCH 5 przy prowadzeniu prac lub prowadzenia badać w oderwaniu od rzeczywistości. Pomimo, że książka nie zajmuje się bezpośrednio tematem weryfikacji poprawności wyników badań autorzy zwracają uwagę na ten niezwykle ważny aspekt prac naukowych. W literaturze można spotkać wiele pozycji związanych z tym tematem np.[..] i uważny czytelnik powinien zwrócić na nie uwagę. 1.2 Wprowadzenie do symulacji zdarzeń dyskretnych W każdej symulacji badamy pewien system, będący odzwierciedleniem systemu rzeczywistego. System takie możemy określić jako zbiór jednostek, obiektów, komponentów lub podsystemów, które pozostają ze sobą w określonych zależnościach. W dalszej części będziemy odwoływać się do elementów takiego systemu stosując zamiennie określenia obiekt systemu i komponent systemu. Symulacje zdarzeń dyskretnych polegają na kolejnych zmianach w czasie symulowanym, począwszy od danego zdarzenia dyskretnego do kolejnego. Zdarzenie jest chwilowym wystąpieniem zjawiska, zawiązanym z określoną chwilą czasu (tzw. czasem wystąpienia, ang. timestamp), które zmienia stan jednego lub wielu obiektów symulacji. Stan obiektu symulacji jest zbiorem atrybutów (zmiennych) odpowiadającym cechom dla danego obiektu w tym momencie. Symulacja trwa aż do wyczerpania określonego limitu. Na ogół jest to limit czasu symulowanego, ale może to też być określony czas symulacji, liczba zdarzeń i inne. Ze względu na to, że upływ czasu symulowanego związany jest z kolejnymi zdarzeniami symulacji z zasady kończy się gdy w systemie nie ma już żadnych zdarzeń do przetworzenia. [TODO: dokończyć, przedstawić dokładniejszy opis i jakieś rysunki] Symulacja zdarzeń dyskretnych jest mechanizmem mającym charakter ogólny i mogą zostać odniesione także do symulacji różnych systemów i układów. W niniejszej książce interesuje nas zastosowanie tego mechanizmu do symulacji sieci komputerowych, do których specyfiki symulacje zdarzeń dyskretnych dopasowują się szczególnie dobrze. Przepływ danych w współczesnych sieciach zachodzi w jednostkach o określonej wielkości (ramki, pakiety, segmenty). Jednostka taka, dostarczona do procesu odbiorcy może być utożsamiana z wystąpieniem zdarzenia, zmieniając stan obiektu i generując kolejne zdarzenia w systemie Symulacja sieci komputerowych Szybki rozwój Internetu, wprowadzenie nowych rozwiązań technologicznych, implementacja mechanizmów zapewnienia jakości usług, rozwój sieci w pełni optycznych, nowoczesne sieci bezprzewodowe, stawiają nowe wyzwania dla symulacji sieci komputerowych. Symulacje działania sieci stają się bardzo ważnym narzędziem dla specjalisty zajmującego się tematyką sieci komputerowych. Metody symulacyjne mogą służyć projektowaniu sieci komputerowych i ich właściwej konfiguracji oraz przy projektowaniu nowych technologii sieciowych. W szczególności mogą być zastosowane w ocenie nowych mechanizmów zarządzania ruchem pakietów w sieciach komputerowych (zróżnicowanie jakości usług). Prace badawcze w dziedzinie symulacji sieci komputerowych w większości koncentrują się wokół zagadnień związanych z protokołem TCP/IP oraz problemami Internetu, który odgrywa podstawową rolę w telekomunikacji i stał się wszechobecnym medium informacyjnym. Prace o tym profilu, obejmując bardzo szeroki zbiór różnorodnych technologii, mają duże znaczenie praktyczne dla informatyki i telekomunikacji. Oczywiście zastosowanie symulacji może mieć znacznie szerszy zakres i dotyczyć zupełnie nowych aspektów, związanych z przesyłaniem informacji.

10 6 ROZDZIAŁ 1. WPROWADZENIE TEORETYCZNE Z praktycznego punktu widzenia symulacje sieci komputerowych pozwalają odpowiedzieć na pytania typu: Jak działa mechanizm przesuwnego okno w TCP? ; Czy protokół TCP w wersji X jest lepszy niż w wersji Y? Jaka będzie zmienność opóźnienia przy przesyłaniu obrazu podczas telekonferencji? ; Czy nowy protokół routingu, sprawdzony w małej sieci lokalnej będzie równie dobrze działał w dużych sieciach o złożonej topologii? Budowa symulatora zdarzeń dyskretnych [TODO] Przegląd dostępnych symulatorów sieciowych Na rynku oprogramowania istnieje wiele różniących się od siebie symulatorów. Część z nich dostępna jest na zasadzie Open Source, inne wymagają zakupu licencji dla celów komercyjnych, a w przypadku jeszcze innych ich zakup wiąże się w każdym przypadku ze bardzo znacznymi wydatkami. Niezależnie od sposobu dystrybucji możemy wyróżnić kilka podstawowych cech, którymi różnią się dostępne produkty: Sposób udostępniania licencji - wspomniana wcześniej, wpływa także na dostępność modeli, rozwój nowych wersji, możliwość ingerencji w kod źródłowy oraz na poziom i dostępność wsparcia technicznego; Dostępność bibliotek modeli - jeden z najistotniejszych elementów, określa zdolność do wykorzystania gotowych modeli istniejących rozwiązań sieciowych, które można bezpośrednio wykorzystywać we własnych symulacjach. Ważna jest także dokładność odwzorowania istniejących standardów oraz weryfikacja modeli symulacyjnych w odniesieniu do systemów rzeczywistych. W tej dziedzinie najlepiej wypadają pakiety komercyjne, jednak także oprogramowanie bezpłatne, dzięki aktywnych grupach użytkowników, także posiada bogaty zbiór bibliotek i rozszerzeń; Wydajność symulacji (prędkość działania) - symulatory różnią się prędkością działania i analogiczna symulacja będzie potrzebować więcej lub mniej czasu rzeczywistego, aby wykonać swoje zadanie. Niektóre rozwiązania pozwalają także realizować symulację w sposób rozproszony, na wielu procesorach lub wielu maszynach fizycznych, co dla określonych modeli przekłada się na wzrost wydajności; Środowisko uruchomieniowe - na ogół oprogramowanie symulatorów oferuje graficzne (GUI - ang. Graphical User Interface, Interfejs Graficzny Użytkownika) bądź tekstowe środowisko uruchomieniowe. W niektórych przypadkach dostarcza dodatkowe oprogramowanie do analizy i zbierania wyników (także podczas symulacji) oraz udostępnia możliwość animacji przebiegu symulacji; Łatwość rozbudowy - wpływa na możliwość rozwijania dostępnych modeli oraz implementacji własnych. W niektórych przypadkach modyfikacja może polegać na graficznej edycji elementów symulacji i topologii modelu, w innych niezbędna będzie ingerencja na niskim poziomie (np. bezpośrednio w plikach źródłowych C++). Często dostępne są specjalne języki skryptowe (lub zmodyfikowane języki ogólnego przeznaczenia) ułatwiające tworzenie modeli;

11 1.2. WPROWADZENIE DO SYMULACJI ZDARZEŃ DYSKRETNYCH 7 Skalowalność - powiązana z wydajnością symulacji, pozwala na symulację modeli o określonej wielkości (np. modele składające się z wielu tysięcy węzłów, czy tzw. modele Internetu). Wpływ ma na to implementacja symulacji i sposób zarządzania zasobami sprzętowymi przez program symulatora. Inne - można wyróżnić wiele dodatkowych cech symulatorów, jak jakość i różnorodność dodatkowego oprogramowania, narzędzie do analizy wyników, szczegółowość symulacji i inne. Wśród ważniejszych symulatorów warto wymienić następujące: OPNET jest komercyjnym symulatorem zdarzeń dyskretnych dedykowanym do modelowania i analizy systemów informatycznych. Opracowywany jest przez OPNET Technologies Inc. Modele obejmują bardzo szeroki zbiór dostępnych na rynku rozwiązań i technologii (konkretne urządzenia, protokoły, aplikacje). Symulator dysponuje wygodnym wizualnym edytorem, za pomocą którego można tworzyć konkretne modele do symulacji. Użytkownik posiada szerokie możliwości modyfikacji istniejących i projektowania nowych modeli. Środowisko symulacyjne odzwierciedla warstwową architekturę sieci, obejmując wszystkie elementy tej hierarchii, od szczegółów łączy do konkretnych aplikacji. Algorytmy, odpowiadające za aktywność elementów modeli są implementowane w języku Proto-C, bedacym rozszerzeniem języka C++ o biblioteki przeznaczone do obsługi symulacji. W skład pakietu wchodzą dodatkowe narzędzia, np. do wyszukiwania błędów, optymalizacji wydajności i wizualizacji przebiegu symulacji. Funkcjonalność pakietu podstawowego można rozszerzać o dodatkowe, licencjonowane moduły. OPNET jest bardzo wydajnym, rozbudowanym narzędziem, łącząc możliwości rozbudowy i bardzo dużą bibliotekę modeli. Oferuje przy tym wysoką, referencyjną wiarygodność generowanych wyników. Barierą dla jego wykorzystania jest jednak bardzo wysoka cena zakupu licencji. NS (Network Simulator), znany także jako ns-2 jest popularnym symulatorem zdarzeń dyskretnych, w pełni darmowym, mającym ogólne zastosowanie w ramach symulacji sieci komputerowych, ale powszechnie wykorzystuje się go do symulacji sieci TCP/IP i innych mechanizmów związanych z sieciami typu internet. Opis symulacji przygotowuje się w formie skryptu w języku Tcl. Podczas symulacji generowany jest plik z wynikami oraz przebiegiem symulacji, który może zostać wizualizowany przy pomocy dedykowanego narzędzia Nam. W NS architekturę modelu określa się na trzech poziomach: aplikacji, będących źródłem danych, agentów (para: nadawca i odbiorca) realizujących zadania protokołów sieciowych oraz węzłów i łączy (tworzących topologię połączeń modelu). W łączach znajdują się kolejki (bufory), które mogą gromadzić się oczekujące na wysłanie pakiety. Cechą charakterystyczną pakietu jest szczególnie dokładnie zaimplementowany model protokołu TCP oraz związanych z nim protokołów aplikacji. Wobec tego budowa symulacji z jego zastosowaniem może być przeprowadzona bardzo szybko a dokładność uzyskiwanych wyników jest duża, co stanowi o głównej zalecie NS. W skład ramach pakietu wchodzą także inne, dobrze przetestowane mechanizmy, znajdujące odzwierciedlenie w istniejących rozwiązaniach i protokołach. Jednocześnie krytycy zarzucają NS skomplikowaną budowę wewnętrzną, utrudniającą rozbudowę poza już zaimplemenmtowane rozwiązania. SMURPH [Pawb] (System symulacji procesów zachodzących w czasie rzeczywistym, ang. System for Modeling Unslotted Real-time Phenomena). Przykład mniej popularnego narzędzia. Jest darmowy, a jego autorem jest Paweł Gbużyński z Departament of Computing Science University of Alberta w Edmonton w Kanadzie. Jest przykładem symulatorów z czasem ciągłym (z krokiem czasowym), co oznacza możliwość uzyskania dowolnej dokładności odmierzania czasu podczas przeprowadzania eksperymentu. Pakiet został zaprojektowany do modelowania protokołów sieciowych warstwy MAC modeli ISO/OSI. Modele opracowuje się w języku C++, a symulator zapewnia dodatkowe

12 8 ROZDZIAŁ 1. WPROWADZENIE TEORETYCZNE elementy składni, oraz dzięki rozbudowanej bibliotece klas, umożliwia szybką i czytelną implementację skomplikowanych protokołów. Istnieje kilka zaimplementowanych modeli, które dołączone są do plików symulatora. Sam pakiet nie jest już obecnie rozwijamy, jednak istnieje jego wersja rozwojowa SIDE/SMURPH [Pawa], przeznaczona do opracowywania, uruchamiania i kontroli sieci sensorowych, zarówno w zakresie symulacji jak i fizycznego obsługi fizycznych urządzeń włączonych w strukturę systemu. OMNeT++, popularny symulator zdarzeń dyskretnych będący przedmiotem niniejszej książki, którego szeroki opis wraz z przykładami znajduje się w kolejnych rozdziałach. W niniejszej książce skupiliśmy się na symulatorze OMNeT++ jako efektywnym rozwiązaniu, które oferuje wysoką wydajność, bogatą dostępną bibliotekę modeli, wygodne środowisko uruchomieniowe i łatwą implementację własnych modeli symulacyjnych. Poszczególne zagadnienia w książce obejmują przedstawienie zasad tworzenia modeli oraz przykłady wykorzystania OMNeT++. Zagadnienia przedstawiane są od poziomu ogólnego do szczegółów, które mogą mieć mniejsze znaczenie dla początkującego użytkownika. W założeniu autorów książka stanowi szerokie wprowadzenie do poznania i opanowania systemu OMNeT++, jednak w pewnych przypadkach należy skorzystać z instrukcji OMNeT++ [OMN], która powinna być źródłem dodatkowej wiedzy. Warto też korzystać z działającego od wielu lat forum dyskusyjnego, poświęconego OMNeT++ (

13 Rozdział 2 Pakiet OMNeT++ OMNeT++ [OMN] jest zintegrowanym środowiskiem do tworzenia symulacji zdarzeń dyskretnych, opracowanym i rozwijany przez Andreasa Vargę, początkowo w ramach Technical Uniwersytetu w Budapeszcie. W książce pakiet ten opisywane jest w najpopularniejszej obecnie, stabilnej wersji 3.3. Obecnie dostępna jest obecnie także wersja 4.x ze znacznie zmienionym zewnętrznym interfejsem i wieloma dodatkowymi mechanizmami. Opisane w książce elementy implementacji modeli w zdecydowanej większości pozostają one aktualne, jednak zmiany, szczególnie w zakresie interfejsu zewnętrznego (środowisko Eclipse) są znaczące. Zintegrowane zostały niezależne do tej pory programy do tworzenia topologii, analizy wyników i generowania wykresów. Pakiet OMNeT++ udostępniany jest za darmo do celów niekomercyjnych. Istnieje jego wersja komercyjna o nazwie Omnest ( ). Poza zakresem zastosowań różnice pomiędzy tymi pakietami są niewielkie i mają znaczenie raczej w przypadku wersji przeznaczonych dla systemu Microsoft Windows (wsparcie dla Microsoft Visual C++, instalator, biblioteki). Środowisko to składa się ze zbioru bibliotek i plików nagłówkowych w języku C++ (współpracuje zarówno gcc, jak również działa w środowisku Visual Studio), zestawu programów wspomagających tworzenie modeli i analizę wyników symulacji oraz środowisk uruchomieniowych: tekstowego (szybka realizacja symulacji) oraz graficznego (wizualizacji przebiegu symulacji wraz z animacją). Tworzenie modelu symulacyjnego w OMNeT++ polega na zdefiniowaniu elementów modelu i opisu topologii połączeń pomiędzy nimi w języku NED oraz zaprogramowania działania poszczególnych elementów w języku C++. Dzięki hierarchicznej i obiektowej architekturze można wielokrotnie wykorzystywać przygotowane wcześniej moduły. OMNeT++ udostępnia mechanizmy do graficznego tworzenia modelu, prezentacji przebiegu symulacji (co jest bardzo przydatne do weryfikacji poprawności jego działania) oraz klasy ułatwiające zbieranie i podstawową analizę statystyczną wyników. Dostępna jest szeroka gama gotowych modeli protokołów sieciowych, jak np. TCP/IP lub model sieci bezprzewodowych IEEE Środowisko zostało zaprojektowane z myślą o symulacji sieci komputerowych, lecz możliwe jest jego wykorzystanie do badań nad innymi modelami, opisanymi np. za pomocą modeli kolejkowych (modele ruchu drogowego lub kolejowego). W tym rozdziale opisywane są zasady tworzenia topologii modelu symulacyjnego i plików konfiguracyjnych, przedstawiane jest środowisko uruchomieniowe, a w dalszej części zasady tworzenia własnych modułów prostych (w C++). Dla wielu użytkowników do poznania możliwości OMNeT++ i prowadzenia badań wystarczające jest zapoznanie się z częścią dotyczącą tworzenia topologii i konfiguracji parametrów modelu. 9

14 10 ROZDZIAŁ 2. PAKIET OMNET Koncepcja budowy modelu symulacyjnego Na kompletny model symulacyjny składają się następujące elementy: opis topologii modelu symulacyjnego w języku NED (pliki.ned); implementacje modułów prostych w języku C++ (pliki.c oraz zazwyczaj pliki nagłówkowe.h); definicje komunikatów (jeśli zostały zdefiniowane) (pliki.msg); Zanim opisany zostanie dokładniej sposób tworzenia modeli i uruchamiania symulacji należy uściślić stosowaną w opisie terminologię. Szczególnego rozróżnienia należy dokonać pomiędzy określeniami definicja a deklaracja, które mają ściśle określone znaczenie w terminologii związanej z programowaniem komputerów. W OMNeT++ występuje pewna trudność polegająca na wykorzystaniu dwóch języków: NED do opisu topologii modelu i C++ do implementacji algorytmów działania elementarnych jednostek funkcjonalnych modelu (w terminologii OMNeT++ używa się tu określenia moduły proste). O ile jasne jest, co jest deklaracją, a co definicją na poziomie C++, o tyle w przypadku języka NED nie jest to już takie oczywiste i nieścisłości tych nie ustrzegli się w pewnych miejscach nawet autorzy instrukcji do OMNeT++. Przy tworzeniu modeli w OMNeT++ będziemy więc rozróżniać następujące określenia i związane z nimi czynności: Definicja typu modułu prostego lub Definicja modułu prostego - polega na utworzeniu nowego typu modułu prostego w języku NED, poprzez określenie jego nazwy oraz (opcjonalnie) zadeklarowanie jego parametrów i bram; Definicja typu modułu złożonego lub Definicja modułu złożonego - utworzenie nowego typu modułu złożonego w języku NED, poprzez określenie jego nazwy, modułów składowych (na podstawie wcześniej zdefiniowanych typów modułów prostych i złożonych) oraz (opcjonalnie) zadeklarowanie jego parametrów, bram i topologii połączeń wewnętrznych modułu; Utworzenie instancji modułu - moduły składowe zawsze są instancjami zdefiniowanych wcześniej typów. Wewnątrz definicji modułu złożonego tworzy się instancje modułów poprzez określenie w każdym przypadku nazwy i typu modułów. Przy tworzeniu instancji można (opcjonalnie) określić konfigurację parametrów i konfigurację bram dla tej konkretnej instancji; Moduł składowy - jest to konkretna instancja określonego typu modułu w ramach modułu złożonego; Definicja topologii połączeń lub Definicja topologii - utworzenie w ramach definicji modułu złożonego połączeń pomiędzy bramami modułów składowych oraz bramami zewnętrznymi tego modułu; Implementacja modułu lub implementacja algorytmu modułu - określenie aktywności (tylko dla zdefiniowanego modułu prostego) w postaci implementacji algorytmu jego działania w języku C++. Aby przeprowadzić symulację modelu należy uruchomić plik wykonywalny wraz z odpowiednim plikiem konfiguracyjnym (omnetpp.ini) oraz plikami opisu topologii (pliki.ned). Przed pierwszym uruchomieniem trzeba przeprowadzić kompilację modelu, z wykorzystaniem odpowiednich narzędzi dostarczonych razem z OMNeT++. Symulacja może zostać przeprowadzona w jednym w dwóch środowisk uruchomieniowych: graficznym (TkEnv) lub tekstowym (CmdEnv). Modyfikacja plików opisu topologii lub pliku konfiguracyjnego na ogół nie wymaga ponownej kompilacji modelu i tworzenia nowego pliku wykonywalnego 1. 1 W OMNeT++ 3.x zależy to od ustawień w pliku konfiguracyjnym, w OMNeT++ 4.x modyfikacja topologii nie wymaga ponownej kompilacji.

15 2.1. KONCEPCJA BUDOWY MODELU SYMULACYJNEGO 11 Na ten fakt warto zwrócić szczególną uwagę. Ma to znaczenie, jeśli chcemy dokonać modyfikacji już utworzonego modelu, w którym interesują nas jedynie zmiany w topologii połączeń oraz ew. parametrów jego działania. W takim przypadku użytkownik nie musi opracowywać kodu w języku C++ ani przeprowadzać procesu jego rekompilacji. Najczęściej wystarczające więc będzie jedynie zmodyfikowanie plików opisu topologii i konfiguracyjnych. Przydatna jest także możliwość przygotowania wielu wariantów symulacji modelu, różniących się topologią lub zestawem parametrów konfiguracyjnych. Wówczas wyboru odpowiedniego wariantu można dokonać bezpośrednio przed uruchomieniem symulacji. W ramach społeczności osób wykorzystujących pakiet OMNeT++ powstało wiele modeli symulacyjnych, które mogą być modyfikowane i wykorzystywane do badań przez osoby, które nie muszą mieć wprawy w programowaniu Hierarchiczność modelu Model symulacyjny jest instancją określonego, zdefiniowanego wcześniej typu modułu. Taki typ może posiadać budowę wewnętrzną, w szczególności może składać się z kolejnych modułów, będących instancjami kolejnych typów, aż do poziomu typów reprezentujących moduły proste. Tworzy to odpowiednią hierarchię, powiązaną za pomocą połączeń. Definicje typów modułów i topologię połączeń modelu tworzy się w specjalnym języku NED (ang. Network EDiting languge). Na najniższym poziomie hierarchii znajdują się tzw. moduły proste (simple). Moduły proste mogą być łączone w moduły złożone (module). Moduły złożone mogą składać się z instancji innych modułów złożonych oraz modułów prostych. Na najwyższym poziomie znajduje się model symulacyjny. Hierarchia powinna odzwierciedlać logiczną strukturę symulowanego układu. Schematycznie jest to przedstawione na Rys Rysunek 2.1: Struktura modelu Punkty wejścia i wyjścia z modułu zwane są bramami. Każdy moduł powinien posiadać takie bramy, które są następnie wykorzystywane do tworzenia połączeń między modułami. Moduły charakteryzowane są także przez parametry, określone przez identyfikatory i przypisane im wartości jednego z typów istniejących w NED (patrz 2.6).

16 12 ROZDZIAŁ 2. PAKIET OMNET++ W szczególnych przypadkach moduł może nie posiadać bram i parametrów. Połączenia i bramy mogą być tworzone dynamicznie bezpośrednio języku w C++. Taki przypadek może mieć zastosowanie np. w modelowaniu sieci bezprzewodowych lub sieci typu ah-hoc. Omawianie tego typu rozwiązań nie wchodzi jednak w zakres niniejszej książki. Dla zdefiniowanych modułów proste należy zaimplementować ich aktywność. Robi się to bezpośrednio w języku C++, z wykorzystaniem biblioteki symulacyjnej. Implementacja ta obejmuje reakcje na zdarzenia symulacji i określa zachowanie modelu. Dokładniej ten problem omówiony zostanie w podrozdziale 2.4 (Definiowanie modułów) Połączenia, bramki, komunikaty Moduły komunikują się ze sobą przesyłając komunikaty (ang. messages). Mogą być one tworzone i przetwarzane jedynie w modułach prostych, stanowiących najniższy poziom w hierarchii. Komunikaty są przysyłane do innych modułów poprzez bramy. Bramy są połączone ze sobą zgodnie z topologią połączeń, określoną w definicji modułu. Połączenia odwzorowują kanały komunikacyjne i mogą posiadać dodatkowe właściwości, takie jak np. przepustowość, opóźnienie i czas propagacji. Możemy wyróżnić połączenia wewnętrzne, między wejściami i wyjściami modułów podrzędnych, oraz zewnętrzne, z i do modułów nadrzędnych. Przykładową topologię bram i połączeń przedstawiono na Rys Komunikaty mogą być także przesyłane także do samego siebie, czyli do obiektu, który dany komunikat utworzył (tzw. self-messages). Taka możliwość okazuje się być często niezbędna np. aby przeprowadzić synchronizację, czy odwzorować komunikat typu TimeOut. Rysunek 2.2: Przykładowa struktura modelu złożonego.

17 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU Definicja modułów i tworzenie topologii połączeń modelu Nie zwracając uwagi na pewne przypadki szczególne, do stworzenia modelu symulacyjnego w OMNeT++ należy zdefiniować moduły i połączenia, pogrupować moduły na poszczególnych poziomach hierarchii modelu, aż do poziomu modelu symulacyjnego. Wszystkie moduły muszą posiadać opis w języku NED. Definicje modułów zapisywane są w plikach tekstowych z rozszerzeniem.ned. Definicje możemy tworzyć bezpośrednio w dowolnym edytorze tekstowym lub skorzystać z dołączonego do pakietu programu o nazwie GNED, który umożliwia edycję plików.ned w sposób graficzny. Zanim przejdziemy do systematycznego opisu tworzenia modeli w języku NED, przedstawmy prosty przykład, zgodne z Rys. 2.2 i 2.5. Do jego analizy nie będzie potrzebna dokładna znajomość składni języka NED. Plik modulyproste.ned opisuje podstawowe moduły symulacji, w których zachodzi przetwarzania komunikatów i które muszą zostać zaimplementowane bezpośrednio w języku C++. W przykładzie nie przedstawiamy tej implementacji, więc poniższy opis odnoszący się do funkcji tych modułów jest jedynie założeniem. 1 // Plik ModulyProste. ned 2 simple Generator 3 gates : 4 out : wyjscie ; 5 endsimple 7 simple Odbiorca 8 gates : 9 in: wejscie ; 10 endsimple 12 simple InterfejsSieciowy 13 gates : 14 out : wyjscie ; 15 in: wejscie ; 16 in: zgeneratora ; 17 out : doodbiorcy ; 18 endsimple Moduł Generator generuje pewne dane, które mają zostać przesłane do odbiorców. Z punktu widzenia języka NED jest to bardzo prosty moduł, który zawiera tylko jedno wyjście i nie zawiera żadnych parametrów. Podobnie, Odbiorca jedynie odbiera pewne dane, wobec czego posiada tylko jedną bramę wejściową, przez którą trafiają do modułu komunikaty zawierające właściwe dane. Moduł InterfejsSieciowy pełni rolę warstwy pośredniej, przyjmując i przekazując dane z zewnątrz poprzez bramy wejscie i na zewnątrz poprzez bramę wyjście. Poza tym przyjmuje dane od generatora poprzez bramę zgeneratora oraz przekazuje dane do odbiorcy przez bramę doodbiorcy. Należy podkreślić, że w pliku zdefiniowaliśmy nowe typy modułów, które teraz mogą być wykorzystane do utworzenia instancji tych modułów wewnątrz kolejnych definiowanych modułów (tym razem będą to moduły złożone). Budowa przykładowego modułu złożonego i utworzenie na jego podstawie modelu symulacyjnego jest przedstawiona w kolejnym przykładzie, w osobnym pliku modelsymulacyjny.ned, którego zawartość prezentujemy poniżej: 1 // Plik ModelSymulacyjny. ned 2 import " modulyproste. ned ";

18 14 ROZDZIAŁ 2. PAKIET OMNET++ 4 module BardzoProstyHost 5 gates : 6 in: wejscie ; 7 out : wyjscie ; 8 submodules : 9 interfejssieciowy : InterfejsSieciowy ; 10 odbiorca : Odbiorca ; 11 generator : Generator ; 12 connections : 13 generator. wyjscie --> interfejssieciowy. zgeneratora ; 14 interfejssieciowy. doodbiorcy --> odbiorca. wejscie ; 15 interfejssieciowy. wyjscie --> wyjscie ; 16 wejscie --> interfejssieciowy. wejscie ; 17 endmodule 19 module DwaHostyRazem 20 submodules : 21 bardzoprostyhost : BardzoProstyHost [2]; 22 connections : 23 bardzoprostyhost [0]. wyjscie --> bardzoprostyhost [1]. wejscie ; 24 bardzoprostyhost [1]. wyjscie --> bardzoprostyhost [0]. wejscie ; 25 endmodule 27 network ModelSymulacyjny : DwaHostyRazem 28 endnetwork Na początku znajduje się dyrektywa import, która dołącza plik z zadeklarowanymi wcześniej modułami prostymi. W pliku tworzymy moduł złożony BardzoProstyHost. Kolejne instrukcje opisujące ten moduł zawarte są w kolejnych sekcjach. W sekcji submodules określamy moduły składowe: nadawcę generator utworzoną jako instancję typu Generator, odbiorcę odbiorca (na podstawie typu Odbiorca) i moduł sieciowy interfejssieciowy (na podstawie InterfejsSieciowy). Moduł będzie posiadał dwie bramy zewnętrzne wejscie i wyjscie, co zostało określone w sekcji gates. Układ połączeń pomiędzy modułami składowymi i bramami zewnętrznymi określony jest w sekcji connections. Strukturę modułu przedstawiono na Rys Od momentu zdefiniowani abardzoprostyhost staje się nowym typem, który możemy znów wykorzystać przy tworzeniu dalszych modułów jako moduł składowy. W przykładzie tworzymy moduł złożony DwaHostyRazem, który zawiera dwa identyczne moduły typu BardzoProstyHost, które chcemy ze sobą połączyć. Instancje tego modułu utworzone są jako tablica (wektor) modułów o dwóch elementach. W sekcji connections łączymy wejścia i wyjścia tych modułów składowych. Proszę zwrócić uwagę, że moduł DwaHostyRazem nie ma żadnych bram zewnętrznych. Moduł DwaHostyRazem znów stanowi nowy tym, który może być wykorzystany przy kolejnych definicjach. Na koniec należy utworzyć właściwy model symulacyjny (network). Polega to na wskazaniu typu modułu, na podstawie którego chcemy oprzeć całą symulację. Na ogół będzie to moduł na najwyższym poziomie hierarchii. W opisywanym przykładzie skazujemy moduł DwaHostyRazem. Można także utworzyć kilka modułów typu network i wskazać właściwy w pliku konfiguracyjnym. Możliwe jest także wybranie odpowiedniego modułu podczas uruchamiania symulacji.

19 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 15 Rysunek 2.3: Moduł złożony, który stanowi podstawę do utworzenia modelu symulacyjnego Składnia języka NED Język NED umożliwia elastyczne definiowanie złożonych topologii i udostępnia wiele zaawansowanych właściwości. Składnia języka NED obejmuje następujące elementy: Polecenia importu danych z innego pliku.ned, co pozwala na włączenie zdefiniowanych wcześniej modułów lub połączeń do definiowanego modelu; Definicje modułów prostych simple; Definicje modułów złożonych module; Definicja kanałów transmisyjnych chanel; Definicje modelu symulacyjnego network. Identyfikatory Jako nazwy: modułów (modules), kanałów (channels), topologii modelu (networks), modułów składowych (submodules), parametrów (parameters), bram (gates) i funkcji (functions) należy stosować unikalne identyfikatory. Jako identyfikatorów nie należy używać zarezerwowanych słów języka NED, którymi są: import channel endchannel simple endsimple module endmodule error delay datarate const parameters gates submodules connections gatesizes if for do endfor network endnetwork nocheck ref ancestor true false like input numeric string bool char xml xmldoc Identyfikatory mogą składać się z kombinacji cyfr i liter angielskiego alfabetu oraz znaku podkreślenia _. Identyfikatory nie mogą zaczynać się od cyfry. Język NED rozróżnia małe i duże litery, więc IP i Ip oznacza dwa różne identyfikatory. Dla początkujących użytkowników pakietu OMNeT++ mylącym może być użycie znaków średnika oraz przecinka. Definiując parametry średnik umieszczany jest na końcu ostatniej linii listy parametrów (poszczególne parametry oddzielane są przecinkami). Definiując bramy, podmoduły oraz połączenia średnik umieszczamy na końcu każdej definicji. Podobna sytuacja występuje w przypadku znaku dwukropek (:). W przypadku bram dwukropek musi wystąpić bezpośrednio po słowach kluczowych in i out. W pozostałych przypadkach (np. definicja podmodułów) może być oddzielony znakami odstępu (spacja) od nazwy typu.

20 16 ROZDZIAŁ 2. PAKIET OMNET++ Zalecana konwencja nazewnictwa Autorzy OMNeT++ proponują stosowanie określonej konwencji przy nadawaniu identyfikatorów dla typów modułów, instancji modułów oraz bram. Zgodnie z tą konwencją identyfikator typu modułu (prostego lub złożonego) powinien zaczynać się z dużej litery (np. Router, Kolejka, Bufor). Identyfikatory poszczególnych parametrów oraz identyfikatory bram zaleca się rozpoczynać z małej litery. Identyfikatory dla instancji modułów także należy zaczynać z małej litery. Import danych Model symulacyjny może być umieszczony w wielu plikach.ned. W przypadku bardziej złożonych modeli pozwala to na lepsze odwzorowanie jego struktury hierarchicznej i logicznej. Pakiety symulacyjne takie jak np. INET, rozszerzające możliwości OMNeT++ składają się z wielu plików.ned opisujących podstawowe elementy funkcjonalne, takie jak karty sieciowe, protokoły, bufory. Tworzenie własnego modelu sprowadza się wtedy do odpowiedniego wykorzystania gotowych elementów. Oczywiście należy je wcześniej zaimportować. Służy do tego dyrektywa import po której musi pojawić się nazwa pliku (z rozszerzeniem.ned lub bez żadnego rozszerzenia). Przykład: import "modulyproste"; lub z rozszerzeniem: import "modulyproste.ned"; Komentarze w języku NED Komentarz rozpoczyna się sekwencją // i obowiązuje do końca bieżącej linii. Komentarze w NED mogą być także wykorzystane do automatycznego tworzenia dokumentacji. Dokładny opis tej właściwości znajduje się w dokumentacji [OMN]. Autorzy zwracają uwagę na to, że poprawnie i wyczerpująco skomentowany kod ułatwia późniejszą modyfikację utworzonych modeli. Szczególnie warto komentować znaczenie poszczególnych parametrów, których może być bardzo wiele, zwłaszcza dla rozbudowanych mechanizmów Usuwanie błędów składniowych Mimo, że opracowany kod jest na ogół czytelny i łatwy w analizie, przy pisaniu jednak własnych plików w języku NED użytkownicy trafiają na wiele trudności. Związane są np. z zasadami stosowania znaków odstępów w ściśle określonych miejscach, poprawnym tworzeniu instancji modułów czy użyciem identyfikatorów. Co prawda wszystkie wątpliwości rozwiązuje przedstawiona w dokumentacji gramatyka formalna, jednak dla większości użytkowników nie będzie ona użyteczna. W dalszej części książki przedstawiamy wskazówki co do istotnych dla poprawności kodu w NED szczegółów. Dobrym rozwiązaniem jest budowa modeli w oparciu o działające, wcześniej opracowane przykłady. Innym pomocnym rozwiązaniem będzie edycja lub przynajmniej próba otwarcia opracowanego pliku.ned w programie GNED (Patrz ). Jeśli w pliku jest błąd składniowy, program potrafi wskazać miejsce wystąpienia tego błędu (Rys. 2.4) Definicja modułów prostych Definicja modułu prostego wymaga określenia jego nazwy (nadanie identyfikatora) oraz opcjonalnych parametrów i bram (punktów wejścia i wyjścia) modułu. Schemat definiowanie modułów prostych jest następujący: 1 simple ModulProsty 2 parameters : 3 //...

21 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 17 Rysunek 2.4: Okno programu GNED ze wskazaniem błędu składniowego. 4 gates : 5 //... 6 endsimple W dalszej części omówiono dokładniej poszczególne sekcje tej definicji. Parametry Parametry modułu są deklarowane i definiowane są w sekcjach parameters: i reprezentują charakterystyczne właściwości tego modułu. Takimi parametrami mogą być np. maksymalna liczba hostów, średni czas obsługi, wielkość bufora itp. Z punktu widzenia składni NED parametrem jest określony i zdefiniowany i zadeklarowany w kodzie w NED element, posiadający identyfikator i typ, umożliwiający przekazanie argumentu do symulacji. Parametry modelu mogą być także odczytywane przez kolejne moduły w hierarchii modelu lub bezpośrednio z poziomu implementacji w C++. Dla każdego parametru można opcjonalnie określić jego typ (jako numeric, numeric const, const, bool, string, lub xml). Jeśli żaden typ nie został określony zakładany jest wtedy typ numeric jako domyślny. Parametry mogą być tworzone jako lista identyfikatorów, oddzielona przecinkami (z opcjonalnym określeniem typu w każdym przypadku), np: 1 parameters : 2 licznahostow, 3 maxliczbaklientow : const, 4 nazwadomeny : string ; Poszczególne typy określone są następująco:

22 18 ROZDZIAŁ 2. PAKIET OMNET++ numeric, numeric const, const - stałe i zmienne numeryczne. Jest to najczęściej stosowany parametr, określający zarówno liczby całkowite jak i zmiennoprzecinkowe. Znajduje także zastosowanie jako typ określający jednostki czasu, dla których można stosować następujące skróty: ns - nanosekundy (10 9 [s]) us - mikrosekundy (10 6 [s]) ms - milisekundy (10 3 [s]) s - sekundy (10 0 [s]) min - minuty (60 [s]) h - godziny (3600 [s]) d - dni (86400 [s]) bool - wartości logiczne (true false); string - łańcuchy znakowe; xml - parametrem jest nazwa pliku XML, po którym można się poruszać korzystając z języka zapytań XPath. Przykładowy moduł prosty, dla którego zdefiniowano zbiór parametrów prezentowany jest poniżej: 1 simple Generator 2 parameters : 3 odstepyczasu, 4 liczbakomunikatow : const, 5 adresodbiorcy : string ; 6 gates : //... 7 endsimple Wartości dla poszczególnych parametrów modułu ustalane są bezpośrednio w plikach NED, przy tworzeniu instancji modułu 2 : 1 //... wewnątrz definicji modułu złożonego... 2 generator : Generator 3 parameters : 4 liczbakomunikatow = 10; 5 //... Mogą być także określane w pliku omnetpp.ini 3 (oraz innych plikach konfiguracyjnych), np: 1 //... 2 przelacznik : Przelacznik 3 [ Parameters ] 4 modelsymulacyjny. generator. liczbakomunikatow = 15 5 //... Jeśli wartości zdefiniowanych parametrów nie zostały ustalone użytkownik zostanie poproszony o ich wprowadzenie przed uruchomieniem symulacji. 3 Mogą także być umieszczane jednocześnie w pliku konfiguracyjnym i w plikach.ned. Wówczas znaczenie mają tylko te ostatnie. Takie rozwiązanie jest jednak nieczytelne i nie powinno być stosowane. Zalecane jest ustalanie wartości parametrów tylko w pliku konfiguracyjnym.

23 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 19 Parametry w XML W określonych przypadkach modułów wymagają one znacznie bardziej złożonych danych konfiguracyjnych. Oczywiście zawsze można skorzystać z najprostszego rozwiązania i jako parametr podać nazwę pliku konfiguracyjnego jako parametr typu string i obsługiwać ten plik z poziomu C++, odczytując kolejne dane zgodnie z formatem pliku. Obecnie dużą popularność zdobył format XML, a OMNeT++ od wersji 3.x zawiera wbudowane mechanizmy związane z obsługą tego formatu (m.in. zawiera wbudowany parser formatu XML dla modelu DOM oraz XPath. Mechanizmy te dostępne są także z poziomu języka NED jak i z poziomu pliku konfiguracyjnego. W języku NED dysponujemy parametrem typu xml), np: 1 simple Generator 2 parameters : 3 konfiguracja : xml ; 4 gates : 5 //... Dla parametrów xml, w miejscu określania takiego parametru należy skorzystać z operatora xmldoc(). Operator ten pozwala na przekazanie jako parametr pliku XML lub jego części (określamy ją za pomocą ścieżek podobnie do XPath v.1.0). Można więc w NED zapisać wyrażenie: 1 konfiguracja = xmldoc (" konfiguracja. xml "); Można skorzystać ze ścieżki XPath: 1 konfiguracja = xmldoc (" konfiguracja. xml ", 2 "/ configuracja / profil = host ]") ; Analogiczne przypisanie można wykonać w pliku omnetpp.ini: 1 [ Parameters ] 2 **. interface [*]. config = xmldoc (" confuracja. xml ") 3 **. interface [2]. config = xmldoc (" interfejsy. xml ", 4 "/ config / interfaces / interface [2]") Ogólne zasady konstrukcji ścieżek dostępu do parametrów w plikach XML są następujące: wyrażenie zawiera sekcje, oddzielone przez / lub //; sekcja zawiera elementy, którymi może być identyfikator znacznika, znak *,. lub..; znak / oznacza element potomny (np: /usr/bin/gcc), znak // oznacza element rodzica (poziom wyżej); znak. oznacza bieżący element,.. poziom wyżej względem bieżącego, znak * element o dowolnej nazwie znacznika; zapis [@attribute= value ] oznacza konkretną wartość dla atrybutu. Przykłady: /korzen - odwołanie się do elementu korzenia (musi być określony jako <root>; /korzen/ala - pierwszy element <ala> występujący po elemencie <root>; //ala - pierwszy występujący element <ala>;

24 20 ROZDZIAŁ 2. PAKIET OMNET++ Bramy /*/ala - pierwszy element <ala>, który występuje po elemencie korzenia; /*/ala[0] - pierwszy element <ala> występujący po elemencie korzenia; /*/ala[1] - drugi element <ala> występujący po elemencie korzenia; /*/ala[@nazwisko= Nowak ] - pierwszy element <ala> występujący po elemencie korzenia, o atrybucie nazwisko określonym jako Nowak; //ala[2] - dowolny element <ala>, który jest trzecim potomkiem jakiegoś elementu rodzica; Poszczególne moduły tworzące model symulacyjny muszą się ze sobą komunikować. Z reguły taka komunikacja realizowana jest za pośrednictwem bram Bramy są to punkty wejścia i wyjścia z modułów, przez które będą wysyłane i odbierane komunikaty 4. Pomiędzy bramami tworzone są połączenia (zob ). Bramy mogą realizować połączenia tylko w określonym kierunku. Stąd wynika podział na bramy wejściowe (in) i wyjściowe (out). Moduł wysyła komunikaty przez bramy wyjściowe, a odbiera przez bramy wejściowe. Deklaracja bram realizowana jest w sekcji gates: każdej definicji modułu. Poszczególne bramy muszą posiadać unikalne w ramach tego modułu identyfikatory. Odpowiednie identyfikatory, oddzielone przecinkami, umieszcza się w podsekcji in: dla bram wejściowych i w podsekcji out: dla wyjściowych 5. Bardzo ważna jest także możliwość deklarowania wektorów bram (tablic), grupujących większą ich liczbę oraz pozwalająca parametryzować tę wielkość. Dostęp do poszczególnych bram realizowany jest wówczas za pomocą operatora indeksowania []. Bramy w takim wektorze numerowane są od zera. Można przy tworzeniu instancji określić wielkość wektora, lub nie określać tej wielkości (pozostawiając jedynie pusty operator indeksowania). Wówczas wielkość wektora zostanie ustalona na podstawie liczby przypisanych połączeń w sekcji connections: lub w sekcji gatesizes: modułu nadrzędnego. Poniższy przykład przedstawia tworzenie instancji dwóch typów modułów. Pierwszy (InterfejsSieciowy) ma po dwie bramy wejściowe i wyjściowe, drugi (Router) dwa wektory bram, których wielkość nie została określona. 1 simple InterfejsSieciowy 2 parameters : //... 3 gates : 4 in: portwejsciowy, odwarstwylaczadanych ; 5 out : portwyjsciowy, ddwarstwylaczadanych ; 6 endsimple 8 simple Router 4 Jak to zostało wspomniane wcześniej, można realizować komunikację między modułami bezpośrednio z pominięciem bram jednak takie rozwiązanie z wielu powodów nie powinno być stosowane. 5 W przypadku plików NED przy deklarowaniu bram występuje pewna niekonsekwencja, na którą warto zwrócić uwagę, gdyż może być ona źródłem błędów początkujących użytkowników. Mianowicie w pozostałych sekcjach (parameters, submodules) z lewej strony znaku dwukropek wstępuje nazwa instancji, z prawej typ. W sekcji gates jest inaczej: z lewej strony występuje słowo kluczowe (in lub out), a nazwa instancji, wykorzystywana w dalszej części definicji modułu, znajduje się z prawej strony. Często stosowane jest także konwencja: gates: in: in; out: out; w której nazwy bram z prawej strony (in, out) są takie same jak nazwy słów kluczowych oznaczających definicje bramy wejściowej i wyjściowej. Definicja taka jest w pełni poprawna, choć w pewnych przypadkach zmniejsza czytelność kodu.

25 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 21 9 parameters : // gates : 11 in: wejscie []; 12 out : wyjscie []; 13 endsimple Jeśli w modułach składowych bramy zostały zadeklarowane jako wektory, a wielkość tych wektorów została pominięta, wtedy w modułach nadrzędnych może znaleźć się sekcja Gatesizes 6, w której zostaną określone wielkości tych wektorów. Jeśli na przykład chcemy wykorzystać moduł Router z poprzedniego przykładu i ustalić, że powinien on posiadać num interfejsów (wejściowych i wyjściowych) definicja przykładowego modułu JakasSiec będzie wyglądać następująco: 13 module JakasSiec 14 parameters : 15 num ; 16 submodules : 17 // router : Router 19 parameters : 20 // gatesizes : 22 in[num ], out [ num ]; 23 // endmodule Wielkość bram instancji modułu typu Router o nazwie router będzie określona przez parametr num Definicja modułów złożonych Elementy związane z definiowaniem modułów złożonych i ich instancji pojawiały się już wcześniej w tekście, pora jednak usystematyzować te wiadomości. Definicja modułu tworzy nowy typ modułu. Należy mu więc nadać unikalny identyfikator. Typy te mogą być następnie wykorzystywane przy budowie modelu symulacyjnego, przez wykorzystanie ich do budowy modułów złożonych (ang. compound modules). Moduły złożone składają się z połączenia jednego lub więcej modułów składowych(submodules). Modułem składowym może być zarówno moduł prosty jak i moduł złożony. Moduły składowe określa się w sekcji submodules:. Definicja modułu złożonego związana jest ze słowem kluczowym module. Posiada sekcję deklaracji bram (gates:) i parametrów (parameters:), instancji modułów czyli modułów składowych (submodules) oraz sieci połączeń connections. Schemat takiej definicji wygląda następująco: 1 module CompoundModule 2 parameters : 3 //... 4 gates : 5 //... 6 submodules : 7 //... 8 connections : 9 // endmodule 6 Gdy brak jest sekcji Gatesizes dla wektorów bram, wówczas można odwoływać się jedynie do pozycji [0] tego wektora.

26 22 ROZDZIAŁ 2. PAKIET OMNET++ Parametry modułu złożonego są najczęściej wykorzystane do parametryzowanie modułów składowych, np: 1 generator : Siec 2 parameters : 3 pewienparametr = 10; 4 gates : 5 //... 6 submodules : 7 host : Host 8 parameters 9 parametrhosta = pewienparametr ; 10 //... Aby utworzyć więcej niż jedną instancję danego typu istnieje też możliwość wykorzystania operatora indeksowania [], np: 1 generator : SporaSiec 2 parameters : 3 liczbahostow = 100; 4 gates : 5 //... 6 submodules : 7 host : Host [ liczbahostow ]; 8 //... W dalszej części zajmiemy się dokładniej problemem tworzenia modułów składowych. Moduły składowe Moduły składowe tworzone są w sekcji submodules: jako instancje określonych typów. Należy określić identyfikator modułu składowego (instancji). Po znaku dwukropek : trzeba odwołać się do określonych typów modułów, za pomocą ich identyfikatorów. Definicje typów modułów muszą być znane w momencie uruchamiania symulacji (albo zadeklarowane wcześniej w pliku.ned albo włączone do pliku dyrektywą import (Patrz 2.2.1). Potem następuje określenie parametrów modułów składowych i wielkości wektorów bram (jeśli bramy tych modułów zostały zadeklarowane jako wektory). Można także utworzyć instancję więcej niż jednego moduł składowego danego typu. Wówczas tworzy się wektor modułów składowych określonego typu. W ten sposób możemy utworzyć określoną liczbę modułów danego typu (np. 100), czy tez uzależnić ich liczbę od wartości określonych parametrów. Podobnie jak w przypadku bram, dostęp do poszczególnych modułów składowych realizowany jest za pomocą operatora indeksowania [], a moduły w takim wektorze numerowane są od zera. Zasady te ilustruje prosty przykład: 1 //... fragment definicji modułu złożonego... 2 submodules : 3 router : Router ; 4 przelacznik : Przelacznik 5 parameters : 6 bufor = 10; 7 host1 : HostTypu1 [100]; 8 host2 : HostTypu2 [ maksimum ]; 9 kartyradiowe : KartaRadiowa [2* minimum +1]; 10 //...

27 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 23 W linii 3 mamy utworzenie instancji modułu (jako modułu składowego), któremu nadajemy nazwę router. Pod tą nazwą będzie teraz dostępny w ramach tworzonego modułu złożonego. Jest on tworzony w oparciu o typ modułu Router. W linii 4 mamy instancję modułu o nazwę przelacznik, opartego o typ Przelacznik. Moduł ten wymaga określenia parametru o nazwie bufor. Parametr ten ustalamy w sekcji parameters: na wartość 10. W linii 7 tworzymy wektor modułów składowych, o nazwie host1. Chcemy, aby utworzyć 100 instancji tego typu, więc korzystając z operatora indeksowania ustalamy taką wartość przy nazwie typu (HostTypu1[100]). Analogiczna sytuacja występuje w linii 8 dla wektora modułu składowego o nazwie host2, z tym, że liczbę tych instancji chcemy ustalić na podstawie parametru o identyfikatorze maksimum. Korzystając z operatora indeksowania definiujemy więc (HostTypu2[maksimum]). W linii 9 mamy przykład wyrażenia, gdzie liczbę modułów podrzędnych kartyradiowe ustala się jako wynik (2*minimum+1). Dokładniej wyrażenia opisane są w Sekcja gatesizes W przypadku, gdy wielkość wektorów bram wejściowych modułów składowych nie została określona przy ich deklaracji, rozmiar ten umieszcza się w sekcji gatesizes, jak na przykładzie poniżej: 1 simple Modul 2 gates : 3 in: wejscia []; 4 out : wyjscia []; 5 endsimple 7 module ModulZlozony 8 parameters : 9 liczbabram : const ; 10 submodules : 11 modulskladowy1 : Modul 12 gatesizes : 13 wejscia [2], wyjscia [2]; 14 modulskladowy2 : Modul 15 gatesizes : 16 wejscia [ liczbabram ], wyjscia [ liczbabram ]; 17 // endmodule Moduł prosty Modul nie ma określonej wielkości dla wektora bram wejściowych i wyjściowych. W module złożonym ModulZlozony, tworzone są dwa modułu składowe. Moduł modulskladowy1 ma ustaloną liczbę bram w wektorze na wartość 2. Moduł modulskladowy2 ma ustaloną liczbę bram na podstawie parametru liczbabram. Określanie wielkości wektora bram nie jest obowiązkowe. Jeśli wartość ta nie zostanie ustalona OMNeT++ przyjmuje wartość 0 jako domyślną. Wówczas można rozszerzać ten wektor korzystając z operatora inkrementacji ++, co zostanie omówione w następnym podrozdziale. Połączenia w ramach modułów złożonych Ponieważ moduły składowe posiadają określone bramy konieczne jest także zdefiniowanie topologii połączeń między nimi (połączenia wewnętrzne) oraz pomiędzy bramami właściwego modułu złożonego (połączenia zewnętrzne). Na rys. 2.1 połączenia pomiędzy modułem kolejka a modułem serwis są

28 24 ROZDZIAŁ 2. PAKIET OMNET++ połączeniami wewnętrznymi, a połączenia między bramami wejściowymi modułu stanowisko_obslugi a modułem kolejka jest połączeniem zewnętrznym. Definiowanie połączeń realizowane jest w sekcji connections. Łączy się bramy poszczególnych modułów składowych oraz bramy wejściowe/wyjściowe definiowanego modułu. Bramy wyjściowe łączy się w bramami wejściowymi, wejściowe z wyjściowymi (out -> in, in < - out). Poszczególne połączenia oddzielamy znakiem średnik (;). Należy pamiętać, że dla jednej bramy może być przypisane tylko jedno połączenie. Nie ma więc możliwości podłączenia wielu połączeń wyjściowych do jednej bramy wejściowej i odwrotnie. W takich wypadkach należy zadeklarować odpowiednie wektory bram. Dostęp do poszczególnych bram modułów podrzędnych uzyskujemy poprzez operator kropki. i określenie nazwy bramy, umieszczone po nazwie instancji konkretnego modułu. Dostęp do bram na poziomie definiowanego modułu uzyskujemy podając jedynie nazwę bramy (bez operatora kropka). Jeśli przykładowo chcemy połączyć wejścia i wyjścia (o nazwach wejscie, wyjscie) dwóch modułów (host1, host2), definicja będzie miała następującą postać: 1 //... 2 connections : 3 host1. wyjscie --> host2. wejscie ; 4 host1. wejscie <-- host2. wyjscie ; 5 //... W bardziej złożonych topologiach (tworzenie grafów czy drzew połączeń, siatek itp.) oraz w przypadkach, kiedy liczba modułów i bram określana jest na podstawie parametrów (określonych np. w pliku konfiguracyjnym), konieczne jest skorzystanie z bardziej zaawansowanych mechanizmów tworzenia topologii. Do dyspozycji mamy możliwość tworzenia pętli (for) oraz operator inkrementacji (++). Z pętli for korzysta się na ogół wtedy, gdy do określenia wielkości wektora bram wejściowych wykorzystano sekcję gatesizes. Określoną wielkość tego wektora możemy wykorzystać do sparametryzowania pętli. Tworząc pętlę określamy jedną lub więcej zmiennych iteracyjnych, których wartość będzie się zmieniać w zakresie od wartości najmniejszej min do największej max włącznie (min...max). W ciele pętli (po słowie kluczowym do) kolejne instrukcje oddzielane są znakiem średnik (;). Pętle kończymy słowem kluczowym endfor. Zasady te pozwalają wygodnie tworzyć połączenia zarówno prostych topologii, jak i bardzo złożonych. Najlepiej zilustrują to przykłady. W pierwszym łączymy pięć portów wychodzących modułu router z 5 portami wejściowymi modułów host (indeksowanych w zakresie 0..4): 1 //... 2 connections : 3 for i =0..4 do 4 router. out [i] --> host [i]. in; 5 endfor ; 6 //... Układ połączeń jaki otrzymamy przedstawia Rys Można tworzyć także pętle zagnieżdżone, przydatne przy tworzeniu topologii wielowymiarowych (siatki, hyperkostki itp). 1 //... 2 for i =0..4, j =0..4 do 3 // w~ petli wartosci : 4 // [i=0, j=0], [i=0, j=1], [i=0, j=2], [i=0, j=3], [i=0, j =4] 5 // [i=1, j=0], [i=1, j=1], [i=1, j=2], [i=1, j=3], [i=1, j =4] 6 //... 7 endfor ;

29 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 25 Rysunek 2.5: Przykład połączeń utworzonych za pomocą pętli for. 8 //... Możliwe jest także wykorzystywanie zmiennych iteracyjnych do tworzenia pętli zagnieżdżonych: 1 //... 2 for i =0..3, j=i do 3 // w~ petli wartosci : 4 // [i=0, j=1], [i=0, j=2], [i=0, j=3], [i=0, j =4] 5 // [i=1, j=2], [i=1, j=3], [i=1, j =4] 6 // [i=2, j=3], [i=2, j =4] 7 // [i=3, j =4] 8 endfor ; 9 //... Często w pętlach występuje konieczność uwzględnienia pewnych specyficznych warunków, które wpływają na tworzenie poszczególnych połączeń. W OMNeT++ mamy do dyspozycji słowo kluczowe if, umieszczane na końcu instrukcji, po którym występuje wyrażenie warunkowe. Spełnienie tego wyrażenia oznacza, że definiowane w tej instrukcji połączenie jest uwzględniane, w przeciwnym wypadku instrukcja jest ignorowana. Przykładowo, gdy chcemy połączyć bramy modułu router1 do modułów host o parzystych numerach a modułu router2 do modułów o nieparzystych numerach, konstrukcja pętli może być następująca: 1 //... 2 for i =0.. n do 3 router1. out [i /2] --> host [i]. in if i %2==0; 4 router2. out [i /2] --> host [i]. in if i %2!=0; 5 endfor ; 6 //... Dla przypadku n=4 otrzymamy topologię jak na Rys W przypadku, gdy wielkości wektora bram wejściowych nie zostały zdefiniowane (brak sekcji gatesizes 7 konieczne jest wykorzystanie operatora inkrementacji (++). W przypadku języka NED operator ++ pełni raczej funkcję operatora rozszerzającego, jednak aby nie wprowadzać dodatkowego terminu w tekście stosowana będzie powszechnie przyjęta nazwa operatora inkrementacji. Operator ten rozszerza wektor wejściowy bramy o jeden (czyli dodaje jedną nową bramę, o kolejnym indeksie). Odwołanie będzie się odnosiło do nowododanej bramy. Tak więc, jeśli bramy out i in modułów node1 i node2 zostały określone jako wektory, bez definiowania ich wielkości, sekwencja poniższa spowoduje utworzenie czterech bram wyjściowych

30 26 ROZDZIAŁ 2. PAKIET OMNET++ Rysunek 2.6: Przykład połączeń utworzonych za pomocą pętli for z wykorzystaniem warunku if. modułu node1 o numerach [0..3] i odpowiednie ich podłączenie do utworzonych bram wejściowych modułu node2: 1 connections : 2 node1. out ++ -> node2.in ++; 3 node1. out ++ -> node2.in ++; 4 node1. out ++ -> node2.in ++; 5 node1. out ++ -> node2.in ++; Ze względu na to, że pętla for może inkrementować wartości w zakresie dowolnych parametrów (a nie tylko wielkości bram wejściowych), można także stosować jednocześnie pętlę for oraz operator ++. Przypadek przedstawiony na Rys. 2.6 może więc przybrać następującą postać: 1 //... 2 for i =0.. n do 3 router1. out ++ --> host [i]. in if i %2==0; 4 router2. out ++ --> host [i]. in if i %2!=0; 5 endfor ; 6 //... Jest to możliwe przy założeniu, że dla modułów router1 i router2 nie określono wielkości wektorów bram wyjściowych, natomiast określone zostały dla modułów host (n bram wejściowych). W przykładzie tym dla modułów host o indeksach parzystych dodawana jest brama wyjściowa w module router1, a dla nieparzystych w router2. Operator sizeof Jeśli wielkość wektorów bram dla modułów składowych została określona, użytecznym i często wykorzystywanym operatorem jest sizeof(), który zwraca rozmiar wektora bramy (w przypadku gdy rozmiar ten został określony za pomocą parametru). Wykorzystywane jest to zazwyczaj przy tworzeniu pętli, w których zakres iterowanych wartości jest ustalony za pomocą tego operatora. Ilustruje to prosty przykład: 1 module ModulZlozony 7 Autorzy, bazując na własnym doświadczeniu, nie zalecają budowanie topologii modelu bez zdefiniowania wielkości wektorów w sekcji gatesizes. Zmniejsza to czytelność kodu i może powodować błędy. Oczywiście istnieją przypadki, kiedy wykorzystanie operator ++ może okazać się wygodne, dlatego warto zapoznać się z tym rozwiązaniem i stosować go jedynie do tych, uzasadnionych przypadków.

31 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 27 2 parameters : 3 numwe : const ; 4 numwy : const ; 5 gates : 6 in: wejscia [ numwe ]; 7 out : wyjscia [ numwy ]; 8 submodules : 9 modulskladowy : Modul ; 10 gatesizes : 11 we[ sizeof ( wejscia )], 12 wy[ sizeof ( wyjscia )]; 13 connections : 14 for i= 0.. sizeof ( wejscia ) -1 do 15 wejscia [i] --> modulskladowy [i]. we; 16 endfor ; 17 for i= 0.. sizeof ( wyjscia ) -1 do 18 wyjscia [i] <-- modulskladowy [i]. wy; 19 endfor ; 20 endmodule Moduł złożony posiada liczbę wejść i wyjść zależna od parametrów. Liczbę wejść i wyjść określamy korzystając z operatora sizeof. Następnie ten sam operator wykorzystywany jest do ustalenia zakresu iteracji w pętli for. Operator index Przy okazji warto wymienić inny, użyteczny operator index, który dla każdego modułu składowego przyjmuje wartość jego indeksu (kolejny numer) w wektorze modułów składowych. Można go wykorzystać np. do dynamicznego tworzenia unikalnego identyfikatora modułu, a także tworzenia bardziej złożonych topologii połączeń, w których numer modułu składowego ma znaczenie. 1 module ModulZlozony 2 parameters : 3 liczbamodulow : const ; 4 //... 5 submodules : 6 modulskladowy : Modul [ liczbamodulow ]; 7 parameters : 8 mojnumer = 1+ index ; // wartości dla kolejnych modułów : 1,2, //... Modyfikator nocheck Domyślnie OMNeT++ wymaga, aby wszystkie bramy zdefiniowane w plikach NED były podłączone. Niespełnienie tego warunku spowoduje błąd przy uruchamianiu symulacji, co ma zapewnić poprawność definiowanych modeli. Często zdarza się jednak, że niektóre bramy pozostają niepodłączone i nie jest to spowodowane błędną definicją, a użytkownik jest świadomy takiej sytuacji. Dzieje się tak na przykład przy dynamicznie tworzonych topologiach (np. topologii siatki, w której połączenia tworzone są w pętli, w której moduły skrajne nie posiadają pewnych sąsiadów) lub w przypadku, gdy połączenia tworzone są losowo. Oczywiście zawsze można zapewnić spełnienie warunku łączenia wszystkich bram, ale na ogół w znaczny sposób komplikuje kod, nie niosąc ze sobą żadnych znaczących korzyści. Na przykład w topologii siatki należało

32 28 ROZDZIAŁ 2. PAKIET OMNET++ by rozróżniać węzły brzegowe przez definiowanie odrębnych typów, różniących się od siebie wielkością wektorów bram. Aby rozwiązać ten problem można skorzystać z zapisu connections nocheck:, który pozwala wyłączyć mechanizm kontroli w odniesieniu do danego modułu. Poniższy przykład ilustruje warunkowe tworzenie połączenia pomiędzy modułami w zależności od wyniku losowania liczby z zadanego rozkładu (uniform(0,1)): 1 module PolaczeniaLosowe 2 parameters : //.. 3 gates : //.. 4 submodules : //.. 5 connections nocheck : 6 for i =0..n -1, j =0..n -1 do 7 node [i]. out [j] --> node [j]. in[i] if uniform (0,1) <0.3; 8 endfor ; 9 endmodule Zapis taki powoduje, że nie dla każdej bramy przypisywane są połączenia. Zapis bez modyfikatora nocheck uniemożliwiałby uruchomienie symulacji. Tworząc podobne rozwiązania z nocheck: pojawia się pewien problem na poziomie implementacji aktywności w C++. Należy uwzględnić fakt, że niektóre bramy są niepodłączone i wysyłanie przez nie komunikatów nie powinno mieć miejsca. OMNeT++ dostarcza jednak odpowiednich metod, które pozwalają to sprawdzić (Patrz 2.4) Wyrażenia w języku NED Warto wspomnieć także o możliwości tworzenia rozbudowanych wyrażeń arytmetycznych bezpośrednio w języku NED. Wartość otrzymana na podstawie wyrażenia może być następnie użyta jako np. wartość parametru, rozmiar tablicy itp. Wyrażenia arytmetyczne mogą być rozbudowane. Możemy korzystać w nich z operatorów przedstawionych poniżej (w kolejności priorytetów): -,!, ~ operatory jednoargumentowe: minus, negacja, negacja bitowa; ^ potęga; *, /, % +, - <<, >> &,, # ==!= mnożenie, dzielenie, reszta z dzielenia; dodawanie, odejmowanie, odejmowanie; równe; przesunięcie bitowe (w lewo, w prawo); nie-równe; >, >=, <, <= &&,, ##?: operacje bitowe (and, or, xor); relacje: większe, większe równe, mniejsze, mniejsze równe; operatory logiczne (and, or, xor); instrukcja warunkowe (na wzór C/C++). Przy budowaniu wyrażeń możemy także korzystać ze zdefiniowanych funkcji matematycznych, m.in.: sin(x), cos(x), log(x), exp(x), floor(x), ceil(x). Dodatkowo zdefiniowano bogaty zestaw funkcji do generowania liczb pseudolosowych wg. zadanych rozkładów (ciągłych i dyskretnych). Wszystkie te funkcje zostały szczegółowo opisane w dokumentacji [OMN].

33 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU Określanie parametrów połączeń Dla każdego z połączeń możemy opcjonalnie określić kombinację określonych parametrów (w nawiasach słowa kluczowe): opóźnienie propagacji [s] (ang. propagation delay) (delay); stopa błędów [errors/bit] (ang.bit error rate) (error); przepustowość [bits/s] (ang. data rate) (datarate); Opóźnienie propagacji określa czas (w sekundach), jaki upłynie od wysłania komunikatu przez nadawcę do odebrania go przez odbiorcę. Stopa błędów odpowiada prawdopodobieństwu przekłamania danych przesyłanych w komunikacie, określone dla każdego bitu. Z tego wynika, że prawdopodobieństwo p, że w komunikat o długości n bitów zostanie poprawnie przesłany przez połączenie ze stopą błędów er wynosi: p = (1 er) n. Fakt wystąpienia przekłamania danych w komunikacie jest odnotowywany przez ustawienie specjalnej flagi (do obsłużenia z poziomu C++). Przepustowość określa się w bitach na sekundę. Czas przesyłu komunikatu mierzy się więc od momentu wysłania pierwszego bitu do momentu odebrania ostatniego bitu komunikatu. Czas transmisji komunikatu o długości n bitów równy T = opoznieniep ropagacji+n/przepustowosc Parametry te można określać przy definiowaniu połączeń, np: 1 //... 2 connections : 3 komp1. out --> datarate error 1e -9 delay > komp2. in; 4 //... Można także zdefiniować bezpośrednio w plikach.ned własne typy połączeń i wykorzystywać je w ramach całego modelu symulacyjnego. Definicja zaczyna się od słowa kluczowego (channel) i polega na podaniu nazwy połączenia i określeniu jego parametrów, np: 1 channel mychannel 2 delay error 1e -9 4 datarate endchannel Dzięki takiej definicji możemy wykorzystywać zdefiniowaną nazwę kanału np: 1 //... 2 connections : 3 komp1. out --> mychannel --> komp2. in; 4 // Szczegółowe zasady przesyłu komunikatów Przesyłanie komunikatów poprzez bramy, z wykorzystaniem połączeń (zgodnie z parametrami tego łącza) zilustrowane jest na Rys.2.7. Komunikat po wysłaniu (zdarzenie wysłanie komunikatu) dotrze do odbiorcy po czasie wynikającym z określonej przepustowości łącza (która wprowadza określone opóźnienie transmisji) oraz po określonym czasie propagacji. Dopiero wtedy odbiorca odbierze komunikat związany ze zdarzeniem nadejście komunikatu. Konsekwencja takiego rozwiązania jest pewne ograniczenie związane z przekazywanie komunikatów przez kilka węzłów. Mianowicie, aby węzeł pośredni mógł przesłać komunikat do kolejnego węzła, musi on zostać odebrany. Zasada ta została zilustrowana na Rys. 2.8.

34 30 ROZDZIAŁ 2. PAKIET OMNET++ Rysunek 2.7: Przesyłanie komunikatu pomiędzy dwoma węzłami [OMN]. Nie można więc bezpośrednio implementować funkcjonalności, w której węzeł rozpoczyna przekazywanie komunikatu dalej, zanim jeszcze został on w pełni odebrany. Mechanizm taki występuje w pewnych urządzeniach sieciowych, np. w przełącznikach działających zgodnie z metodą cut-throught, w których przekazywanie ramek pomiędzy segmentami sieci odbywa się zaraz po przetworzeniu nagłówka, jednak jeszcze zanim odebrana zostanie cała ramka (zwiększa to efektywność pracy przełącznika). Przy budowie modelu w takich przypadkach należy dokonać podziału komunikatu na mniejsze elementy (np. oddzielając dane od nagłówka) i przesyłać je w odrębnych komunikatach lub generować osobne komunikaty dla rozpoczęcia i dla zakończenia transmisji Definiowanie funkcji użytkownika W plikach języka NED poza zdefiniowanymi już funkcjami matematycznymi i losowymi użytkownik może używać własnych. W tym celu należy opracować kod odpowiedniej funkcji w języku C++ i zarejestrować ją za pomocą makra Define_Function(). Dokładniej reguły definiowania takich funkcji i ich ograniczenia zostały opisane w [OMN] Definicja sieci symulacyjnej Do tej pory zajmowaliśmy się definiowaniem modułów bez wyróżniania, na bazie którego z modułów uruchomiona ma być właściwa symulacja. Do uruchomienia więc symulacji konieczne jest określenie tzw. definicji sieci (ang. network definition). Polega ono na wskazaniu (utworzeniu instancji) jednego z uprzednio definiowanych modułów 8. Można w tym celu wykorzystać jedynie te moduły, które nie mają żadnych bram, bo moduł będący podstawą symulacji nie może mieć żadnych połączeń zewnętrznych. Składnia podobna jest do definicji modułu prostego. Określa się unikalną nazwę, a po znaku dwukropek (:) nazwę modułu, który jest podstawą sieci. W najprostszym przypadku wygląda to następująco (definicja sieci o nazwie segmentlan na podstawie modułu SegmentLAN): 1 network segmentlan : SegmentLAN 2 endnetwork ; Można także opcjonalnie określić parametry (w sekcji parameters), które zostaną przekazane do instancji modułu, np (por ), np.:

35 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 31 Rysunek 2.8: Przekazywanie komunikatu przez węzeł pośredni [OMN]. 1 network wirelesslan : WirelessLAN 2 parameters : 3 numusers =10, 4 httptraffic = true, 5 ftptraffic = true, 6 distancefromhub = truncnormal (100,60) ; 7 endnetwork Sekcja parameters jest opcjonalna, gdyż parametry te można także określić w pliku konfiguracyjnym omnetpp.ini lub, jeśli nigdzie nie zostaną określone, użytkownik będzie poproszony o określenie tych parametrów przed uruchomieniem symulacji. Można zdefiniować wiele sieci symulacyjnych. Uruchamiając symulację najczęściej wskazuje się w wybraną sieć (poprzez podanie unikalnej nazwy) w pliku konfiguracyjnym omnetpp.ini Właściwości graficzne komponentów Uruchomienie symulacji w trybie w wizualizacją (środowisko Tkenv, por ) powoduje, że poszczególne komponenty symulacji (moduły, komunikaty, połączenia) prezentowane są w oknie graficznym. Można śledzić przebieg symulacji, włącznie z animacją (we wszystkich trybach poza trybem Express). Symulator, na podstawie opisu w języku NED, rozmieszcza komponenty w oknie graficznym. Czasami jednak, np. dla topologii o charakterze dynamicznym, rozmieszczenie tych elementów jest przypadkowe i utrudnia śledzenie symulacji. Użytkownik ma jednak wpływ na sposób rozmieszczania komponentów, zarówno z poziomu języka NED, jak i z poziomu C++. Graficzne rozmieszczanie komponentów W przypadku symulacji przeznaczonych do szerszej dystrybucji, na przykład do celów edukacyjnych, ale także w innych przypadkach nie powinno się zaniedbywać możliwości związanych z oprawą graficzną 8 W większości przypadków będzie to jeden z modułów złożonych, chociaż teoretycznie możliwe jest także użycie w tym miejscu modułu prostego (cała symulacja zdefiniowana w języku C++ w ramach jednego modułu).

36 32 ROZDZIAŁ 2. PAKIET OMNET++ tworzonych modeli. OMNeT++ dysponuje możliwościami podglądu przebiegu symulacji włącznie z animacją. Dobranie więc właściwych elementów graficznych i ikon znacznie poprawia czytelność symulacji. Możliwość graficznego formatowania i rozmieszczania komponentów w oknie podglądu symulacji polega na dodawaniu do plików w języku NED specjalnych łańcuchów formatujących wyświetlanie (w dokumentacji OMNeT++ stosuje się określenie display strings). Łańcuch taki składa się jednego lub więcej parametrów formatujących, rozdzielonych znakiem średnik (;), umieszczonych w cudzysłowach ("..."), np: "p=100,100;b=60,10,rect;o=blue,black,2" Poszczególne wartości dla konkretnych parametrów mogą zostać pominięte. Wówczas pozostaje przecinek rozdzielający i przypisana zostanie wartość domyślna, np: "p=100,100;b=,,rect;o=blue,black" W łańcuchach formatujących można uwzględniać parametry modułu. Należy wówczas poprzedzić je znakiem dolar ($), np: "p=$x,$y;b=rect,60,10;o=$kolor,black,2" Łańcuchy formatujące umieszcza się w wyrażeniach języka NED po słowie kluczowym display. Występuje tutaj pewna niedogodność formalna, wynikająca ze składni. W częściach dotyczących całego modułu złożonego lub modułów podrzędnych słowo to umieszcza się tak jak sekcję, razem z znakiem dwukropek (:) a kończąc znakiem średnik (;). Natomiast przy definiowaniu wyglądu graficznego połączeń to słowo kluczowe umieszcza się już bez znaku dwukropek. Najlepiej zilustruje to przykładowy zapis w języku NED, w którym wykorzystano łańcuchy formatujące: 1 module ClientServer 2 submodules : 3 pc: Host ; 4 display : " p =66,55; i= comp "; // Pozycja oraz ikona graficzna modułu podrzędnego 5 server : Server ; 6 display : "p =135,73; i= server1 "; 7 connections : 8 pc.out --> server.in 9 display " m=m,61,40,41,28"; // Wygląd dla polaczenia. Uwaga, tu nie ma znaku ":"!!! 10 server. out --> pc.in 11 display " m=m,15,57,35,69"; 12 display : " o =# ffffff "; // kolor tla calego modulu zlozonego. Jest znak ":" 13 endmodule Do określania parametrów modułu używa się współrzędnych X, Y, określanych względem modułu nadrzędnego. Lewy górny róg modułu nadrzędnego ma współrzędne określone jako X=0, Y=0. Można także używać wartości ujemnych, przesuwając komponenty poza obrys modułu nadrzędnego. Opiszemy teraz krótko najważniejsze możliwości formatowania: p=x,y umieszcza moduł podrzędny (lewy górny róg) na pozycji określonej współrzędnymi X,Y. Jeśli zastosujemy to formatowanie do wektora modułów podrzędnych, parametry odnoszą się do pierwszego modułu, a kolejne moduły zostaną rozmieszczone automatycznie; Jeśli deklarowany jest wektor modułów podrzędnych, możemy także sprecyzować rozmieszczenie elementów tego wektora. Wykorzystywane jest także ustawienie p=x,y... Jako kolejny parametr ustawia się jeden z kilku możliwych sposobów rozmieszczania, następnie ew. dodatkowe parametry:

37 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 33 p=x,y,row,deltax p=x,y,column,deltay p=x,y,matrix, itemsperrow,deltax,deltay p=x,y,ring,width,height p=x,y,exact,deltax,deltay Kolejno są to więc następujące oznaczenia typów rozmieszczania 9 : row - moduły rozmieszczane w rzędzie (poziomo), deltax określa odległość pomiędzy elementami w poziomie; column - moduły rozmieszczane w kolumnie (pionowo), deltay określa odległość pomiędzy elementami w pionie; matrix - moduły rozmieszczane w tablicy, itemsperrow określa liczbę elementów w rzędzie; ring - moduły rozmieszczane w łańcuchu typu ring, o określonej szerokości width i wysokości height; exact - moduły rozmieszczane w ściśle określonych pozycjach (Xpos+deltax, Ypos+deltay). ustawienie takie ma sens tylko wtedy, gdy Xpos,Ypos jest odpowiednio sparametryzowane, np.("p=100,100,exact,$x,$y"). Rysowanie figur geometrycznych jako symboli modułów może być zapisane jako: b=width,height,rect b=width,height,oval Stosowane są oznaczenia: rect - prostokąt o określonej wysokości i szerokości, domyślnie width=40, height=24; oval - elipsa o określonej wysokości i szerokości, domyślnie width=40, height=24; Dla prostokątów i elips możliwe jest ustawianie kolorów wypełnienia (fillcolor), kolorów obrysu (outlinecolor) i grubości linii (borderwidth). Stosujemy zapis: o=fillcolor,outlinecolor,borderwidth Domyślnie przyjęte są wartości fillcolor=#8080ff (jasnoniebieski), outlinecolor=black, borderwidth=2. Użycie kolorów Warto przy okazji wyjaśnić stosowaną konwencję definiowania kolorów. Akceptowane są angielskie nazwy oraz numeryczne oznaczenia kolorów, zgodne ze specyfikacją języka TclTk (zob. membres.lycos.fr/fbonnet/tcl/tkgs/specs Mamy więc oznaczenia: red, black, white, blue, lightgray, wheat itd. Numeryczne oznaczenia są kolorów możliwe zgodnie z konwencja #rgb, gdzie r, g, b są liczbami w formacie hex (heksadecymalnym) 10. Komponenty jako ikony graficzne Kolejną przydatną opcją jest możliwość reprezentacji komponentów w postaci ikon. Ikony są to pliki graficzne w formacie GIF. Zbiór dostępnych ikon znajduje się standardowo w katalogu z zainstalowanym OMNeT++, w podkatalogu bitmaps/. Przykładowy zbiór ikon prezentowany jest na Rys Zbiór ikon dostarczany razem z pakietem OMNeT++ jest bardzo szeroki i obejmuje symboliczną reprezentację większości urządzeń i aspektów działania sieci, a także obiektów abstrakcyjnych. Możliwe jest także dodawanie własnych zbiorów ikon zostało to opisane w w części dotyczącej konfiguracji środowiska Tkenv. Ikony przypisujemy do komponentów używając zapisu: "i=iconname,color,percentage" 9 Można także stosować skróty: r dla row, c dla column, m dla matrix, ri dla ring, e lub x dla exact. 10 Możliwe jest także użycie formatu barwa-jasność-nasycenie HSB (ang. hue-saturation-brightness) (wartości w formacie hex).

38 34 ROZDZIAŁ 2. PAKIET OMNET++ W zapisie tym iconname określa nazwę ikony (konwencja opisana poniżej), kolor color określa kolor oraz parametr percentage określa procentowe nasycenie kolorem. Domyślnie przyjęte są wartości iconname = box, kolor nie jest ustawiony a percentage = 30%. Ikony dostarczane w pakiecie OMNeT++ obejmują wiele kategorii. Jeśli strona wizualna tworzonej symulacji jest ważna (np. w zastosowaniach edukacyjnych) warto przeglądnąć ten zbiór i wybrać ikony, które właściwie odzwierciedlają komponenty modelu. Ikony w podkatalogu bitmaps/ zostały podzielone na grupy: block/ - ikony przeznaczone dla modułów prostych (kolejki, protokoły itp.); device/ - urządzenia sieciowe, na ogół moduły złożone (serwery, hosty itp); abstract/ - symbole różnych urządzeń z wielu kategorii; misc/ - ikony pomocnicze (węzły, podsieci, chmura, miasto); msg/ - ikony przeznaczone dla komunikatów (np. koperta, paczka). Ikony mają przypisany jeden z czterech rozmiarów: normal, large, small, very small, zapisane jako przyrostek do nazwy ikony (odpowiednio _n, _l, _s, _vs) 11.. Rysunek 2.9: Przykładowe ikony graficzne OMNeT++ (z podkatalogu /bitmaps/device). Odwołując się do konkretnych ikon w łańcuchu formatującym podajemy ścieżkę dostępu, np: "i=device/server,gold" 11 Korzystając z nazw ikon mamy do wyboru: albo podajemy pełną nazwę, np: "i=device/router_l" albo albo określamy wielkość ikony korzystając z dodatkowej opcji is, np.: "i=device/router;is=l". W drugim przypadku nazwa ikony występuje bez przyrostka

39 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 35 "i=misc/globe,#808080,100" "i=block/queue,white,100" Graficzny edytor GNED Do tworzenia i edycji plików w języku NED opracowany został także edytor graficzny o nazwie GNED. Jest on częścią pakietu OMNeT++. Edycja plików.ned możliwa jest w trybie graficznym oraz tekstowym. Jednocześnie można edytować wiele plików.ned, wchodzących w skład struktury modelu. Obsługa programu GNED nie jest skomplikowana. Dokładny opis można znaleźć np. w [GNE]. Nawet osobom, które do edycji plików w języku NED korzystają z edytora tekstowego może się przydać podstawowa znajomość tego programu. Składnia często bywa niejasna, drobne błędy uniemożliwiają kompilacje plików, a ich lokalizacja jest trudna. W takich wypadkach wygodnie jest wczytać plik, w którym występują błędy, do programu GNED. Podczas próby włączenia podglądu graficznego topologii (zakładka Graphics) GNED wskaże nam dokładną lokalizację błędnej linii 12. Po uruchomieniu programu tworzony jest nowy plik z definicją pustego modułu złożonego (Rys. 2.10). Rysunek 2.10: Okno programu GNED (po uruchomieniu). Ekran programu podzielony jest na dwie części. Z lewej strony prezentowane jest drzewo modułów. Korzystając z niego można uzyskać łatwy dostęp do wszystkich modułów i parametrów, rozwijając kolejne pozycje, odpowiadające sekcjom modułów. Przyciski paska narzędzi umożliwiają dodawanie nowych modułów i innych definicji języka NED, operacje na plikach, tworzenie nowych plików.ned, zmianę właściwości i ustawień wyglądu poszczególnych elementów. Program GNED ułatwia też rozmieszczanie elementów topologii w oknie ekranu graficznego. Posługiwanie się jednak współrzędnymi graficznymi w edytorze tekstowym jest niewygodne i edytor graficzny jest tutaj dobrym rozwiązaniem. Trzeba zaznaczyć, że w przypadku topologii tworzonych dynamicznie (gdy liczba modułów biorących udział w symulacji nie jest określona), poprawne rozmieszczanie elementów może być kłopotliwe i dokonywane jest raczej metodą prób i błędów. 12 Podobny efekt można też uzyskać podczas kompilacji pliku.ned w wierszu poleceń (z pomocą programu gnedc.exe).

40 36 ROZDZIAŁ 2. PAKIET OMNET Plik konfiguracyjny omnetpp.ini Plik konfiguracyjny o nazwie omnetpp.ini pełni szczególną rolę podczas uruchamiania symulacji w OMNeT++. Przy starcie symulacji plik ten jest odczytywany, a ustawione w pliku parametry mają wpływ na tryb i zakres symulacji, wybór konkretnego modelu, a także na parametry poszczególnych modułów. W niniejszym podrozdziale omówione zostaną jedynie najważniejsze z opcji pliku konfiguracyjnego. Pełny opis znajduje się w dokumentacji do OMNeT++ [OMN]. W pliku można umieszczać komentarze, zaczynając je od znaku hash (#). Ze względu na to, jak ważne jest poprawne ustalenia parametrów symulacji, zalecane jest możliwie szerokie komentowanie poszczególnych wpisów. Plik składa się z kolejnych sekcji, których nazwy zapisane są w nawiasach kwadratowych. Kolejno są to sekcje: [General] - podstawowe ustawienia dla całej symulacji; [Parameters] - wartości przyporządkowywane parametrom w poszczególnych modułach; [Cmdenv] - opcje wsadowego (uruchamianego w oknie terminala) środowiska symulacyjnego; [Tkenv] - opcje graficznego, wizualnego środowiska symulacyjnego; [Run i] - dla symulacji wielowariantowej podaje się numer wariantu symulacji i, następnie parametry dla tego wariantu; [OutVectors] - konfiguracja rejestracji wyników symulacji, dokładniejszy opis - patrz 2.8.1). Poszczególne sekcje w pliku można rozdzielać (choć utrudnia to analizę kodu). Rozdzielone sekcje są łączone ze sobą kolejno, np: 1 [ General ] 2 foo = " wartosc okreslona dla parametru foo " [ General ] 5 bar =" parametr bar takze nalezy do sekcji [ General ]" Konfiguracje można też rozdzielać na wiele plików.ini. W pliku omnetpp.ini należy dołączyć te pliki korzystając ze słowa include, np: 1 # omnetpp. ini include parametry. ini 4 include warianty - run. ini 5... Sekcja [General] Najważniejsze opcje tej sekcji to: network - opcja wskazująca konkretną sieć symulacyjną do uruchomienia (Patrz 2.2.8), np: 1 [ General ] 2 network = testpolaczeniatcp

41 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 37 sim-time-limit, cpu-time-limit - odpowiednio określenie limitu czasu symulacji, wyrażonego w jednostkach czasu symulowanego (tzw. slotach czasowych) i określenie limitu czasu symulacji, wyrażonego w jednostkach czasu procesora. Można stosować jednostki s m h dla sekund, minut i godzin, np: 3 sim - time - limit = cpu -time - limit = 60s Ustalenia tych wartości jest opcjonalne. Jeśli nie zostaną one ustalone symulacja kończy się, gdy wszystkie komunikaty symulacji zostana przetworzone. output-vector-file, output-scalar-file, snapshot-file - określenie nazw plików, do których zapisywane będą wyniki symulacji, odpowiednio wyniki wektorowe, skalarne i "zrzuty" stanu symulacji, np: 5 output - vector - file = omnetpp. vec 6 output - scalar - file = omnetpp. sca 7 snapshot - file = omnetpp. sna Poniżej ważniejsze opcje poszczególnych sekcji zostaną opisane dokładniej. Sekcja [Parameters] Parametry modułów mogą być określane na poziomie modułów w plikach.ned, wprowadzane przez użytkownika w trybie interaktywnym (jeśli nie zostały określone w inny sposób) lub ustawiane właśnie w pliku konfiguracyjnym. Ten ostatni przypadek wydaje się najbardziej właściwy, gdyż pliki w języku NED służą do definiowania topologii, a z wprowadzanie parametrów w trybie interaktywnym jest niewygodne i należy z niego korzystać tylko w ostateczności. Dobrą praktyką jest więc umieszczanie wszystkich parametrów w pliku.ini. Jeśli ten sam parametr został określony zarówno w języku NED jak i w omnetpp.ini, wówczas uwzględniany jest ten zapisany w języku NED. Parametry w określonej sekcji uwzględniane są zgodnie z kolejnością ich wystąpienia. Ma to istotne konsekwencje. Jeśli w pliku omnetpp.ini określony parametr ustawiany jest więcej niż raz, skuteczne jest pierwsze ustawienie tego parametru. Z rozwiązania tego często się korzysta w praktyce, ustawiając najpierw parametr dla przypadków szczególnych i pojedynczych modułów, a potem określoną wartość parametru grupowo, dla większej liczby modułów. Do parametrów poszczególnych modułów odwołujemy się poprzez podanie identyfikatora wraz z pełną ścieżką w ramach hierarchicznej struktury modułów. Do wskazania kolejnych nazw w hierarchii modułów wykorzystywany jest operator kropka (.). Kolejność odwoływania następuje od najwyższego poziomu w hierarchii, do najniższego. Przykładowo, aby odwołać się do parametru liczbahostow na najwyższym poziomie modelu symulacyjnego (definicja sieci symulacyjnej) napiszemy: 1 [ Parameters ] 2 net. liczbahostow = 15 Jeśli w tym module istnieje instancja modułu o nazwie serweraplikacji, który posiada parametr liczbaaplikacji, odwołamy się do niego następująco: 2 net. serwer. liczbaaplikacji = 100

42 38 ROZDZIAŁ 2. PAKIET OMNET++ Znaki wieloznaczne (wildcards) Jeśli model posiada wiele parametrów, określanie wszystkich osobno może być niewygodne (np. dla wektora modułów tego samego typu). Moduły symulacji zazwyczaj posiadają podobną budowę a niektóre elementy składowe są tego samego typu (np. istnieje moduł prosty pełniący rolę bufora, a użytkownik chciałby dla wszystkich ustawić identyczne ograniczenia na jego wielkość). Z pomocą przychodzą tutaj konstrukcje zwane znakami wieloznacznymi lub także znakami uniwersalnymi (ang. wildcars). Pełnią one ważna rolę w OMNeT++, umożliwiając dokładne i wygodne wskazywanie grup modułów w plikach konfiguracyjnych. Lista dostępnych konstrukcji tego typu jest następująca:? - dowolne dopasowanie jednego znaku (z wyjątkiem kropki.); * - dowolne dopasowanie łańcucha znaków (zero i więcej znaków z wyjątkiem kropki.); ** - dowolne dopasowanie łańcucha znaków (włącznie ze znakiem kropki.); {a-f} - dowolne dopasowanie znaku z zakresu a-f; {â-f} - dowolne dopasowanie znaku z wyjątkiem znaków z zakresu a-f; { } - dopasowanie liczby (sekwencji cyfr) z zakresu od 38 do 150; [ ] - dopasowanie wszystkich indeksów (w nawiasach kwadratowych) z zakresu od 38 do 150; backslash (\) - dopasowanie dotyczy znaków o specjalnym znaczeniu (escape sequence, poprzedzonych znakiem backslash); Najistotniejsza różnica dotyczy znaków * i **. Znak * oznacza dopasowanie dla pojedynczego modułu lub nazwy parametru 13. Przykładowo: 1 networkwifi.*. waittime = 8 ms Zapis ten znacza, że parametr waittime będzie ustalony na 8ms dla wszystkich modułów, zdefiniowanych na poziomie modułu networkwifi. Znak ** powala dopasować wiele elementów na ścieżce. Gdyby zapisać następująco: 1 networkwifi.**. waittime = 8 ms Wówczas wszystkie moduły, od poziomu najwyższego (wewnątrz sieci networkwifi) do najniższego, które mają zdefiniowany parametr waittime przypiszą mu wartość 8ms. Gdyby zmodyfikować zapis do postaci: 1 networkwifi **. waittime = 8 ms Wtedy otrzymamy podobny efekt, z tym że będzie także dopasowanie dla definicji sieci o nazwach networkwifi10, networkwifimax, networkwifitest itp. Wykorzystując znaki wildcards należy pamiętać o wspomnianej już zasadzie, że wpisy w pliku konfiguracyjnym uwzględniane są po kolei i dla identycznego dopasowania obowiązuje tylko pierwsze ustawienie parametru. Zwróćmy uwagę na poniższy zapis: 13 W wersjach OMNeT++ poniżej 3.0 konstrukcja ** nie była jeszcze implementowana, a konstrukcja * obejmowała również znak kropka (.). Uruchamiając więc modele opracowane dla tych wersji można napotkać na problem z kompatybilnością. W takich przypadkach można dodać wpis #% old-wildcards, przywracający stary sposób traktowania tych wyrażeń.

43 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 39 1 *. host [*]. waittime = 10 ms 2 *. host [3]. waittime = 6 ms 3 *. host [0]. waittime = 5 ms W typ przypadku pierwszy wpis powoduje, że wszystkie parametry zostaną ustalone na 10ms, nawet dla host[0] i host[3]. Taki zapis należy więc uznać za błędny i źródło potencjalnych problemów. Uzasadnione jest jednak stosowanie zapisów typu: 1 *. host [0]. waittime = 10 ms 2 *. host [*]. waittime = 5ms Pierwszy wpis ustala parametr w pierwszym module na 10ms. Ostatni wpis ustala dla wszystkich (pozostałych) modułów host wartość parametru na 5ms, Dzięki temu unikamy wielokrotnych wpisów dla tej samej wartości parametru. Nieco bardziej złożony jest poniższy przypadek: 1 *.*. queue [3..5]. bufsize = 10 2 *.*. queue [12..]. bufsize = 18 3 *.*. queue [*]. bufsize = 6 Wykorzystno możliwość określenia zakresów indeksów w nawiasach kwadratowych. Parametr bufsize ustalono na 10 dla modułów o indeksach 3, 4, 5. Wartość 18 w modułach od 12 wzwyż (do końca). Ostatni wpis ustala więc parametr na wartość 6 jedynie dla modułów od 0 do 2 i od 6 do 11. Każdy z typów parametrów posiada wartości domyślne. Dla liczb jest to wartość zero, dla wartości logicznych false a dla łańcuchów znaków łańcuch pusty. W typowym przypadku każdy z parametrów musi zostać określony przed uruchomieniem symulacji. Istnieje jednak możliwość odwołania się do tych wartości domyślnych, korzystając z wyrażenia use-default = yes w odniesieniu do określonego parametru. Tak więc na przykład: 1 *.*. queue [*]. bufsize.use - default = yes Ustalona wartość dla tego parametru wynosi więc zero. Warto w tym miejscu zauważyć, że poniższy zapis oznacza przyjęcie wartości domyślnych dla wszystkich parametrów: 1 **. use - default = yes Sekcje [Run i] Parametry mogą być ustalane zarówno w sekcji [Parameters] jak też w sekcjach uruchamiania wielowariantowego [Run 1], [Run 2], [Run 3] itd., obejmujących różne, alternatywne zestawy parametrów. Jeśli w pliku konfiguracyjnym występują takie sekcje, ustawienia parametrów w nich zapisane są brane pod uwagę jako pierwsze. Podczas uruchamiania symulacji użytkownik podejmuje decyzje (np. poprzez pole wyboru przy symulacji w trybie graficznym). Bezpośrednio pod nagłówkiem sekcji można umieścić opis dla danego wariantu (po słowie description). Przykładowa sekwencja w pliku konfiguracyjnym może być następująca (wyjaśnienia bezpośrednio w komentarzach w kodzie): 1 [ Parameters ] 2 net. numhosts = 15 3 net. server. transactionspersecond = [ Run 1] 6 description =" ustawienie ogolne " 7 # wykorzystuje ustawienia z~ sekcji [ Parameters ]

44 40 ROZDZIAŁ 2. PAKIET OMNET++ 9 [ Run 2] 10 description =" wieksze obciazenie serwera " 11 # pierwszenstwo przed ustawieniem z~ sekcji [ Parameters ]: 12 net. server. transactionspersecond = # parametr net. numhosts bedzie ustawiony tak jak w~ sekcji [ Parameters ] 15 [ Run 3] 16 description =" wieksza liczba klientow i~ wieksze obciazenie serwera " 17 # zastepuje oba parametry : 18 net. numhosts = net. server. transactionspersecond = 150 Pozostałe parametry konfiguracyjne Opcje konfiguracyjne dla sekcji [Cmdenv] oraz [Tkenv] zostaną opisane w dalszej części rozdziału. Sekcja [OutVectors] jest opisana przy części dotyczącej zbierania wyników symulacji (Zob. 2.8). Poza wymienionymi, w pliku konfiguracyjnym może być ustawianych wiele innych, zaawansowanych opcji. Część z nich dotyczy na przykład symulacji rozproszonej, która nie mieści się w zakresie niniejszej książki. Dokładny opis wszystkich opcji znajduje się w dokumentacji [OMN] Zaawansowane parametryzowanie modułów Informacje o sposobie definiowania i przekazywania parametrów w modułach oraz o parametryzowaniu topologii symulacji zamieszczone zostały już wcześniej. Warto zwrócić jednak uwagę na pewne zaawansowane możliwości, które mogą się okazać przydatne w bardziej złożonych przypadkach. Parametryzowanie wektorów modułów składowych Tworząc instancje modułów składowych, przy określaniu ich parametrów i bram możemy skorzystać z warunków (słowo kluczowe if). Poszczególne sekcje definicji (parameters, gatesizes) można powielać, umieszczając określony warunek na końcu. Mechanizm ten można wykorzystać wtedy, gdy instancje danego typu modułu zadeklarowane zostały jako wektor, np: 1 //... 2 submodules : 3 host : Host [n]; 4 //... Jest to więc wektor modułów host typu Host o rozmiarze n i indeksach w zakresie [0..(n-1)]. Dla każdego z kolejnych indeksów wywoływane są sekcje parameters, gatesizes dla tego modułu podrzędnego. Warunki te odnoszą się do wartości tego indeksu, który można sprawdzić za pomocą słowa kluczowego index. Zasada jest taka, że dla każdego z indeksów ważna jest ostatnia wykonana instrukcja. Zawsze wykonywana jest instrukcja w sekcji bez warunku i obowiązuje, jeśli żaden warunek nie zostanie dopasowany. Poniżej przedstawiono przykładową sekwencję warunków: 1 parameters : 2 //... 3 parameters if index ==0: 4 //... 5 parameters if index ==n -1: 6 //... 7 gatesizes : 8 //...

45 2.2. DEFINICJA MODUŁÓW I TWORZENIE TOPOLOGII POŁĄCZEŃ MODELU 41 9 gatesizes if index ==0 index ==n -1: 10 // gatesizes if index!=2 && index %2==0: 12 //... Jako przykład wykorzystujący opisany sposób parametryzowania modułów przedstawimy tworzenie łańcucha modułów (typu Node). Każdy z modułów wewnątrz łańcucha łączony jest z dwoma sąsiadami, za wyjątkiem skrajnych modułów w łańcuchu, które mają tylko jednego sąsiada. Moduły wewnętrzne potrzebują więc dwóch bram wejściowych i wyjściowych, a skrajne tylko po jednej bramie [OMN]: 1 module LancuchWezlow 2 parameters : 3 liczbawezlow : const ; 4 submodules : 5 wezel : Wezel [ liczbawezlow ] 6 gatesizes : 7 in [2], out [2]; 8 gatesizes if index ==0 index == liczbawezlow -1: 9 in [1], out [1]; 10 connections : 11 for i= 0.. liczbawezlow -2 do 12 wezel [i]. out [i!=0? 1 : 0] --> wezel [i +1]. in [0]; 13 wezel [i]. in[i!=0? 1 : 0] <-- wezel [i +1]. out [0]; 14 endfor ; 15 endmodule Warunek w linii 9 zapewnia, że dla ostatniego i pierwszego modułu utworzone będą jedynie 2 bramy. Samo tworzenie połączeń realizowane jest w pętli for. Każdy moduł o indeksie [i] łączony jest z modułem [i+1]. Konstrukcję z wykorzystaniem operatora warunkowego (? :) gwarantuje dla pierwszego modułu użycie bram o indeksach [0], a dla pozostałych [1]. Pętla kończy się na przedostatnim indeksie ([count-2]), co zapewnia podłączenie do ostatniego elementu. Warto zauważyć, że gdyby nie było warunku w sekcji gatesizes to model byłby nadal poprawny, jednak skrajne elementy miałyby niepodłączone bramy. Tak więc w sekcji connections należałoby dopisać słowo kluczowe nocheck, jak na przykładzie poniżej: 1 module LancuchWezlow 2 parameters : 3 liczbawezlow : const ; 4 submodules : 5 wezel : Wezel [ liczbawezlow ] 6 gatesizes : 7 in [2], out [2]; 8 connections nocheck : 9 for i= 0.. liczbawezlow -2 do 10 wezel [i]. out [0] --> wezel [i +1]. in [0]; 11 wezel [i]. in [1] <-- wezel [i +1]. out [1]; 12 endfor ; 13 endmodule Parametryzowanie typów modułów W niektórych przypadkach wygodnie jest przekazywać typ modułu podrzędnego jako parametr (np. w pliku konfiguracyjnym). Rozwiązanie takie oznacza, że można wówczas w miejsce tak sparametry-

46 42 ROZDZIAŁ 2. PAKIET OMNET++ zowanego modułu ogólnego zastosować dowolny moduł, pod warunkiem, że jego interfejs wewnętrzny (wejścia, wyjścia i parametry) będą zgodzie z typem ogólnym modułu 14. Do tworzenia takich konstrukcji wykorzystywane jest słowo kluczowe like. Jako przykład można rozważyć sytuacje, gdy chcemy porównać ze sobą różne typy przełączników. Każdy z nich zdefiniowany jest jak odrębny moduł prosty, o unikalnej nazwie (Przelacznik1, Przelacznik2, Przelacznik3 itd.) Najpierw definiowany jest typ ogólny Przelacznik, który posiada identyczną konstrukcję jak moduły, które chcemy parametryzować. Moduł ten, mimo, że jest modułem prostym, nie musi być implementowany w C++. Z kolei moduły proste, które przekazywana są jako parametr nie muszą posiadać swojej definicji w języku NED. Następnie definiujemy moduł złożony (o nazwie TesterPrzelacznika), który jako parametr przyjmuje nazwę konkretnego typu modułu (typ określony jako string). Przy tworzeniu połączeń odwołujemy się juz do instancji ogólnego typu (przelacznik): 1 simple Przelacznik 2 gates : 3 out : out []; 4 in: in []; 5 endsimple 7 module TesterPrzelacznika 8 parameters : 9 typprzelacznika : string ; 10 gates : // submodules : 12 przelacznik : typprzelacznika like Przelacznik ; 13 // connections nocheck : 15 //... odwolujemy sie np. przelacznik. out - - > endmodule W wyniku zastosowania takiego zapisu uzyskujemy elastyczną topologię, w której występuje uogólniony moduł typu Przelacznik. W jego miejsce możemy wstawić dowolny inny moduł o zgodnych bramach. Typ modułu możemy określić podając jego identyfikator, z poziomu pliku konfiguracyjnego, w innym pliku NED lub ręcznie, podczas uruchamianie symulacji (podobnie jak dowolne inne parametry). Jeśli typ modułu (określony przez jego identyfikator) będzie niepoprawny lub niezgodny, OMNeT++ zasygnalizuje to komunikatem o błędzie podczas uruchamiania symulatora. 2.3 Środowisko uruchomieniowe symulacji Jeśli symulacja jest kompletna, można przystąpić do jej uruchamiania. Uruchamiając symulację użytkownik może chcieć obserwować przebieg komunikatów (co ma znaczenie także dla wyszukiwania błędów w symulacji), wpływać na proces symulacyjny lub też interesuje go jedynie wynik całej symulacji (np. statystyka długości kolejek). Użytkownik OMNeT++ ma do dyspozycji dwa środowiska uruchomieniowe:cmdenv, które jest środowiskiem tekstowym, oraz środowiskiem graficznym Tkenv, które umożliwia wizualizację symulacji. Poniżej przedstawiono ich konfigurację, możliwości oraz obsługa jest przedstawiona. 14 Mechanizm ten przypomina polimorfizm znany z programowania zorientowanego obiektowo.

47 2.3. ŚRODOWISKO URUCHOMIENIOWE SYMULACJI Środowisko tekstowe Cmdenv Tryb linii poleceń obsługuje jedynie komunikaty wypisywane w oknie tekstowym (bez wizualizacji). Dzięki temu jednak zyskujemy na efektywności, gdyż działanie symulacji w tym trybie jest znacznie szybsze. Środowisko to można uruchomić w dwóch trybach: Normal i Express. W trybie Normal na ekranie wypisywane są wszystkie komunikaty symulacji, w trybie Express wypisywane są jedynie zbiorcze informacje (co pewien określony odstęp czasu) oraz zbiorczo, na zakończenie symulacji. Konfiguracji tych trybów dokonuje się w pliku omnetpp.ini, co zostało opisane w dalszej części. Interpretowanie komunikatów tekstowych Cmdenv Podczas działania symulacji, w zależności od wybranego trybu i pozostałych ustawień, mogą pojawiać się trzy rodzaje komunikatów: komunikaty generowane przez moduły; komunikaty o zajściu zdarzenia; informacje zbiorcze. Format komunikatów generowanych przez moduły może być dowolny i zależy od konkretnej implementacji w C++. Komunikaty o zajściu zdarzenia mają określony format. Zawierają numer kolejnego zdarzenia, czas zajścia zdarzenia (wartość bezwzględna i wyrażona w jednostkach czasu) oraz numer i nazwa modułu, z którym związane jest zdarzenie nadejścia komunikatu. Przykładowy komunikat może wyglądać następująco: ** Event #2. T = ( 87 ms). Module #2 fifonet. gen 3... Kolejnymi komunikatami, które mogą pojawiać się w oknie Cmdenv wypisywane są także informacje zbiorcze. Postać tych informacji może przykładowo być następująca: ** Event # T = ( 2m 3s) Elapsed : 0m 12 s 3 Speed : ev/sec = simsec / sec = ev/ simsec = Messages : created : present : 6553 in FES : 8 5 ** Event # T = ( 2m 28 s) Elapsed : 0m 15 s 6 Speed : ev/sec = simsec / sec = ev/ simsec = Messages : created : present : 7815 in FES : Każda pierwsza linia takiej informacji zaczyna się od znaków ** i zawiera następujące informacje: Pierwsza linia (informacje podstawowe): ile komunikatów zostało już przetworzonych; jaki jest bieżący stan czasu symulowanego; jaki okres czasu upłynął od rozpoczęcia symulacji. Druga linia (wydajność symulacji):

48 44 ROZDZIAŁ 2. PAKIET OMNET++ ev/sec określa wydajność symulacji, tj. ile komunikatów symulacji zostało przetworzonych na jedną sekundę czasu rzeczywistego; simsec/sec także określa wydajność, jako liczba sekund czasu symulowanego przypadających na sekundę czasu rzeczywistego; ev/simsec określa gęstość komunikatów, tj. ile komunikatów symulacji przypada na jedną sekundę czasu symulowanego. Trzecia linia (informacje o komunikatach): Created: liczba utworzonych komunikatów; Present: liczba komunikatów bieżących (jest to ważny parametr, gdyż można określić, czy w symulacji nie znajdują się komunikaty, które z różnych powodów nie są przetwarzane, a nie zostały usunięte; FES: liczba komunikatów przeznaczonych do przesłania w przyszłości, znajdujących się w FES (ang. Future Event Set). Informacje opisane powyżej są także aktualne dla środowiska graficznego (Patrz ), w ramach którego w oknie komunikatów pojawiają się informacje w identycznym formacie. Konfiguracja środowiska Cmdenv Konfiguracja środowiska Cmdenv obejmuje dokonanie odpowiednich ustawień w sekcji [Cmdenv] pliku konfiguracyjnego omnetpp.ini. Poniżej prezentowane są wybrane, najważniejsze ustawienia, wraz z przykładowymi wartościami: 1 [ Cmdenv ] 2 runs -to - execute = 1 Ustawia konkretny wariant symulacji do uruchomienia (Por Sekcja [Run i]). Można oddzielić przecinkami kilka wariantów. Symulacje będą uruchamiane kolejno, w podanej kolejności. 3 express - mode = yes Ustawia wydajny tryb Express dla uruchamianej symulacji. Domyślnie jest ustawiony tryb Normal (taki sam efekt daje użycie słowa no. 4 module - messages = yes Opcja yes jest ustawiona jako domyślna. Wypisuje na ekranie wszystkie komunikaty z modułów. O formacie tych komunikatów decyduje programista implementując moduł w C++. Opcja no wyłącza te komunikaty. 5 event - banners = yes Opcja yes jest ustawiona jako domyślna. Działa tylko w trybie Normal. Wypisuje na ekranie komunikaty o zajściu zdarzenia. 6 status - frequency = Działa tylko w trybie Express. Wypisuje zbiorcze komunikaty co określoną liczbę zdarzeń. 7 message - trace = no Opcja no jest ustawiona jako domyślna. Działa tylko w trybie Normal. Wypisuje na ekranie informacje o wysłaniu komunikatu.

49 2.3. ŚRODOWISKO URUCHOMIENIOWE SYMULACJI Środowisko graficzne TkEnv Środowisko graficzne Tkenv umożliwia szczegółową wizualizację przebiegu symulacji. Poza głównym ekranem graficznym można w osobnych oknach (tzw. inspektorach) uruchomić podgląd dla każdego z modułów modelu symulacyjnego (domyślnie jest to topologia całego modelu symulacyjnego). Możliwe jest monitorowanie przebiegu symulacji w postaci odpowiednich histogramów i wykresów. Uruchamianie symulacji realizowane jest w trybie interaktywnym, co pozwala na zmianę jej parametrów. Ekran środowiska graficznego podzielony jest na dwa okna. W jednym znajduje się drzewo obiektów symulacji, w drugim wypisywane są komunikaty tekstowe. Dostępny jest też pasek narzędzi (przycisków), które pozwalają na wykonanie najbardziej przydatnych operacji (Rys. 2.11). Rysunek 2.11: Okno główne środowiska Tkenv (przykład o nazwie fifonet) Uruchamiając symulację można wybrać jeden z dostępnych trybów (reprezentowanych przez kolejne przyciski). Są to kolejno: step - wykonuje jeden krok symulacji (przetworzenie jednego zdarzenia) i zatrzymuje symulację. Pozwala to na wykonanie symulacji "krok po kroku", co jest szczególnie przydatne przy poszukiwaniu ewentualnych błędów (debugging); normal - tryb, w którym przetwarzane są kolejne zdarzenia, wraz z pełną animacją wszystkich kroków; fast - tryb z ograniczoną animacją, w którym przebieg symulacji jest znacznie szybszy; express - tryb szybki, w którym wyłączone jest animacja i ograniczone jest wypisywanie komunikatów. Należy jednak pamiętać, że największą wydajność symulacji osiąga się rezygnując ze środowiska graficznego na rzecz tekstowego Cmdenv. Można też zdecydować się na wybór przycisku Until, która pozwala na realizację symulacji do osiągnięcia zadanego czasu symulacji lub numeru zdarzenia. Wartości te ustawiane są w odpowiednim oknie dialogowym. Pozostałe przyciski paska narzędzi oznaczają kolejno: wybór jednego z wariantów symulacji; wybór jednego z modeli symulacyjnych (simulation network) zadeklarowanych w pliku.ned;

50 46 ROZDZIAŁ 2. PAKIET OMNET++ ponowne wczytanie plików.ned; zatrzymanie symulacji; zakończenie symulacji (związane z wywołaniem metody finish() dla wszystkich modułów (na poziomie C++); wywołanie okna z topologią modelu; wyświetlenie okna zawierającego stos zdarzeń (komunikatów, które nie zostały jeszcze przetworzone i czekają na swoją kolej); wyszukiwanie określonego łańcucha tekstowego w oknie komunikatów włączenie/wyłączenie drzewa obiektów symulacji; wywołanie okna dialogowego wyboru opcji symulacji; Poniżej paska narzędzi znajduje się pasek informacyjny. Znajdują się w nim ważne informacje o przebiegu symulacji, aktualizowane na bieżąco. Są to kolejno: Run # - aktualny wariant symulacji; Event # - numer aktualnego zdarzenia; T= - aktualny czas symulacji; Next: - nazwa obiektu, do którego odnosi się następne zdarzenie; Msgs scheduled: - liczba komunikatów, które pozostały do przetworzenia (znajdują się stosie zdarzeń); Msgs created: - liczba komunikatów, które zostały utworzone od momentu uruchomienia symulacji; Msgs present: - liczba komunikatów aktualnie znajdujących się w symulacji (zarówno przyszłych jak i bieżących); Ev/sec: - liczba zdarzeń na sekundę czasu rzeczywistego; Simsec/sec: - liczba sekund czasu symulacji przypadająca na sekundę czasu rzeczywistego (odzwierciedla wydajność symulacji); Ev/simsec: - liczba zdarzeń przypadająca na sekundę czasu symulowanego. Poniżej pasków informacyjnych znajduje się okno z graficzną reprezentacją czasu symulacji (Rys. 2.12). Oś czasu jest przedstawiona w skali logarytmicznej, na której, w postaci punktów, odwzorowane są komunikaty znajdujące się na stosie zdarzeń. Klikając na poszczególne punkty na osi czasu można uzyskać dostęp do parametrów tych komunikatów (nazwa, rodzaj, długość, czas wysłania, czas nadejścia itp.). Rysunek 2.12: Oś czasu symulacji środowiska Tkenv Dla poszczególnych obiektów (instancji modułów) można wywołać osobne okna podglądu symulacji (automatycznie wywoływane jest okno dla modelu symulacyjnego). Okna te można wywołać albo poprzez

51 2.3. ŚRODOWISKO URUCHOMIENIOWE SYMULACJI 47 kliknięcie na obiektach w drzewie obiektów symulacji (dostęp hierarchiczny do wszystkich elementów symulacji) lub poprzez wywołanie (kliknięcie) na wskazanym obiekcie dostępnym z poziomu dowolnego okna podglądu symulacji. W zależności od rodzaju obiektu okno podglądu symulacji występuje w dwóch możliwych widokach: widok graficzny o nazwie Inspect as Graphics i widok obiektu o nazwie Inspect as Object. Okno podglądu graficznego (zob. Rys.2.13) udostępnia dodatkowy pasek narzędzi, w którym kolejne przyciski odpowiadają za: przejście na wyższy poziom w hierarchii modułów; wywołanie okna podglądu obiektu (podglądu atrybutów modułu, jego parametrów, modułów składowych i bram), opisane poniżej; wywołanie okna komunikatów dla danego obiektu; uruchomienie symulacji w trybie Normal lub Fast, która zostanie zatrzymana w momencie, gdy wystąpi zdarzenie związane w danym obiektem; zatrzymanie symulacji; szybkość animacji (regulowana za pomocą suwaka). Rysunek 2.13: Okno podglądu graficznego, z widokiem całej topologii modelu (przykład dołączony do pakietu OMNeT++ o fifonet) Zastosowanie animacji pozwala na śledzenie w tym oknie przebiegu symulacji. Animowany jest przepływ komunikatów, a obiekty z którymi związane są bieżące zdarzenia, są dodatkowo zaznaczane (otoczone są ramką w kolorze czerwonym). Bardzo przydatna jest możliwość śledzenia w tym oknie tylko komunikatów związanych z danym obiektem i zatrzymywania symulacji po każdym takim zdarzeniu. Okno podglądu obiektu nie obsługuje animacji. Dostępny jest za to dostęp do pełnej informacji o obiekcie. Informacje te znajdują się na kolejnych zakładkach (zob. Rys. 2.14). Są to kolejno atrybuty modułu (zakładka o nazwie Info), parametry (zakładka o nazwie Params), moduły składowe (zakładka o nazwie Submodules) i bramy (zakładka o nazwie Gates). Widoczny jest pasek narzędziowy, podobny jak w przypadku okna podglądu graficznego. Dodatkowo dostępny jest przycisk podglądu graficznego tego obiektu.

52 48 ROZDZIAŁ 2. PAKIET OMNET++ Rysunek 2.14: Okno podglądu obiektu dla jednego z modułów prostych modelu (przykład dołączony do pakietu OMNeT++ o nazwie fifonet) Niektóre obiekty zawierają dodatkowe elementy składowe, takie jak wykresy, histogramy i kontenery (Rys. 2.15). Możliwe jest sprawdzenie zawartości tych składowych za pomocą dodatkowej zakładki o nazwie Contents. Jeśli na przykład obiekt zawiera strukturę kolejki, w której przechowywane są komunikaty przeznaczone do wysłania, możemy uzyskać do nich dostęp. Dla każdego z komunikatów możemy następnie wywołać osobne okno podglądu obiektu. Rysunek 2.15: Wykres przykładowego parametru modułu, aktualizowany na bieżąco podczas symulacji Dodatkowo możliwa jest zmiana niektórych atrybutów i parametrów obiektu w trakcie trwania symulacji. Wprowadzone zmiany należy zatwierdzić.

53 2.4. PROGRAMOWANIE AKTYWNYCH MODUŁÓW (C++) 49 Konfiguracja środowiska Tkenv W przypadku Tkenv istnieje także możliwość ustawiania większości opcji w głównym oknie graficznym (menu Options -> Simulation Options). Z tymi ustawieniami związany jest plik.tkenvrc, w którym zapamiętane są poszczególne parametry środowiska (opcje, położenie okienek, poziom szczegółowości symulacji, szybkość animacji itp). Plik ten przechowuje ustawienia opcji środowiska pomiędzy kolejnymi uruchomieniami. Możliwa jest także zmiana większości ustawień w pliku Omnetpp.ini. Do konfiguracji trybu graficznego w tym pliku służy sekcja [Tkenv]. Najczęściej ustawiane parametry to: 1 [ Tkenv ] 2 default run = 1 Oznacza warianty symulacji (sekcja [Run i]) która zostanie wywołany po uruchomieniu. 2 module - messages = yes Wypisuje wszystkie informacje z modułów. Ustawienie to odnosi się jedynie do trybu Normal. 3 event - banners = yes Wypisuje informacje o zajściu zdarzenia. Ustawienie to odnosi się jedynie do trybu Normal. 4 status - frequency = Wypisuje w oknie komunikatów tekstowych stan symulacji, co określoną liczbę zdarzeń. Ustawienie to odnosi się jedynie do trybu Express. 5 message - trace = no Wypisuje informacje przy każdym zdarzeniu związanym z wysłaniem komunikatu. Parametr ten jest domyślnie wyłączony. W symulacjach można także wykorzystywać własne komponenty graficzne (zob ). Aby uzyskać dostęp do własnych katalogów z takimi komponentami należy dodać do pliku omnetpp.ini wpis, który dodaje ikony ze wskazanego katalogu (wówczas stają się możliwe do użycia w programie symulacji i z poziomu języka NED), np: 6 bitmap - path = "/ home / you / model - framework / bitmaps ;/ home / you / extra - bitmaps " 2.4 Programowanie aktywnych modułów (C++) Moduły proste w OMNeT++ muszą być zaprogramowane bezpośrednio w języku C++. Jeśli użytkownik chce stworzyć własne moduły proste lub modyfikować zachowanie już istniejących musi zaimplementować odpowiednie algorytmy i przeprowadzić kompilację stworzonych źródeł. Pakiet dysponuje obszerną biblioteką klas C++, której można używać do implementacji modułów prostych. Posiadają one metody, które są wykorzystywane do efektywnego budowania symulacji i pozwalają na: wysyłanie i odbieranie komunikatów, dostęp do bram i parametrów, uzyskanie dostępu do innych modułów,

54 50 ROZDZIAŁ 2. PAKIET OMNET++ przechowywanie danych w strukturach, generowanie liczb losowych, zbieranie statystyk i zapisywanie ich do plików, operowanie na rozkładach Symulacja zdarzeń dyskretnych w OMNeT++ OMNeT++ jest symulatorem opierającym się na koncepcji symulacji zdarzeń dyskretnych DES (ang. Discrete Event System). Stan symulacji zmienia się w dyskretnych chwilach czasu symulacji (ang. simulation time) w wyniku nadejścia zdarzeń (ang. events). Zdarzenia te są jedynym źródłem zmian w czasie symulacji i zakłada się, że pomiędzy zdarzeniami nic się nie dzieje. Zajście zdarzenia i jego obsługa odbywa się w tej samej chwili czasu (nie powoduje upływu czasu symulowanego). Za przetwarzanie zdarzeń w OMNeT++ odpowiadają moduły proste. Algorytmy tego przetwarzania są implementowane w języku C++ z wykorzystaniem klas i metod biblioteki symulacyjnej. Podstawowym zadaniem użytkownika implementującego dany model symulacyjny na poziomie modułów prostych jest odpowiednie zaprojektowanie typów zdarzeń, generowanie nowych zdarzeń i reakcja na zdarzenia. Przykładami zdarzeń mogą być: początek transmisji pakietu, odebranie pakietu, przekroczenie czasu na potwierdzenie pakietu. OMNeT++ działa na podobnej zasadzie jak inne symulatory zdarzeń dyskretnych, których koncepcja została opisana wcześniej (Zob. rozdział ). Aby tworzyć własne modele symulacyjne i implementować zachowanie komponentów modelu w modułach prostych wymagane jest dobre rozumienie problematyki symulacji zdarzeń dyskretnych, podstawowa znajomość języka programowania C/C++ oraz rozumienie podstawowych pojęć z zakresu programowania obiektowego. Zaawansowana znajomość programowania C++ nie jest wymagana, ze względu na to, że obiektowy szkielet modelu symulacyjnego w C++ jest tworzony automatycznie, w wyniku kompilacji topologii modelu w języku NED. OMNeT++ wykorzystuje komunikaty, czyli odpowiednie obiekty w C++, aby zamodelować zdarzenia. Do reprezentacji komunikatów przeznaczona jest klasa ogólna cmessage. Tak więc podczas działania symulacji obiekty tej klasy (lub klas pochodnych) przesyłane są pomiędzy obiektami reprezentującymi moduły Czas symulowany Symulacja przetwarza komunikaty, które mają określony czas nadejścia (timestamp) danego zdarzenia w systemie. Przetwarzanie kolejnych komunikatów powoduje upływ dyskretnego czasu symulowanego. Komunikaty przetwarzane są według kolejności czasów nadejścia komunikatów. Czas nadejścia komunikatu zostaje ustalony w chwili jego wysłania. W przypadku np. komunikatów wysyłanych bezpośrednio do modułów (np. self-messages) będzie to konkretna wartość, nadana bezpośrednio w programie danego modułu. W przypadku wysyłania komunikatów przez zdefiniowane w topologii modelu połączenia, będzie to czas wynikający z propagacji sygnału w takim połączeniu oraz wielkości komunikatu. Jeśli więcej komunikatów ma ten sam czas nadejścia, uwzględniany jest ten o niższej wartości priorytetu (priorytet jest jednym z pól klasy komunikatów (Por. 2.5), a jego wartość może ustalać programista). Jeśli czas nadejścia i priorytet są takie same, wykonywany jest ten wysłany wcześniej (czas wysłania komunikatu jest także jednym z pól klasy komunikatów). Wielkości związane z czasem wyrażone są w typie o nazwie simtime_t (tożsamym z typem double). Wszystkie zmienne wyrażające jednostki czasu symulowanego powinny być oparte na tym typie.

55 2.4. PROGRAMOWANIE AKTYWNYCH MODUŁÓW (C++) 51 Bieżącą wartość czasu symulacji możemy odczytać wywołując metodę simtime(). Jeśli więc chcemy przypisać zmiennej czas odległy o 1 sekundę od bieżącego (np. w celu wysłania komunikatu o takim właśnie czasie nadejścia) napiszemy: 1 simtime_ t time = simtime () + 1; Wykorzystanie typu simtime_t, opartego na double, ma określone konsekwencje. Najważniejszą jest dokładność numeryczna obliczeń i błędy zaokrągleń. Przykładowo, wyrażenia identyczne z punktu widzenia matematyki nie muszą być identyczne z punktu widzenia arytmetyki liczb zmiennoprzecinkowych. Na wynik może wpływać na przykład kolejność działań, a w konsekwencji ten sam czas nadejścia dwóch komunikatów, obliczony w różny sposób, w rezultacie da różne wyniki i komunikaty te zostaną przetworzone w innych chwilach czasu Wymiana informacji ze środowiskiem symulacji Uruchomienie każdej symulacji odbywa się zawsze w jednym z dwóch trybów: graficznym Tkenv lub tekstowym CmdEnv. Niezależnie do wybranego trybu konieczne jest zapewnienie odpowiedniej wymiany informacji pomiędzy środowiskiem uruchomieniowym a programem w C++. Komunikację tę zapewnia klasa o nazwie cenvir. Posiada ona tylko jeden, globalny obiekt, który stanowi jej instancję, o nazwie ev. Najczęściej do tego obiektu użytkownik będzie się odwoływać w sytuacji, gdy chce wygenerować określony komunikat informacyjny, który ma pojawić się w oknie komunikatów. Korzystamy wówczas z przeciążonego operatora <<, np: 1 ev << " Trwa inicjalizacja modułu "; W większości zastosowań rozwiązanie to powinno w zupełności wystarczyć, jednak obiekt ev pozwala także na bardziej zaawansowane operacje. Można na przykład sprawdzić z poziomu programu w C++ ustawienia poszczególnych opcji w pliku konfiguracyjnym. Wykorzystanie metod tego obiektu jest także istotne przy dynamicznym tworzeniu modułów i połączeń. Wykracza to jednak poza zakres tej książki. Dalsze, dokładniejsze informacje dotyczące dynamicznego tworzenia komponentów można znaleźć w [OMN] oraz w OMNeT++ API Reference na stronie Dostęp do komponentów graficznych i animacji Gdy korzystamy ze środowiska graficznego możemy także wpływać na animację i okno graficzne korzystając z łańcuchów formatujących wyświetlanie (patrz ). Dzięki temu można wyświetlać własne obiekty graficzne w oknie. Aby utworzyć łańcuch formatujący należy skorzystać z klasy cdisplaystring i utworzyć odpowiedni obiekt lub pobrać łańcuch formatujący z istniejącego obiektu. Następnie można dokonać odpowiednich modyfikacji w takim łańcuchu. Przypisując zmodyfikowany łańcuch do obiektu wpływamy na jego wygląd i położenie. Poniższy przykład ilustruje zmianę wyglądu i położenia obiektu nadrzędnego (do którego dostęp uzyskiwany jest za pomocą metody parentmodule(). 1 cdisplaystring * dispstr = displaystring (); 2 dispstr -> parse ("p =100,125; i= cloud "); 3 parentmodule () -> displaystring () = dispstr ; 15 Czasami, na poziomie modelu symulacyjnego, przy kalkulowaniu jednostek czasu, warto przyjąć określony, dostatecznie mały odcinek czasu symulowanego jako parametr i wszelkie wartości zaokrąglać względem tego parametru.

56 52 ROZDZIAŁ 2. PAKIET OMNET++ Dokładny opis właściwości graficznych obiektów z poziomu C++ i wpływanie na te właściwości podczas działania symulacji wykracza poza zakres tej książki. Dokładniejsze informacje można znaleźć w [OMN] oraz w OMNeT++ API Reference na stronie Dodatkowe komunikaty animowane w oknie graficznym W oknie graficznym środowiska Tkenv można także w prosty sposób umieszczać dodatkowe komunikaty w formie tzw dymków. Mogą to być komunikaty o określonych, ważnych zdarzeniach lub sygnalizujące pewne stany działających modułów. Umieszczenie takiego komunikatu jest łatwe i ogranicza się go wywołania metody bubble, np: 1 bubble (" Bufor przepelniony!") ; Komunikaty te są ignorowane w oknie środowiska tekstowego Cmdenv. Zalecane jest jednak sprawdzenie, w jakim środowisku uruchomiona jest symulacja. Można to osiągnąć sprawdzając wartość logiczną, którą zwraca metoda isgui(), związana z obiektem reprezentujących środowisko uruchomieniowe ev. W pełni poprawny zapis powinien więc wyglądać następująco: 1 if (ev. isgui ()) 2 bubble (" Bufor przepelniony!") ; W przypadku zajścia określonego zdarzenia w oknie graficznym danego modułu wyświetlony zostanie komunikat jak na Rys Rysunek 2.16: Komunikat w oknie graficznym Definiowanie modułów prostych w C++ W języku NED definicja modułu prostego obejmuje jedynie interfejs zewnętrzny: bramy i parametry. Moduły proste to w rzeczywistości klasy napisane w języku C++, dziedziczące z klasy bazowej csimplemodule. Implementacja w praktyce polega utworzeniu takiej klasy, a następnie na redefiniowaniu wirtualnych metod tej klasy. Najczęściej są to metody:

57 2.4. PROGRAMOWANIE AKTYWNYCH MODUŁÓW (C++) 53 void initialize() - inicjalizacja modułu (wywoływana przed uruchomieniem obsługi zdarzeń); void handlemessage(cmessage *msg) - obsługa reakcji na zdarzenia; void finish() - wywoływana po zakończeniu symulacji, zawiera na ogół instrukcje zapisujące wyniki symulacji. Po uruchomieniu symulacji, ale jeszcze przed uruchomieniem obsługi zdarzeń OMNeT++ przeprowadza fazę inicjalizacji. Tworzone są moduły i łączone według opisów w języku NED. W tej fazie wywoływane są także metody initialize() wszystkich modułów prostych. W metodach tych mogą zostać utworzone i wysłane pierwsze komunikaty, które zostaną odebrane już w fazie obsługi zdarzeń. Faza realizacji symulacji polega na wywoływaniu dla zdarzeń o kolejnych czasach nadejścia odpowiednich metod void handlemessage(cmessage *msg) modułów, dla których zdarzenia te są przeznaczone. W metodach tych na ogół dochodzi do zmiany stanu symulacji (wartości zmiennych) oraz tworzone i wysyłane są kolejen komunikaty, reprezentujące kolejne zdarzenia. W wyniku przetworzenia wszystkich zdarzeń lub w wyniku osiągnięcia zadanego czasu symulacji (rzeczywistego lub symulowanego (por ) symulacja kończy się 16. Symulator przechodzi do fazy zakończenia symulacji. Wówczas wywoływane są metody finish() wszystkich modułów. Typowym zadaniem tych metod jest zapisanie wyników, zbieranych podczas symulacji (np. rozkładów, statystyk). Należy odróżniać metody initialize() od konstruktorów klasy i metody finish() od destruktorów. Tworzenie i usuwanie obiektów odbywa się niezależnie od tych metod. Wszelkie odwołania do jakichkolwiek mechanizmów związanych z symulacją należy wykonywać w fazie inicjalizacji, a nie w konstruktorze, w którym można jedynie tworzyć i inicjalizować wewnętrzne struktury danych klasy. Podobnie destruktor powinien służyć jedynie do zwalniania pamięci, zajętej przez dynamiczne struktury klasy. Powstała klasa musi zostać zarejstrowana w OMNeT++ za pomocą makra Define_Module() Najprostszy moduł prosty może być zaimplementowany następująco: 1 # include < omnetpp.h> 2 class ProstyModul : public csimplemodule 3 { 4 protected : 5 virtual void initialize (); 6 virtual void handlemessage ( cmessage * msg ); 7 }; 9 Define_ Module ( ProstyModul ); 11 void ProstyModul :: initialize () 12 { 13 ev << " Halo, tu Inicjalizacja!\ n"; 14 } 15 void ProstyModul :: handlemessage ( cmessage * msg ) 16 { 17 ev << " Odebrano komunikat "; 18 delete msg ; // usuwanie komunikatu 19 } Definiujemy nową klasę, o nazwie ProstyModul, bazując na typie csimplemodule. W ciele definicji deklarujemy dwie podstawowe metody wirtualne, które będziemy implementować: initalize() i handlemessage(cmessage *msg). Pamiętamy o zarejestrowaniu utworzonej klasy w OMNeT++ (makro Define_Module) Można także zarządać zakończenia symulacji bezpośrednio z kodu programu wywołując funkcję endsimulation(); 17 Zgodnie z zaleceniami twórców OMNeT++, makro Define_Module powinno być wywołane w plikach.cc lub.cpp, ale nie w plikach nagłówkowych.h.

58 54 ROZDZIAŁ 2. PAKIET OMNET++ Definicje metod są bardzo proste. Jak już wiadomo, ev pozwala nam na umieszczenie komunikatu w oknie komunikatów środowiska symulacji. Metoda handlemessage(cmessage *msg) zostanie wywołana dla każdego komunikatu adresowanego do instancji danego modułu. Metoda wypisuje informację o odebraniu komunikatu i kasuje go, żeby zwolnić miejsce w pamięci. Oczywiście w tych metodach nie tworzymy nowych komunikatów, więc zakładamy, że w systemie istnieje jakiś inny moduł, który się tym zajmie. Dla zdefiniowanego modułu musi istnieć jego reprezentacja w języku NED w postaci: 1 simple ProstyModul 2 gates : 3 in: in; 4 endsimple Proszę zwrócić uwagę, że użytkownik nie tworzy żadnych instancji modułów, a jedynie definiuje odpowiednie typy (klasy). Tworzeniem instancji zajmuje się OMNeT++ na podstawie plików NED i konfiguracji po uruchomieniu symulacji Metoda handlemessage(cmessage *msg) Metoda ta obsługuje nadchodzące do modułu komunikaty. Jej implementacja ma podstawowe znaczenie w budowie modelu symulacyjnego. Metoda ta, zdefiniowana w klasie csimplemodule jako wirtualna, jest wywoływana osobno dla każdego komunikatu, który przybywa do danego modułu. Komunikat ten jest dostępny na poziomie metody poprzez wskaźnik msg typu cmessage. W metodzie określamy sposób reakcji na zdarzenie (związane z nadejściem komunikatu). Z obsługą komunikatu (wywołaniem metody) nie wiąże się upływ czasu symulowanego. Z punktu widzenia modelu możemy przyjąć, że obsługa komunikatu zachodzi w czasie 0 sekund. Jeśli chcemy zasymulować niezerowy czas obsługi musimy skorzystać z dodatkowych mechanizmów (np. wysłać do samego siebie komunikat z czasem nadejścia równym czasowi obsługi, który będzie odzwierciedlał czas reakcji na zdarzenie). Konsekwencją tego rozwiązania jest to, że nie można żadnych informacji o stanie symulacji (pomiędzy kolejnymi komunikatami) przechowywać w zmiennych dynamicznych metody, gdyż będą one tracone z każdym jej wywołaniem. Należy więc pamiętać o zadeklarowaniu odpowiednich struktur danych jako pól w klasie. Struktury takie będą np. odzwierciedlać: stan modelu (IDLE/BUSY, CONNECTED/UNCONNECTED it.); liczniki, kolejki, timery; statystyki, pliki log-ów; parametry modelu, tablice routingu i wiele innych. Ciało metody składa się na ogół z sekwencji instrukcji rozpoznających rodzaj komunikatu na podstawie wskaźnika msg i wywołujących odpowiednią sekwencję instrukcji lub funkcję (metodę) obsługi. Rozpoznawanie komunikatu realizowane jest na ogół za pomocą sekwencji instrukcji warunkowych if...else lub konstrukcja warunkowa switch...case. Reakcja na zdarzenia obejmuje różne operacje zmieniające stan modelu symulacyjnego. W szczególności będzie to wygenerowanie nowych komunikatów, adresowanych do innych modułów, bądź do samego siebie (self-message). Do dyspozycji mamy więc następujące metody: 18 Wyjątkiem jest sytuacja, gdy podczas działania symulacji moduły oraz połączenia są tworzone dynamicznie (przez inne moduły). Rozwiązania takie nie będą jednak prezentowane w tej książce.

59 2.4. PROGRAMOWANIE AKTYWNYCH MODUŁÓW (C++) 55 send(), senddelayed(), senddirect() - zbiór metod różniących się parametrami, realizują wysłanie komunikatu do innych modułów; scheduleat() - wysłanie komunikatu typu self-message; cancelevent() - metoda usuwa określony komunikat typu self-message. Przykład implementacji metody przedstawiono poniżej (poszczególne elementy staną się bardziej zrozumiałe dzięki wyjaśnieniom w dalszej części rozdziału): 1 void Protocol :: handlemessage ( cmessage * msg ) 2 { 3 if ( msg - > isselfmessage ()) // rozpoznanie typu komunikatu 4 processtimer ( msg ); 5 else 6 if ( msg - > arrivedon (" fromnetw ")) // rozpoznanie kierunku nadejścia komunikatu ( która brama?) 7 processmsgfromlowerlayer ( check_and_cast < FooPacket * >( msg )); 8 else 9 processmsgfromhigherlayer ( msg ); 10 } Trzeba pamiętać, że moduły z zaimplementowaną metodą handlemessage() nie uruchomią się samodzielnie. Do każdego wywołania tej metody konieczne jest odebranie komunikatu. Pierwsze komunikaty, startowe muszą więc zostać w jakiś sposób wygenerowane. Do tego służy inna wirtualna metoda każdego z modułów o nazwie initialize(). Metoda initialize() jest wywoływana dla każdego modułu przed rozpoczęciem przetwarzania komunikatów. Podobnie, każdy moduł posiada wirtualną metodą finish(), która jest wywoływana po zakończeniu procesu przetwarzania komunikatów. Należy pamiętać, aby odróżniać te metody jako niezależne od konstruktora i destruktora obiektu. W szczególności konstruktor wywoływany jest przed wywołaniem metody initialize(), a destruktor po metodzie finish(). Komunikaty mogą docierać do modułów na różne sposoby. Mogą to być komunikaty przesyłane za pomocą połączeń i wówczas docierają do modułów poprzez bramy. Mogą to być też komunikaty przesyłane bezpośrednio do innych modułów (z pominięciem bram i połączeń) lub tzw. self messages, czyli wysłane przez moduł do samego siebie. Przesyłanie bezpośrednie i tzw. self-messages zostały opisane w dalszej części (zob. 2.5). Zajmiemy się najpierw najczęściej wykorzystywanym przypadkiem: wysyłaniem i odbieraniem komunikatów przez bramy oraz identyfikacją takich komunikatów. Metoda activity() Metoda activity() odzwierciedla działanie modułu przez cały czas działania symulacji, w odróżnieniu od handlemessage(), dla której kod związany z danym modułem wywoływany jest jedynie podczas otrzymania komunikatu, a w pozostałym czasie jej aktywność jest uśpiona. Metoda activity() realizowana jest w postaci pętli, w której powinno sprawdzać się, czy nie nadszedł komunikat. Między komunikatami mogą być realizowane inne instrukcje, lub też może sama przejść w stan uśpienia na określony odcinek czasu lub do momentu nadejścia kolejnego komunikatu. Mimo prostoty tej metody i jej intuicyjności, należy zauważyć, że dla złożonych symulacji utrzymywanie aktywności poszczególnych modułów (w sposób równoległy) znacznie obniża efektywność symulacji. Dlatego też implementacja aktywności modułów w oparciu o metodę activity() nie jest zalecana. Nie jest też pewne, czy metoda ta zostanie zachowana w kolejnych wersjach OMNeT++. Z powyższych względów metoda activity() nie będzie w tej książce szerzej omawiana.

60 56 ROZDZIAŁ 2. PAKIET OMNET Obsługa bram i połączeń Bramy i połączenia deklarowane i definiowane są na poziomie języka NED. Każda brama posiada więc identyfikator (na poziomie C++ jest to łańcuch znaków) oraz, jeśli jest to wektor bram, numer indeksu. Połączenia łączą ze sobą bramy i komunikaty są przesyłane między nimi za ich pośrednictwem, z uwzględnieniem parametrów tego połączenia. Jeśli kolejnym punktem na drodze komunikatu jest brama modułu złożonego, przesyłany jest on dalej, poprzez kolejne połączenie, aż osiągnie moduł przeznaczenia - określony moduł prosty. Tam komunikat przetwarzany jest przez metodę handlemessage() lub activity(). Ponieważ brama wyjściowa determinuje odbiorcę (określoną bramę docelową), użytkownik musi mieć możliwość wysyłania komunikatów przez wybrane bramy a także identyfikacji bram dla komunikatów przychodzących. Bramy w C++ reprezentowane są przez obiekty typu cgate. Aby pobrać wskaźnik na konkretną bramę modułu wywołujemy metodę Gate tego modułu, podając jako parametr identyfikator bramy: 1 cgate * outgate = gate (" out "); Jeśli zamiast pojedynczej bramy zdefiniowany jest wektor bram, obok identyfikatora podajemy numer indeksu konkretnej bramy (indeksy numerowane od 0): 1 cgate * outvec5gate = gate (" outvec ",5); Można też sprawdzić, czy identyfikator określa wektor bram, czy pojedynczą bramę, korzystając z bezparametrowej metody klasy cgate - isvector(). Zwraca wartość true dla bram reprezentujących wektory. W praktyce, o ile na ogół wiadomo, czy konkretna brama jest wektorem, to już rozmiar tego wektora (na ogół parametryzowany z poziomu języka NED lub omnetpp.ini) jest nieznany. Można go sprawdzić wywołując metodę klasy cgate - size(). Obiekt bramy zna także swoją pozycję (indeks) w wektorze, co można odczytać metodą index(), np: 1 int size2 = outvec5gate - > size (); // --> rozmiar outvec5gate [] 2 int index = outvec5gate - > index (); // --> 5 ( piąta brama wektora ) Wielkość wektora można też odczytać bezpośrednio za pomocą identyfikatora bramy i metody gatesize("name"): 2 int size3 = gatesize (" out "); Numery identyfikacyjne bram Bramy, z poziomu języka C++, poza identyfikatorem (nazwą) i ew. numerem indeksu (jeśli korzystamy z wektora bram) posiadają jeszcze numer identyfikacyjny (tzw. Gate Id), który jest unikalny w ramach danego modułu prostego. Nie należy mylić tego numer z indeksem. Numer ten możemy odczytać wywołując metodę id() obiektu cgate: 1 int id = outgate ->id (); Można też odczytać go na podstawie identyfikatora bramy (identyfikatora i indeksu, w przypadku wektora bram): 1 int id1 = findgate (" out "); 2 int id2 = findgate (" outvect ",5) Numer identyfikacyjny bramy można następnie wykorzystać podczas wysyłania komunikatów, podając go zamiast identyfikatora i indeksu. Takie rozwiązanie zwiększa nieco wydajność symulacji, kosztem zmniejszenia przejrzystości kodu.

61 2.5. KOMUNIKATY 57 Identyfikacja niepodłączonych bram Przy okazji tworzenia połączeń w języku NED można było skorzystać ze słowa kluczowego nocheck i wtedy niektóre bramy mogły pozostać niepodłączone, bez generowania błędu przy kompilacji plików.ned (zob ). Takie podejście w pewnych przypadkach ułatwiało tworzenie topologii sieci, jednak na poziomie języka C++ wówczas istnieje konieczność rozpoznawanie takich niepodłączonych bram i uniknąc wysyłania przez nie komunikatów. Służy do tego metoda klasy cgate o nazwie isconnected(), np: 1 cgate * gate = gate (" somegate "); 2 if (! gate -> isconnected ()) 3 { 4 ev << " gate not connected " << endl ; 5 } Dodatkowe informacje OMNeT++ pozwala na uzyskanie jeszcze bardziej szczegółowych informacji o połączeniach i bramach (np. uzyskania pełnej ścieżki wzdłuż połączeń między modułami. Dokładniejszy opis tych możliwości znajduje się w instrukcji obsługi OMNeT++ [OMN]. 2.5 Komunikaty Rozszerzymy teraz wprowadzone już wcześniej pojęcie komunikatu. Podstawową klasą dla komunikatów jest cmessage. Komunikat może odpowiadać bardzo wielu aspektom realizowanej symulacji. Może odzwierciedlać pakiety, ramki, segmenty czy nawet elementarne jednostki informacji jak bajty, bity, sygnały. Jeśli symulacja dotyczy modeli spoza tematyki sieci komputerowych może to być np. klient serwisu, pojazd czy paczka pocztowa. Może też odzwierciedlać abstrakcyjne zdarzenia, które mają wpływ na przebieg symulacji (np. uszkodzenie połączenia sieciowego) lub realizować wewnętrzne funkcje kontrolne i pomocnicze, nie związane bezpośrednio z symulacją (np. komunikaty synchronizacji). W przypadku prostych symulacji nie jest konieczne tworzenie własnych klas komunikatów (dziedziczących po cmessage. Bazowa klasa posiada zbiór użytecznych atrybutów. Część z nich jest wykorzystywana przez jądro symulacji, część jest przeznaczona do wykorzystania przez użytkownika. Kolejno są to 19 : name, typu const char *, nazwa komunikatu. Jest często wykorzystywana do rozpoznawania typu nadchodzących komunikatów. Podczas symulacji z wizualizacją (Por nazwa stanowi łatwo rozpoznawalny atrybut animowanych komponentów 20 ;. kind, typu int jest także atrybutem użytkownika 21. Może służyć do liczbowego określenia typu pakietu; length, typu int, długość pakietu określona w bitach. Wartość ta jest wykorzystywana do obliczenia opóźnienia i przekłamań pakietu podczas przesyłania przez połączenia; bit error flag, typu bool, jest ustawione na true jeśli podczas przesyłania pakietu uległ on uszkodzeniu. Reakcja na uszkodzone pakiety oczywiście zależy od implementacji modelu przez użytkownika; 19 nazwy atrybutów zostały oznaczone jako italic, bo dostęp do nich realizowany jest za pomocą metod pośrednich (zbiór metod set...), a nie bezpośrednio z użyciem nazw atrybutów. 20 Ściślej nazwa jest atrybutem przypisanym do wszystkich obiektów symulacji w OMNeT++ i jest zdefiniowana na poziomie cobject 21 Ściślej, użytkownik nadaje wartości tego atrybutu jako większe lub równe 0. Wartości mniejsze niż 0 są zarezerwowane na potrzeby biblioteki symulacyjnej.

62 58 ROZDZIAŁ 2. PAKIET OMNET++ priority, typu int, decyduje o kolejności wywoływania komunikatów, jeśli ich czas nadejścia jest taki sam; timestamp, typu simtime_t, określa czas nadejścia komunikatu; Poza wymienionymi pakiet przechowuje także listę parametrów zdefiniowanych przez użytkownika, może enkapsulować inne komunikaty. Posiada też pola kontrolne i wskaźnik kontekstu. Parametry te zostaną omówione w dalszej części rozdziału. Podstawowe działania Aby wysłać komunikat należy najpierw utworzyć obiekt klasy cmessage. W zależności od konkretnych zastosowań należy skorzystać z jednego z wielu konstruktorów 22, m.in: cmessage *msg = new cmessage(); cmessage *msg = new cmessage("nazwa"); cmessage *msg = new cmessage("nazwa", rodzaj); Parametr "nazwa" jest łańcuchem znaków (atrybut name, który zostaje przypisany do komunikatu, a rodzaj jest przyjętym przez użytkownika oznaczeniem typu komunikatu (atrybut kind). Zalecane jest aby zawsze nadawać nazwy tworzonym obiektom, gdyż ułatwia to uruchamianie i wyszukiwania błędów a także ułatwia śledzenie wizualizacji. Atrybut kind często jest ustawiany w odrębnym pliku.h jako stała symboliczna (zdefiniowana w ciągu dyrektyw #define lub w ramach typu wyliczeniowego), gdzie poszczególne identyfikatory reprezentują rodzaje możliwych w symulacji komunikatów, np.: 1 # define DataFrame 0 2 # define AckFrame 1 3 # define RequestFrame 2 4 # define TimeOut 3 Takie rozwiązanie zwiększa czytelność kodu symulatora. Jeśli korzystamy z powyższych definicji przykładowa obsługa komunikatów może wyglądać następująco (w zależności od komunikatu wywołujemy właściwą funkcję obsługi); 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 switch (msg -> kind ()) 4 { 5 case DataFrame : odbierzramke ( msg ); break ; 6 case AckFrame : potwierdzramke ( msg ); break ; 7 case RequestFrame : rozpocznijtransmisje ( msg ); break ; 8 case TimeOut : przekroczenieczasu ( msg ); break ; 10 default : ev << " Nieznany rodzaj komunikatu!"; 11 } 12 } Zbiór metod, które pozwala na inicjalizację podstawowych parametrów jest następujący: 1 msg -> setkind ( rodzaj ); 2 msg -> setlength ( dlugosc ); 22 Dostępne są także inne konstruktory, które umożliwiają inicjalizację pozostałych atrybutów, jednak zalecanym rozwiązaniem jest ich inicjalizacja w osobnych liniach.

63 2.5. KOMUNIKATY 59 3 msg - > setbytelength ( dlugosc_ w_ bajtach ); 4 msg - > setpriority ( priorytet ); 5 msg -> setbiterror ( err ); 6 msg -> settimestamp (); 7 msg - > settimestamp ( simtime ); Znaczenie większości metod jest oczywiste. Metoda setbytelength() przyjmuje wartości w bajtach, więc przed przypisaniem do atrybutu length są mnożone przez 8. Bezparametrowa metoda settimestamp() ustawia atrybut timestamp na bieżącą wartość zegara symulacji. Parametry komunikatów można odczytywać, korzystając z następujących metod: 1 int k = msg -> kind (); 2 int p = msg -> priority (); 3 int l = msg -> length (); 4 int lb = msg -> bytelength (); 5 bool b = msg - > hasbiterror (); 6 simtime_t t = msg -> timestamp (); Przykładowo, możemy zdefiniować metodę initialize(), która utworzy i wyśle prosty komunikat przez bramę "out" (zakładamy, że taka brama istnieje). Zakładamy też, że moduł ma zdefiniowany w NED parametr Dlugosc: 1 void JakisModul :: initialize () 2 { 3 cmessage * m = new cmessage (" Komunikat "); 4 m-> setlength ( par (" Dlugosc ")); 5 ev << " Inicjalizacja, wysylam komunikat \ n"; 6 send (m, " out "); 7 } Enkapsulacja i dekapsulacja komunikatów Czasami tworząc bardziej złożony model komunikacji w sieciach komputerowych konieczne jest zamodelowanie mechanizmów enkapsulacji i dekapsulacji komunikatów. Tworzenie takiego mechanizmu ręcznie byłoby dość złożone, na szczęście OMNeT++ udostępnia odpowiednie metody. Metoda encapsulate() enkapsuluje jeden komunikat w drugim. Długość komunikatu opakowującego odpowiednio zwiększa się. Mechanizm ten ilustruje przykład: 1 cmessage * danehttp = new cmessage (" http "); 2 danehttp - > setbytelength (2048) ; 3 ev << " Długość daych :" << danehttp - > bytelength () << endl ; // cmessage * tcpsegment = new cmessage (" tcp "); 6 tcpsegment - > setbytelength (24) ; 8 tcpsegment -> encapsulate ( danehttp ); 9 ev << " Długość segmentu :" << tcpsegment - > bytelength () << endl ; // = 2072 Każdy komunikat może enkapsulować jedynie jeden, inny komunikat. Kolejne wywołanie encapsulate() spowoduje błąd symulacji. Odwrotną operację realizuje metoda decapsulate() 23. Użycie tej metody może być następujące:: 23 Wielkość komunikatu analogicznie zmniejsza się o wielkość komunikatu rozpakowanego, choć w rzeczywistości dalsze wykorzystanie komunikatu opakowującego na ogół nie jest już potrzebne.

64 60 ROZDZIAŁ 2. PAKIET OMNET++ 1 cmessage * danehttp = tcpseg - > decapsulate (); Uzupełnieniem tego mechanizmu jest metoda encapsulatedmsg(), która zwraca wskaźnik na enkapsulowany komunikat, lub NULL, jeśli żaden komunikat nie jest enkapsulowany Wysyłanie komunikatów Schemat działania modułów prostych tak naprawdę ogranicza się do odbierania i wysyłania komunikatów. Odbieranie komunikatów polega na odpowiednim przetworzeniu zmiennej msg, będącej wskaźnikiem otrzymanym dzięki wywołaniu metody handlemessage(cmessage *msg). Zajmiemy się teraz szerszym omówieniem zagadnienia wysyłania komunikatów. Aby wysłać komunikat musi on zostać najpierw przygotowany (utworzony lub odebrany odpowiedni obiekt klasy cmessage). Do wysyłania służy zbiór metod send. W najprostszym przypadku korzystamy z wysłania komunikatu przez określoną bramę, podając odpowiednie parametry: identyfikator (nazwę) bramy i (opcjonalnie) indeks bramy: send(cmessage *msg, const char *gatename, int index=0); numer identyfikacyjny bramy: send(cmessage *msg, int gateid); wskaźnik na obiekt bramy: send(cmessage *msg, cgate *gate); Najprostszym przykładem będzie tu moduł, który odbiera komunikat i natychmiast wysyła go na bramę wyjściową (o nazwie wyjscie): 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 send (msg, " wyjscie "); 4 } Częściej zdarza się, że moduł przetwarza komunikat (np. odbiera jakieś dane, uaktualnia statystyki itp.) a w odpowiedzi wysyła inny komunikat (np. potwierdzenie). Wówczas sekwencja instrukcji może być następująca: 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 if (msg -> kind () == DataFrame ) 4 { 5 odebrano += msg - > bytelength (); 6 cmessage * ack = new cmessage (); 7 ack -> setkind ( AckFrame ); 8 send (ack, " wyjscie "); 9 delete ( msg ); 10 } } Identyfikacja właściwej klasy komunikatu W rozbudowanych symulacjach modelowanie wszystkich przypadków komunikacji w oparciu o standardową klasę cmessage na ogół już nie wystarcza. Można co prawda rozbudowywać obiekty tej klasy o

65 2.5. KOMUNIKATY 61 dodatkowe parametry (obiekty klasy cpar), lecz zbyt duża liczba parametrów wpływa na zmniejszenie wydajności symulacji. W takich wypadkach należy utworzyć własne klasy w oparciu o klasę bazową cmessage lub skorzystać z opisanego w dalszej części książki, wbudowanego w OMNeT++ mechanizmu do tworzenia nowych komunikatów (Patrz 2.4). Zgodnie z deklaracją metody handlemessage(cmessage *msg) nadchodzące do modułu komunikaty są zawsze typu cmessage. Jeśli w symulacji wszystkie komunikaty zbudowane są w oparciu o inny typ, np. cpakietip wówczas, po odebraniu, wystarczy zastosować proste rzutowanie na właściwy typ, np: 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 cpakietip * n_msg = ( cpakietip *) msg ; } W przypadku jednak, gdy w modelu zdefiniowanych jest wiele klas komunikatów, pewnym problemem dla początkujących użytkowników jest jednak rozróżnienie dla przychodzących komunikatów właściwej klasy i przeprowadzenie rzutowania na właściwy typ. Właściwym rozwiązaniem wówczas jest zastosowanie operatora C++ dynamicznego rzutowanie dynamic_cast<typ> 24. Jeśli operacja rzutowania nie powiedzie się, wówczas jej wynik będzie równy NULL, co można wykorzystać w instrukcji warunkowej, jak na przykładzie, w którym występują dwa rodzaje komunikatów (cpakietip i cicmp): 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 if ( dynamic_cast < cpakietip * >( msg )!= NULL ) 4 { 5 cpakietip * pakiet = ( cpakietip *) msg ; } 8 if ( dynamic_cast < cicmp * >( msg )!= NULL ) 9 { 10 cicmp * pakieticmp = ( cicmp *) msg ; } 13 else 14 ev << " Niezidentyfikowany typ pakietu!"; 15 } Opóźnione wysyłanie komunikatów Omówiona wcześniej grupa metod send() realizowała wysyłanie komunikatów natychmiast po jej wywołaniu. Opóźnienie związane z dostarczeniem wysłanego w ten sposób komunikatu do odbiorcy wiązało się jedynie z opóźnieniem propagacji komunikatu przez kanały komunikacyjne. Czasami jednak pojawia się konieczność zamodelowana pewnego opóźnienia związanego np. z przetwarzaniem komunikatu, zanim zostanie on wysłany. Można to zrealizować za pomocą tzw. self-messages (co zostanie opisane w dalszej części), ale znacznie łatwiej jest zastosować tzw. wysyłanie z opóźnieniem. Realizowane jest ono przez zestaw trzech metod. W każdej trzeba podać dodatkowy parametr, jakim jest opóźnienie wysłania pakietu. Pozostałe parametry są identyczne jak w przypadku metod send(). Są to więc kolejno: senddelayed(cmessage *msg, double delay, const char *gatename, int index); senddelayed(cmessage *msg, double delay, int gateid); 24 W OMNeT++ zdefiniowany został także operator check_and_cast<>(), który wywołuje błąd symulacji, jeśli w wyniku rzutowania otrzymano NULL.

66 62 ROZDZIAŁ 2. PAKIET OMNET++ senddelayed(cmessage *msg, double delay, cgate *gate); Przykładowe wykorzystanie może być następujące (opóźnienie obliczane z rozkładu, na podstawie wyniku zwracanego przez metodę truncnormal()): 1 double opoznienie = truncnormal (0.005, ) ; 2 cmessage pakiet = new cmessage (" pakiet "); 3 senddelayed ( pakiet, opoznienie, " wyjście "); Bezpośrednie przesyłanie komunikatów W pewnych przypadkach może okazać się potrzebne wysłanie komunikatu bezpośrednio do konkretnego modułu, z pominięciem topologii połączeń. Do tego celu służą metody senddirect(). Aby skorzystać z tej metody należy określić jej parametry: komunikat do wysłania, opóźnienie dostarczenia (co jest szczególnie istotne, gdyż w przesyłaniu bezpośrednim nie występuje opóźnienie związane z propagacją komunikatu przez połączenia) oraz parametry określające bramę w module docelowym (musi to być brama wejściowa), przez którą komunikat zostanie dostarczony. Metody są następujące: senddirect(cmessage *msg, double delay, cmodule *mod, int gateid) senddirect(cmessage *msg, double delay, cmodule *mod, const char *gatename, int index=-1) senddirect(cmessage *msg, double delay, cgate *gate) Jedynym problemem jest tutaj określenie bramy docelowej. Można to osiągnąć za pomocą metod parentmodule() i submodule(), które umożliwiają przemieszczanie po hierarchii modelu, udostępniając odpowiednio wskaźniki modułu nadrzędnego i modułów składowych. Mechanizm ten ilustruje przykład: 1 cmodule * moduldocelowy = parentmodule () -> submodule (" PewienModul "); 2 double opoznienie = 0.001; 3 cmessage pakiet = new cmessage (" pakiet "); 4 senddirect ( pakiet, opoznienie, moduldocelowy, " wejscie "); Po wysłaniu takiego komunikatu moduł docelowy odbiera go w normalny sposób, identycznie jak przy wykorzystaniu metod send(). Bezpośrednie wysyłanie komunikatów może być przydatne, jeśli korzystamy z dynamicznego tworzenia modułów lub w pewnych specyficznych modelach, np. sieci bezprzewodowych. Zmniejsza jednak czytelność kodu i uniemożliwia symulację rozproszoną. Duplikowanie komunikatów Często po otrzymaniu komunikatu zachodzi konieczność rozesłania go do wielu kolejnych modułów (symulując np. rozgłaszanie), lub wysłania pakietu z jednoczesną potrzebą zachowania jego kopii. Można to osiągnąć w łatwy sposób, wykorzystując jeden z dwóch, równoważnych mechanizmów. Pierwszy to użycie wbudowanej w klasę cmessage metoda dup(), która zwraca wskaźnik na obiekt będący kopią tego obiekt, dla którego wywołano metodę 25, np: cmessage *copy = (cmessage *) msg->dup(); Przykładowo, gdy chcemy rozesłać komunikat przez n bram wyjściowych: 1 for ( int i =0; i<n; i ++) 2 { 25 Ściślej, metoda dup() jest metodą wirtualną klasy cpolymorphic, klasy bazowej dla wszystkich klas OMNeT++. Tak więc taką możliwość kopiowania posiadają wszystkie obiekty symulacji, nie tylko komunikaty.

67 2.5. KOMUNIKATY 63 3 cmessage * copy = ( cmessage *) msg - > dup (); 4 send (copy, " out ", i); 5 } 6 delete msg ; Druga możliwość to skorzystanie z konstruktora, w którym jako parametr przekazano wskaźnik komunikatu, który chcemy skopiować: cmessage *copy = new cmessage( *msg ); Problem własności obiektów Każdy obiekt w OMNeT++ (oparty na cobject)ma przypisane wskazanie na obiekt, który go stworzył (ownership). Gdy np. komunikat tworzony jest w module prostym, moduł ten staje się jego właścicielem. Jeśli komunikat ten jest enkapsuklowany w innym komunikacie, właścicielem staje się ten właśnie komunikat. Po odebraniu komunikatu odbiorca staje się właścicielem. Takie rozwiązanie zabezpiecza przed powstawaniem wielu błędów, wspomaga działanie wizualizacji, umożliwia śledzenie ścieżek obiektów (np. metoda fullpath(). Rozwiązanie takie może jednak czasami powodować błędy, szczególnie gdy użytkownik nie zdaje sobie sprawy z istnienia tego mechanizmu. Przykładem może być błędna implementacja retransmisji komunikatów w symulacji. Określony komunikat został wysłany, lecz moduł zachowuje wskaźnik na ten komunikat, aby wykorzystać go ponownie, jeśli zajdzie potrzeba retransmisji (np. przekroczony został czas TimeOut). Przy korzystaniu jednak z metod z grupy send() lub scheduleat() sprawdzane jest, czy moduł, który wysyła komunikat jest jego właścicielem. Jeśli nie, generowany jest komunikat o błędzie (runtime error: not owner of message) i symulacja jest przerywana. W opisywanym przypadku do takiego właśnie błędu dojdzie. Rozwiązanie jest proste i należy go konsekwentnie przestrzegać. Komunikaty muszą być traktowane jak obiekty rzeczywiste, które nie mogą znajdować się w kilku miejscach w tym samym czasie. Po wysłanie komunikatu nie należy on już do tego modułu i jakiekolwiek wskazania do tego obiektu należy traktować jako nieaktualne. Opisywany powyżej problem retransmisji można rozwiązać w taki sposób, że moduł wysyła kopie obiektu komunikatu, oryginał zachowując na potrzeby retransmisji: 1 // Retransmisja : 2 cmessage * copy = ( cmessage *) packet - > dup (); 3 send (copy, " out "); Jeśli dalsze korzystanie z oryginału komunikatu nie będzie już potrzebne, powinien on zostać usunięty za pomocą operatora delete (delete packet;). Autokomunikaty (ang. self-messages) Komunikaty self-messages 26 są to komunikaty, które moduł wysyła do samego siebie. Zostaną one odebrane przez ten moduł po upływie zadanego czasu (lub jeszcze w tym samym slocie czasowym). Zastosowanie tych komunikatów obejmuje tworzenie wszelkiego rodzaju zegarów (timers), synchronizowanie modułu w określonych punktach czasowych, modelowanie czasów obsługi, reprezentację różnych wewnętrznych zdarzeń w modułach itp. Na przykład pewien moduł wysyła pakiet i chce się upewnić, że w określonym czasie TimeOut dotrze do niego od odbiorcy potwierdzenie otrzymania. Wysyła więc self-message z czasem przybycia odległym o TimeOut od bieżącego czasu symulacji. Jeśli potwierdzenie pakietu dotrze jako pierwsze ustawiana jest odpowiednia flaga lub self-messages jest usuwany z kolejki przyszłych komunikatów. Jeśli pierwszy przyjdzie self-message, a potwierdzenia do tego czasu nie

68 64 ROZDZIAŁ 2. PAKIET OMNET++ odnotowano, wtedy trzeba przeprowadzić retransmisję tego pakietu. Wysyłanie self-messages realizowane jest w oparciu o metodę scheduleat(). Jako argumenty podaje się bezwzględny czas nadejścia oraz obiekt komunikatu: scheduleat(czasabsolutny, komunikat); Na ogół zamiast podawać wartość czasu absolutnego wygodniej jest podać wartość czasu względnego (opóźnienia). Wówczas można odnieść się do czasu bieżącego za pomocą funkcji simtime() i dodać wartość opóźnienia: scheduleat(simtime() + opoznienie, komunikat); Z programistycznego punktu widzenia self-messages są obiektami typu cmessage (lub oparte na tym typie), podobnie jak wszystkie pozostałe komunikaty. Gdy komunikat taki dociera do modułu wywoływana jest więc metoda HandleMessage(), należy dokonać sprawdzenia komunikatu i podjąć odpowiednie działania 27. Przydatna jest możliwość sprawdzenia, czy dostarczony komunikat jest typu self-message, za pomocą metody bool isselfmessage() (jeśli tak, zwraca wartość true): W opisanym powyżej przykładzie oczekiwaliśmy, który komunikat nadejdzie pierwszy: potwierdzenie odebrania pakietu czy self-message z komunikatem o przekroczeniu czasu. Jeśli będzie to potwierdzenie odebrania, wówczas komunikat o przekroczeniu czasu, ciągle oczekujący na dostarczenie, staje się nieaktualny. Istnieje wówczas możliwość sprawdzenie, czy określony komunikat self-message znajduje się w kolejce oczekujących na dostarczenie (służy do tego metoda klasy cmessage o nazwie isscheduled(), a następnie można taki komunikat odwołać (funkcja cancelevent(komunikat)) 28 ; Rozwiązanie takie przedstawia poniższy przykład 29. Jeśli odebrany komunikat to potwierdzenie: 1 void JakisModul :: handlemessage ( cmessage * msg ) 2 { 3 switch (msg -> kind ()) 4 { 5 case AckFrame : 6 if ( przekroczenieczasu - > isscheduled () 7 cancelevent ( przekroczenieczasu ); case TimeOut : przekroczenieczasu ( msg ); 10 ev << " Przekroczenie czasu. Konieczna retransmisja."; } } Dodawanie parametrów do komunikatów Proste komunikaty, jako obiekty klasy cmessage zawierają kilka parametrów, z których część może być wykorzystana przez użytkownika (np. parametr kind). Do większości bardziej rozbudowanych zastosowań 26 Trudno w tym wypadku przyjąć jakieś sensowne polskie tłumaczenie. Autorzy, nie chcąc tworzyć kolejnego słownego potworka postanowili używać angielskiego terminu self-messages 27 Różnica w stosunku do odebrania zwykłego pakietu jest to, że self-messages dociera do modułu bezpośrednio, z pominięciem bram. 28 Funkcja cancelevent(komunikat) zwraca wskaźnik na komunikat, usuwając go jednocześnie z kolejki przyszłych komunikatów. Należy też pamiętać, że wywołanie jej w przypadku, gdy w kolejce nie ma określonego komunikatu spowoduje błąd programu. Funkcję tę należy więc zawsze stosować w zestawie z metodą isscheduled(). Uwaga: tylko komunikaty typu self-messages mogą być usuwane z kolejek oczekujących komunikatów. 29 Należy pamiętać, że handlemessage(cmessage *msg), jak każda inna funkcja i metoda, nie zachowuje zmiennych zadeklarowanych w jej ciele jako dynamicznych. Należało by więc zadeklarować wskaźnik cmessage * przekroczenieczasu jako atrybut modułu.

69 2.5. KOMUNIKATY 65 potrzebnych jest jednak znacznie więcej parametrów. Na przykład dla zamodelowania nagłówka IP będzie to długość nagłówka, typ usługi, całkowita długość, identyfikacja protokołu, znaczniki, adres źródłowy, adres docelowy, TTL itp. Zalecanym rozwiązaniem jest zdefiniowanie własnej klasy komunikatów, w oparciu o bazową klasę cmessage (patrz Definiowanie własnych komunikatow). W prostych przypadkach, lub kiedy nie wymagamy od symulacji dużej wydajności, wystarczające może się okazać wykorzystanie klasy parametrów cpar. Jest to możliwe dlatego, że każdy obiekt klasy cmessage posiada wbudowaną tablicę dynamiczną (carray), do której można dodawać i z której można usuwać parametry (właśnie obiekty klasy cpar). Dodawanie parametru realizuje metoda addpar(nazwa). Dostęp do dodanego parametru uzyskujemy poprzez nazwę (metoda par("nazwa"). Z pomocą tej metody można zarówno odczytywać jak i ustawiać wartość parametrów. Przy odbieraniu komunikatu można sprawdzić, czy posiada on określony parametr, korzystając z metody haspar("nazwa"), zwracającej wartość logiczną. Przykładowa sekwencja dodania parametru, ustawiania wartości oraz sprawdzenia i odczytu, w oparciu o wprowadzone metody, może być następująca: 1 msg -> addpar (" adresdocelowy "); 2 msg - > par (" adresdocelowy ") = 145; // komunikat msg zostaje odebrany w module docelowym : 5 if (msg -> haspar (" adresdocelowy ") 6 ev << " Adres docelowy to: " << msg - > par (" adresdocelowy "); 7... Dodawanie obiektów do komunikatów Bardziej zaawansowane możliwości korzystania z komunikatów obejmują także dodawanie do ch struktury obiektów. Warunkiem jest, aby były to obiekty klasy cobject lub pochodne (patrz 2.11-Biblioteka klas). Jest to bazowa klasa dla niemal wszystkich klas wykorzystywanych w OMNeT++, więc większość obiektów biblioteki symulacyjnej spełnia ten warunek. W przypadku obiektów użytkownika trzeba jednak pamiętać o odpowiednim dziedziczeniu. Klasa komunikatów posiada wbudowaną strukturę typu tablica dynamiczna carray, która odpowiada za przechowywanie obiektów (ściślej, wskaźników na obiekty). Związane są z tym odpowiednie metody addobject(), getobject(), hasobject(), removeobject(). Można dodawać dowolną liczbę obiektów. Zakładając, że istnieje zdefiniowana klasa mojaklasa dziedzicząca po cobject, można przykładowo zapisać sekwencję: 1 mojaklasa * pewienobiekt = new mojaklasa (" nazwaobiektu "); 2 msg -> addobject ( pewienobiekt ); // komunikat msg zostaje odebrany w module docelowym : 5 if (msg -> hasobject (" nazwaobiektu ")) 6 { 7 mojaklasa * odebranyobiekt = ( mojaklasa *) msg - > getobject (" nazwaobiektu "); } Wyjaśnienia wymaga konstruktor klasy mojaklasa. Podawany jest w nim identyfikator (łańcuch tekstowy) "nazwaobiektu". Oczywiście konstruktor może być dowolny inny, jednak jednym z atrybutów podstawowej klasy cobject jest jego nazwa (łańcuch znaków typu char *). Ze względu na dziedziczenie

70 66 ROZDZIAŁ 2. PAKIET OMNET++ atrybut ten mają praktycznie wszystkie obiekty biblioteki symulacyjnej. Jeśli nazwa nie została określona (parametr ten jest opcjonalny w obiektach klasy cobject) przed dodaniem obiektu trzeba ją określić. W przypadku dodawania obiektów do komunikatu właśnie nazwa obiektu jest wykorzystywana do jego identyfikacji pośród pozostałych obiektów (jeśli zostały dodane) i pozostałych parametrów (dlatego nazwa ta nie może pokrywać się z nazwą innego obiektu ani parametru). Dodawanie obiektów typu void * do struktury komunikatów Ze względu na właściwości klasy parametrów cpar istnieje możliwość dodawania do komunikatów także parametrów dowolnego typu, a dokładniej może to być parametr typu void * (dowolny wskaźnik). W szczególności mogą to być dowolne obiekty, nawet takie, które nie dziedziczą po cobject. Przykładowo dodamy do komunikatu strukturę: 1 struct naglowek { 2 int adreszrodlowy ; 3 int adresdocelowy ; 4 int typprotokolu ; 5 }; struct naglowek * naglowekinfo = new naglowek ; 8 msg - > addpar (" naglowekinfo ") = ( void *) naglowekinfo ; 9 msg -> par (" naglowekinfo "). configpointer (NULL,NULL, sizeof ( struct naglowek )); Należy jednak w tym miejscu zaznaczyć, że jeśli użytkownik, rozbudowując swój symulator, stanie przed koniecznością stosowania tego typu mechanizmów, to powinien zamiast tego zdecydować się raczej na zdefiniowanie własnych klas komunikatów, co poprawi czytelność programu i przyspieszy działanie symulacji (patrz 2.5.2) Definiowanie własnych klas komunikatów (pliki.msg) Standardowa klasa komunikatów cmessage w bardziej złożonych zastosowaniach często przestaje być wystarczająca. Często potrzebne jest wiele nowych atrybutów oraz własnych metod. Przykładowo, symulując nagłówek pakietu IP trzeba dodać pole protokołu, TTL, adres IP nadawcy i odbiorcy, pola kontrolne i wiele innych. Użytkownicy implementujący modele symulacyjne mają do wyboru jedną z dwóch możliwości: dodanie parametrów do obiektów klasy cmessage lub utworzenie własnych klas komunikatów, zawierających już potrzebne pola i metody. Pierwsza z nich to skorzystanie z możliwości dodawanie własnych, dodatkowych parametrów bezpośrednio do obiektów klasy cmessage. Parametry są obiektami typu cpar 30. Rozwiązanie to jest bardzo proste i polega na skorzystaniu z metod addpar("nazwa") i par("nazwa"). Pierwsza pozwala na dodanie do obiektu komunikatu parametru o nazwie określonej przez łańcuch znaków "nazwa". Przykładowa sekwencja dodania parametru, a następnie jego odczytu prezentowana jest poniżej: 1 msg -> addpar (" destaddr "); 2 msg -> par (" destaddr ") = 100; long destaddr = msg -> par (" destaddr ");

71 2.5. KOMUNIKATY 67 Można także skorzystać z metody haspar("name") zwracającą true, jeśli dany parametr występuje w obiekcie. W wielu przypadkach rozwiązanie to jest wystarczające, jego największą zaletą jest prostota. Dodajemy dowolną liczbę parametrów, tyle ile wymaga implementacja danego typu komunikatu (np. wszystkie pola nagłówka IP). Autorzy OMNeT++ nie zalecają jednak stosowania tego rozwiązania, gdyż posiada ono wiele wad. Po pierwsze wykorzystanie obiektu dość złożonej klasy cpar dla każdego parametru w znacznym stopniu zwiększa zapotrzebowanie symulacji na pamięć. Po drugie, przetwarzanie takich obciążonych komunikatów znacznie zmniejsza wydajność symulacji. Kolejnym możliwym rozwiązaniem jest utworzenie klas komunikatów w oparciu o klasę bazową cmessage. Poza uzyskaniem większej wydajności pamięciowej i obliczeniowej, mamy dodatkową kontrolę typów dla nowych atrybutów. Klasa cpar, przez swoją uniwersalność odnośnie różnych typów danych, które może przechowywać, takiej kontroli nie zapewnia. Samodzielne tworzenie nowych klas bezpośrednio jest możliwe, ale nie jest wskazane. Przyjęta konwencja wymaga określenie każdego pola jako prywatne i zdefiniowaniu odpowiednich akcesorów (metod get i set) 31 oraz zintegrować otrzymaną klasę ze środowiskiem symulacyjnym. Ważną cechą klas otrzymanych w ten sposób jest odzwierciedlanie informacji przenoszonych w takich komunikatach w środowisku uruchomieniowym Tkenv (Zob ), a więc z możliwością wizualnego podglądu symulacji. Jako alternatywę OMNeT++ oferuje wygodną metodę definiowania komunikatów 32 w specjalnym języku opisu 33 w plikach z rozszerzeniem.msg. Na podstawie tych plików generowany jest właściwy kod klas w C++. W tym celu należy skorzystać z programu napisanego w Perl o nazwie opp_msgc, będącego składnikiem pakietu OMNeT++. Jeśli nowa klasa komunikatów ma ograniczać się do dodania kilu pól, definicja jest bardzo prosta. Na przykład gdy chcemy zbudować klasę w której dodane zostaną pola adresu źródłowego, docelowego i pole TTL, definicja będzie następująca: 1 message MyIP 2 { 3 fields : 4 int srcaddress ; 5 int destaddress ; 6 int TTL = 255; 7 }; Po skompilowaniu pliku (załóżmy, że jego nazwa to simpleip.msg otrzymamy plik z deklaracją klasy MyIP o nazwie simpleip_m.h i plik definicji simpleip_m.cc. Plik mypacket_m.h musi zostać włączony do kodu C++ symulacji. Jego zawartość będzie zawierać m.in: 1 class MyIP : public cmessage { virtual int getsrcaddress () const ; 30 Obiekty tego typu są także wykorzystywane do obsługi parametrów modułów prostych, oraz w innych obiektach OMNeT Mechanizm ten, według twórców OMNeT++ nie przybrał jeszcze swojej ostatecznej formy i może ulegać pewnym zmianom. Podobnie kompilator plików msg napisany w języku Perl nie jest jeszcze docelową, ostateczną wersją. Brakuje częściowo funkcjonalności, m.in. wskaźniki jako pola klas nie są jeszcze obsługiwane (OMNeT++ wersja 3.2). 32 Tworzenie plików.msg nie ma na celu powielanie deklaracji klas w innym niż C++ języku. Rozwiązanie to dostarcza przede wszystkim interfejs dostępu do wszystkich atrybutów klasy, spójnego zarówno dla użytkownika jak i narzędzi symulatora (np. Tkenv). Interfejs ten obejmuje wiele aspektów, m.in. odwzorowanie symbolicznych nazw atrybutów w postaci łańcuchów znakowych. 33 Proszę zauważyć, że w nazwach metod po metod słowach get i set zawsze występuje duża litera. Jeśli identyfikator pola zaczyna się od małej litery i tak zostanie ona zamieniona w tym przypadku na dużą.

72 68 ROZDZIAŁ 2. PAKIET OMNET++ 4 virtual void setsrcaddress ( int srcaddress ); }; Jak widać, dostęp do utworzonych pól realizowany jest za pośrednictwem metod zaczynających się od set* i get*. Proszę zwrócić uwagę, że metody deklarowane są jako wirtualne, więc użytkownik ma możliwość przeciążania ich funkcjonalności. Po włączeniu pliku nagłówkowego do symulacji można już korzystać z nowej klasy komunikatów, np: 1 # include " simpleip_m.h" MyIP * pkt = new MyIP (" pkt "); 4 pkt - > setsrcaddress ( localaddr ); 5... Utworzona klasa posiada konstruktor z parametrami domyślnymi oraz kopiujący: MyIP(const char *name=null, int kind=0); MyIP(const MyIP& other); Jako że nowa klasa komunikatów dziedziczy po bazowej klasie cobject, zdefiniowany jest także operator przypisania (=) oraz metoda duplikująca komunikat dup()). Przy tworzeniu klas w ten sposób można korzystać z następujących typów pól: bool, char, unsigned char, short,unsigned short, int, unsigned int, long, unsigned long i double. Wartości zainicjalizowane są wartością zero (false dla bool). Można przypisywać wartości początkowe za pomocą operatora przypisania (=), jak w przykładzie powyżej dla pola TTL. Czasem wygodnie jest też zdefiniować określone pola jako wartości typu wyliczeniowego. Typ wyliczeniowy w plikach.msg definiujemy następująco: 1 enum TypProtokolu 2 { 3 IP = 1; 4 TCP = 2; 5 UDP = 3; 6 }; Można teraz skorzystać ze zdefiniowanego typu wyliczeniowego np: 6 message JakisPakiet 7 { 8 fields : 9 int Protokol enum ( TypProtokolu ); 10 }; Zaletą definiowania typów wyliczeniowych w plikach.msg jest to, że przy wykorzystaniu tych typów w polach klas podczas symulacji w trybie z wizualizacją (Tkenv) dostępne są także symboliczne nazwy poszczególnych wartości typu (automatycznie generowany jest w tym celu odpowiedni kod klasy). Można także deklarować tablice w polach klasy. Zasada jest intuicyjna: rozmiar wektora umieszczony jest w nawiasach kwadratowych ([rozmiar]), np: 1 message MojKomunikat 2 { 3 fields : 4 long tabela [4]; 5 };

73 2.5. KOMUNIKATY 69 Tym razem wygenerowane metody set... i get... uwzględniają indeks elementu, który należy podać jako parametr: virtual long gettable(unsigned index); virtual void settable(unsigned index, long value); Ciekawą możliwością jest deklarowanie wektorów w sposób dynamiczny (pozostawione same nawiasy kwadratowe ([]), bez rozmiaru), np: 1 message MojKomunikat 2 { 3 fields : 4 long tabela []; 5 }; Tym razem, poza metodami wymienionymi powyżej (dla tablicy o ustalonym rozmiarze) mamy jeszcze dwie: virtual unsigned gettablearraysize(); virtual void setroutetablesize(unsigned n); Pierwsza (gettablearraysize) zwraca aktualną wielkość tablicy. Druga (setroutetablesize) pozwala dynamicznie ustalić lub zmienić rozmiaru tablicy. Jeśli następuje zmiana na większy rozmiar dotychczasowe wartości są zachowywane (przepisywane w nowe miejsce w pamięci). Użytkownik ma więc do dyspozycji prostą, dynamiczną strukturę danych. Oczywiście nadużywanie metody zmieniającej rozmiar może przyczynić się do spadku wydajności symulacji (konieczna rezerwacja pamięci, kopiowanie). Zaawansowane możliwości definiowania klas komunikatów Opisana powyżej funkcjonalność jest wystarczająca do większości zastosowań. Możliwości jednak opisu klas w plikach.msg są znacznie większe. Obejmują definiowanie lub deklarowanie własnych klas i struktur, których obiekty mogą później stać się polami w klasie komunikatu. Możliwe jest definiowanie klas bazowych jako w pełni wirtualnych do dalszego wykorzystania i rozbudowy. Można także wbudowywać w klasy struktury dynamiczne bazujące na STL (np. vector). Do kodu klas można dodawać fragmenty w kodzie C++ (np. włączające pliki nagłówkowe z deklaracjami struktur do wykorzystania w klasach komunikatów). Opis tych możliwości wykracza poza ramy książki, wszystkie opisane są dokładniej w dokumentacji do symulatora OMNeT++ [OMN]. Kompilacja plików.msg Przed wykorzystaniem nowo zdefiniowanych komunikatów w symulacjach najpierw należy dokonać ich translacji, polegającej na utworzeniu plików w języku C++ (.h i.cpp) na podstawie plików.msg. Zgodnie z przyjętą konwencją do nazwy pliku.msg dodawany jest przyrostek _m. Na przykład na podstawie pliku mojkomunikat.msg powstają pliki mojkomunikat_m.h i mojkomunikat_m.cpp. Translację przeprowadza się za pomocą dołączonego skryptu o nazwie opp_msgc 34. Skrypt posiada szereg parametrów, których listę można uzyskać wywołując nazwę skryptu bez podania żadnych parametrów. Większość jednak parametrów ma ustalone wartości domyślne i dla większości zastosowań nie ma potrzeby ich zmiany. 34 Skrypt ten został napisany w języku Perl. Rozwiązanie to obowiązuje w wersji 3.2 pakietu OMNeT++. Autorzy zapowiadają, że docelowo translacja taka będzie realizowana przez kompilator języka NED (nedtool).

74 70 ROZDZIAŁ 2. PAKIET OMNET++ W najprostszym więc przypadku wywołanie skryptu polega na podaniu jako argumentu tylko nazwy odpowiedniego pliku.msg. W rezultacie otrzymamy dwa pliki źródłowe języka C++, które należy włączyć do właściwego projektu. 2.6 Parametry Parametry odgrywają ważna rolę przy tworzeniu uniwersalnego modelu. Parametryzować można topologię modelu, połączenia, liczbę bram. Określone parametry mogą być przypisane do modułów oraz do komunikatów. Parametrem może być wartość określonego typu, może to być także funkcja (np. rozkład prawdopodobieństwa przy wysyłaniu pakietów). W OMNeT++ wszystkie zagadnienia związane z parametrami obejmuje klasa cpar. Podczas tworzenia symulacji najczęściej korzysta się tylko z niektórych właściwości tej klasy: dostępu do parametrów modułów oraz dodawania parametrów do obiektów standardowej klasy komunikatów cmessage Dostęp do parametrów modułu Parametry modułu zdefiniowane są w języku NED. Każdy z nich posiada określony identyfikator, a jego wartość jest ustalona albo także w języku NED albo w pliku konfiguracyjnym. Na poziomie C++ dostęp do konkretnych parametrów można uzyskać wywołując metodę par() klasy cmodule, jako argument podając właściwy identyfikator, np: double czasobslugi = par("czasobslugi"); int wielkoscbufora = par("wielkoscbufora"); Można także bardziej ogólnie, pobrać referencję do obiektu typu cpar, np: cpar& delaypar = par("opoznienie"); Jeśli określony parametr został określony w języku NED jako funkcja, to każdorazowe odwołanie się do parametru zwróci wartość wynikającą z kolejnego wywołania funkcji (np. pseudolosowej), na przykład określając parametr w języku NED: 1 // plik Generator. ned 2 simple Generator 3 parameters : 4 odstepyczasu = exponential (1.0) ; 5 gates : 6 in: wejscie ; 7 out : wyjscie ; 8 //... W języku C++ można odwołać się następująco: 1 cpar & odstepyczasu = par (" odstepyczasu "); senddelayed ( pakiet, ( simtime_t ) waittime, " wyjscie "); 4... Możliwa jest także zmiana wartości parametrów. Można tego dokonać za pośrednictwem nazwy parametru: par("czasobslugi") = 0.5; Druga możliwość to wykorzystanie referencji do parametru, jak to było pokazane wcześniej. Przykładowo można zapisać: cpar& waittime = par("waittime");

75 2.7. IDENTYFIKACJA I DOSTĘP DO HIERARCHII MODUŁÓW 71 waittime = 0.12; 2.7 Identyfikacja i dostęp do hierarchii modułów W pewnych przypadkach (np. dostęp do parametrów innych modułów, bezpośrednie wysyłanie komunikatów, dynamiczne tworzenie i usuwanie modułów i połączeń czy budowa sieci o pseudolosowej topologii) przydatne jest uzyskanie informacji o topologii i hierarchii modelu bezpośrednio z poziomu modułów lub bezpośredni dostęp (wskaźnik) do innych modułów. Dostęp do poszczególnych modułów może być realizowany albo za pomocą wskaźników, albo identyfikatorów. Każdy moduł posiada swój unikalny identyfikator, który nie może się powtórzyć podczas symulacji, nawet jeśli moduł zostanie usunięty. Identyfikator bieżącego modułu uzyskujemy korzystając z metody id(): int mojidentyfikator = id(); Moduły proste są częścią modułów złożonych. Dostęp do pierwszego w hierarchii modułu złożonego (rodzica) uzyskać można za pomocą metody parentmodule() pisząc: cmodule *rodzic = parentmodule(); Dysponując wskaźnikiem do innego modułu, możemy też uzyskać jego identyfikator: int rodzicid = rodzic->id(); Operacją odwrotną jest uzyskanie dostępu do modułu składowego. Mamy do dyspozycji dwie metody: findsubmodule() oraz submodule(). Pierwsza zwraca identyfikator modułu składowego w oparciu o jego nazwę i indeks (jeśli moduł złożony składał się z więcej niż jednego modułu określonego typu) lub wartość -1 jeśli nie znaleziono określonego modułu, np: cmodule *rodzic = parentmodule(); int modulskladowyid = rodzic->findsubmodule("jakismodul", 5); Druga metoda zwraca wskaźnik do modułu i zwraca NULL, jeśli nie znaleziono modułu. Analogicznie mamy więc: cmodule *rodzic = parentmodule(); cmodule *submod = rodzic->submodule("jakismodul", 5); Oczywiście można także rozbudowywać podobne wyrażenia, dla uzyskania dostępu do bardziej zagnieżdżonych lub odległych modułów, np: parentmodule()->submodule("modulzlozonya",3)->submodule("modulskladowymodulua"); Przy okazji omawiania pliku konfiguracyjnego omnetpp.ini (patrz Konfiguracja) wprowadzone zostało pojęcie ścieżek bezwzględnych, które określają położenie określonego parametru w ramach modułu. Podobną hierarchię ścieżek bezwzględnych, określanych z poziomu najwyższego poziomu w hierarchii, można wykorzystać do określenia położenia konkretnego modułu. Łatwo jest uzyskać ścieżkę i nazwę bieżącego modułu lub dowolnego modułu, do którego posiadany jest wskaźnik. Użyteczne są dwie metody const char* fullname() i const char* fullpath(), kolejno do nazwy i do ścieżki bezwzględnej. Pewnym uzupełnieniem tych metod jest wymieniona wcześniej metoda int index() zwracająca numer indeksu modułu w wektorze, jeśli moduł składowy zawiera więcej niż jeden moduł danego typu 35. Do uzyskania dostępu do dowolnego modułu na podstawie ścieżki bezwzględnej należy wykorzystać metodę modulebypath(), która jest składową klasy csimulation, a w modułach dostępna jest za pomocą 35 metoda fullname() zwraca taką samą nazwę dla wszystkich modułów składających się na wektor.

76 72 ROZDZIAŁ 2. PAKIET OMNET++ globalnego obiektu simulation, np: cmodule modul = simulation->modulebypath(calasiec.modulzlozonya.modulzlozonyb[4].modulskladowy[3]); Druga możliwość, znacznie częściej wykorzystywana w praktyce, to zastosowanie ścieżek względnych (względem bieżącego modułu). W tym celu należy zastosować metodę modulebyrelativepath(). Na przykład jedno z poprzednich wyrażeń można zapisać jako: parentmodule()->modulebyrelativepath("modulzlozonya[3].modulskladowymodulua"); Warto zauważyć, że przy budowaniu złożonych instrukcji, powodujących przejście przez więcej niż jeden moduł w hierarchii, kolejne moduły muszą istnieć, gdyż w przeciwnym wypadku wystąpi błąd programu (próba uzyskania dostępu do metod nieistniejącego obiektu). OMNeT++ zawiera także inny mechanizm, pozwalający na wygodny dostęp do modułów w hierarchii. Jest to iterator, obiekt który tworzy się w oparciu o klasę csubmoditerator. Tworząc iterator przekazujemy jako argument konstruktora obiekt określonego modułu złożonego (uzyskany np. za pomocą wskaźnika), a następnie w pętli uzyskujemy dostęp do wszystkich jego modułów składowych. Przykład zastosowania tego mechanizmu może być następujący: 1 for ( csubmoditerator iteratorparentmodule());!iterator.end(); iterator++) ev << "Nazwa: " << iterator()->fullname() << "Index:" iterator()->index(); Ostatnią możliwością jest śledzenie połączeń pomiędzy modułami i sprawdzanie osiągalnych w ten sposób modułów. Dla bram wejściowych wywołuje się wówczas metodę fromgate(), a dla bram wyjściowych togate(). W ten sposób otrzymamy wskaźnik bramy docelowej w sąsiednim module. Następnie wystarczy uzyskać wskaźnik właściwego modułu, korzystając z metody ownermodule(). Tak więc dla bram wyjściowych można przykładowo zapisać: cmodule *sasiednimodul = gate( "wyjscie" )->togate()->ownermodule(); Dla bram wejściowych zapiszemy: cmodule *sasiednimodul = gate( "wejscie" )->fromgate()->ownermodule(); 2.8 Zbieranie i przetwarzanie wyników symulacji Najczęściej celem symulacji jest zebranie pewnych wyników, odzwierciedlających zachowanie modelu w postaci pewnych statystyk, wykresów histogramów itp. Pakiet OMNeT++ posiada wbudowane odpowiednie narzędzia, zarówno do zbierania informacji, jak i do analizy uzyskanych wyników. Podczas symulacji można gromadzić informacje o przebiegu symulacji w postaci wektorów wyjściowych (output vectors) oraz skalarów wyjściowych (output scalar). Informacje te zapisywane są w odpowiednich plikach wyjściowych (z rozszerzeniem.sca dla informacji skalarnych i.vec dla informacji wektorowych). Do zapisu informacji w jednym pliku może być wykorzystanych jednocześnie wiele badanych parametrów. Pliki wynikowe można następnie analizować w dostarczanym razem z pakietem OMNeT++ programie Plove). Do gromadzenia danych i obliczania podstawowych wielkości statystycznych służą odpowiednie klasy: coutvector dla zapisu parametrów w postaci wektorów (zależnych od czasu), do tworzenie różnego rodzaju wykresów oraz zbiór klas do zbierania różnego rodzaju statystyk, opartych na bazowej klasie cstatistic. W zależności od wybranej klasy statystyki te mają wiele ciekawych właściwości, np. mogą służyć do generowania liczb pseudolosowych w oparciu o zebrane informacje (rozkłady). W dalszej części dokładniej opisano wymienione możliwości gromadzenia i przetwarzania wyników symulacji Klasa wektorów coutvector Informacje w postaci wektorów wyjściowych można wykorzystywać np. do zapisu wszelkiego rodzaju wartości zależnych od czasu, np. długości kolejek, liczby aktywnych połączeń, liczby odrzuconych

77 2.8. ZBIERANIE I PRZETWARZANIE WYNIKÓW SYMULACJI 73 pakietów itp. Do obsługi wektorów wyjściowych wykorzystywana jest klasa coutvector. Jako parametr konstruktora podaje się symboliczną nazwę dla parametru, który chcemy analizować: coutvector czasodpowiedzi("czas odpowiedzi"); lub: coutvector czasodpowiedzi; w drugim przypadku warto pamiętać o nadaniu obiektowi nazwy za pomocą metody setname(), np; czasodpowiedzi.setname("czas odpowiedzi"); Obiekty tej klasy deklaruje się jako atrybuty klasy określonego modułu prostego, w którym chcemy mierzyć lub rejestrować parametr. Korzystanie z klasy wektorów w najprostszym przypadku ogranicza się do wykonania kolejnych metod record(parametr) (zapisuje kolejny parametr o nazwie określonej przy utworzeniu wektora w pliku wyjściowym, domyślnie jest to omnetpp.vec). Na przykład (utworzenie obiektu wektora i rejestracja kolejnych czasów życia nadchodzących do modułu komunikatów): 1 class ModulProsty : public csimplemodule 2 { 3 coutvector czaszyciapakietow ; virtual void initialize (); 6 virtual void handlemessage ( cmessage * msg ); 7 virtual void ( finish ); } 11 Define_Module ( Node ); 13 void ModulProsty :: initialize () 14 { 15 czaszyciapakietow. setname (" czas odpowiedzi "); } 19 void ModulProsty :: handlemessage ( cmessage * msg ) 20 { 21 simtime_ t czaszycia = simtime () - msg - > creationtime (); 22 czaszyciapakietow. record ( czaszycia ); delete msg ; 25 } Warto zwrócić uwagę na istotną rolę, jaką pełni nazwa obiektu wektora w postaci łańcucha znaków. Jak wiemy, każdy obiekt symulacji posiada taką indywidualną nazwę. Na zewnątrz kodu symulacji obiekty rozpoznawane są właśnie po tych nazwach, m.in. podczas wizualizacji w oknie środowiska Tkenv czy poprzez nazwy parametrów w pliku omnetpp.ini. W przypadku wektora wynikowego dzięki tej nazwie można w pliku konfiguracyjnym wpływać na proces rejestracji wyników na dysku. Konfiguracja wektorów wynikowych Wyniki, które są zbierane podczas symulacji w postaci wektorów wyjściowych, zapisywane są w plikach z rozszerzeniem.vec. W bardziej złożonych symulacjach, gdy istnieje potrzeba zbierania informacji dla dużej liczby różnych parametrów, rozmiar plików wynikowych znacząco rośnie i może osiągać wielkość

78 74 ROZDZIAŁ 2. PAKIET OMNET++ liczoną w setkach megabajtów. OMNeT++ pozwala na kontrolę zapisu tych wyników w plikach, poprzez odpowiednią konfigurację. Szczegóły wykorzystania wektorów wejściowych ustalane są w pliku omnetpp.ini w sekcji [outvectors]. Domyślnie prowadzona jest rejestracja wszystkich parametrów podczas całego zakresu czasu symulacji. Odwołanie do poszczególnych obiektów plików wynikowych następuje przez podanie ścieżki dostępu do obiektu w ramach hierarchii obiektów oraz indywidualnej nazwy obiektu wektora. Z poziomu pliku konfiguracyjnego omnetpp.ini dysponujemy następującymi możliwościami: sciezka_dostepu.nazwa_obiektu_wektora.enabled = yes/no włącza lub wyłącza rejestrowanie parametru związanego z danym obiektem wektora; sciezka_dostepu.nazwa_obiektu_wektora.interval = start..stop sciezka_dostepu.nazwa_obiektu_wektora.interval =..stop sciezka_dostepu.nazwa_obiektu_wektora.interval = start.. ustala zakres czasowy czasu symulacji, w którym rejestrowane będą wyniki parametru związanego z danym obiektem wektora. Podobnie jak w przypadku parametrów, przy określaniu nazwy i ścieżki dostępu można stosować znaki uniwersalne typu * czy ** Klasa statystyk cstatistic Poprzednio opisaną klasę wektorów wykorzystuje się do zapisu zależności określonych parametrów od czasu. Czasami występuje także potrzeba zapisywania podczas symulacji wartości pewnych pojedynczych parametrów, które nie muszą być zależne od czasu symulacji (np. liczba przetworzonych przez moduł łącznie zadań obliczona pod koniec symulacji). Zapis pojedynczej wartości parametru o określonej nazwie może być wykonana wykorzystując metodę recordscalar(nazwa, parametr), która jest metodą klasy modułów prostych csimplemodule, np: 1 void ModulProsty :: finish () 2 { 3 recordscalar (" Odebranych komunikatow ", liczbakomunikatow ); 4 } Pełniejsze możliwości można uzyskać wykorzystując obiekty będące pochodnymi klasy cstatistic. Pozwalają one na obliczanie różnych dodatkowych danych statystycznych dla rejestrowanych parametrów. Dostępne są następujące klasy pochodne: cstddev, najczęściej wykorzystywana klasa, przechowująca poszczególne wartości parametru, obliczająca wartość średnią, odchylenie standartowe, minimum, maksimum itp., cweightedstddev, podobnie jak poprzednia, jednak akcpetuje także próbki ważone, clonghistogram i cdoublehistogram,poza właściwościami identycznymi jak dla klasy cstddev szereguje próbki w postaci histogramu w stałych przedziałach o jednakowej szerokości, cvarhistogram, podobnie jak poprzednia, jednak przedziały mogą mieć różną szerokość, cpsquare, klasa oblicza kwantyle próbek zgodnie z metodą P 2, cksplit, klasa w oparciu o nową, eksperymentalną metodę adaptacyjnego doboru parametrów histogramu.

79 2.8. ZBIERANIE I PRZETWARZANIE WYNIKÓW SYMULACJI 75 Aby skorzystać z możliwości oferowanych przez wszystkie wymienione klasy należy zadeklarować obiekt danej klasy i odpowiednio dodawać kolejne próbki za pomocą metody collect(). Można także skorzystać z przeciążonego operatora +=. Podstawową klasą w tej grupie jest cstddev. Po zebraniu odpowiedniej liczby próbek można skorzystać z podstawowych metod obliczających parametry statystyczna, takie jak: samples() - liczba zebranych próbek, min(), max(), mean() - odpowiednio, wartość największa, najmniejsza oraz średnia, stddev(), variance() - odpowiednio, odchylenie standardowe i wariancja, sum(), sqrsum() - odpowiednio, suma wartości zebranych próbek oraz pierwiastek kwadratowy tej sumy. Korzystając z tych metod można np. wypisać odpowiedni raport w oknie komunikatów, np: 1 class ModulProsty : public csimplemodule 2 { 3 cstddev stat ; } 7 Define_Module ( Node ); 9 void ModulProsty :: initialize () 10 { 11 cstddev stat (" mojastatystyka "); } 15 void ModulProsty :: handlemessage ( cmessage * msg ) 16 { 17 stat. collect (msg -> par (" badanyparametr ")); } 21 void ModulProsty :: finish () 22 { 23 ev << " Liczba probek - >" << stat. samples (); 24 ev << " Wartosc minimalna - >" << stat. min (); 25 ev << " Wartosc maksymalna - >" << stat. max (); 26 ev << " Wariancja - >" << stat. variance (); 27 ev << " Odchylenie standardowe - >" << stat. stddev (); 28 } Wykorzystanie klas zbierających dane w postaci histogramów daje, poza wymienionymi, dodatkowe możliwości. Dokładne omówienie tego zagadnienia wykracza jednak poza zakres niniejszej książki. Opis tych klas można znaleźć m.in. w instrukcji obsługi [OMN]. Poniżej zaprezentowano prosty przykład, w którym tworzony jest obiekt histogramu, w metodzie handlemessage() dodawane są próbki, a w metodzie finish() badane są przedziały histogramu: 1 void ModulProsty :: initialize () 2 { 3 // 10 przedziałów histogramu, dobór szerokości automatyczny :

80 76 ROZDZIAŁ 2. PAKIET OMNET++ 4 cdoublehistogram histogram (" histogram ", 10) ; 5 // podział na zakresy zostanie dokonany po zebraniu pierwszych 100 próbek 6 // podział może się zmienic ( rozszerzyć ) jeśli wartości w dodatkowych 7 // próbkach przekroczą ustalony zakres o 1.5: 8 histogram. setrangeauto (100,1.5) ; } 12 void ModulProsty :: handlemessage ( cmessage * msg ) 13 { 14 stat. collect (msg -> par (" badanyparametr ")); } 18 void ModulProsty :: finish () 19 { 20 long n = histogram. samples (); 21 // liczbę ustalonych przedziałów zwraca metoda cells (): 22 for ( int i =0; i< histogram. cells (); i ++) 23 { 24 // granicę przedziału i zwraca metoda besepoint ( i) 25 double szerokoscprzedzialu = histogram. basepoint ( i +1) - histogram. basepoint (i); 26 // metoda cell ( i) zwraca liczbę próbek w przedziale i: 27 int count = histogram. cell ( i); 28 // } 30 } Kontrola parametrów w oknie środowiska TkEnv W oknie środowiska graficznego mamy dostęp do parametrów wszystkich zarejestrowanych obiektów opartych na cobject. Czasami jednak przydatny jest dostęp także do innych parametrów modułu, które są przechowywane np. jako wartości typów podstawowych (int, long, double). OMNeT++ dostarcza jednak dodatkowe makro o nazwie WATCH(), które pozwala w prosty sposób rozwiązać ten problem. Makro to może zostać wywołane dla zmiennych będących atrybutami klasy (np. w ramach metody initialize(), a także dla zmiennych dynamicznych (w ramach metody handlemessage(). Może zostać wywołane dla zmiennych,a także pól struktur czy atrybutów innych klas 36, np: 1 long liczbapakietow ; 2 WATCH ( liczbapakietow ); 3 double czasoczekiwania ; 4 WATCH ( czasoczekiwania ); WATCH ( konfiguracja. liczbaodbiorcow ); Ciekawe jest, że to makro pozwala także na interaktywną zmianę wartości parametrów (zmiennych) z poziomu okna środowiska graficznego Ściślej, makro WATCH() może zostać wywołane dla każdej zmiennej, dla której zdefiniowano operator <<, czyli takich, które mogą być wykorzystane przy operacjach na strumieniu wyjściowym. Można także zdefiniować lub redefiniować ten operator dla własnych typów, co pozwoli na odpowiednie interpretowanie wartości danej zmiennej w oknie graficznym.

81 2.9. WEWNĘTRZNE STRUKTURY DANYCH: LISTY, KOLEJKI OMNeT++ pozwala także na podgląd całych struktur dynamicznych, opartych na popularnej bibliotece STL (ang. Standard Template Library), np. klasy vector). Wykorzystuje się do tego zbiór dodatkowych makr. Dokładniejsze informacje znajdują się w instrukcji obsługi [OMN]. 2.9 Wewnętrzne struktury danych: listy, kolejki... Przy tworzeniu modeli symulacyjnych sieci kolejkowych istotną rolę odgrywa odpowiednie i wygodne odzwierciedlenie takich elementów jak kolejki i bufory. OMNeT++ także i w tym przypadku dostarcza odpowiednich klas, tzw. kontenerów: cqueue dla kolejek i carray dla tablic i bardziej złożonych mechanizmów przechowywania obiektów. W modelach symulacyjnych najczęściej w kontenerach przechowywane są obiekty komunikatów. Oczywiście nie jest to jedyna możliwość, a sam OMNeT++ często wykorzystuje kontenery do wewnętrznych zastosowań (np. każdy komunikat posiada kontener carray do przechowywania parametrów) Kolejki Klasa cqueue jest kontenerem zachowującym się jak kolejka. Z punktu widzenia wewnętrznej implementacji jest to lista dynamiczna dwukierunkowa. Dwa elementy kolejki są wyróżnione: początek (head) i koniec (tail). Podstawowe operacje obejmują dodawanie elementów na końcu kolejki i pobieranie elementów na początku kolejki. Operacjom tym odpowiadają diw podstawowe metody klasy: insert() dla operacji umieszczania elementów na końcu i pop() dla operacji pobierania z początku kolejki. Metoda pop() zwraca wskaźnik na przechowywany obiekt, typu cobject. Aby uzyskać obiekt właściwego typu konieczne jest odpowiednie rzutowanie. Metoda empty() zwraca true jeśli kolejka jest pusta (nie ma żadnych elementów). Sekwencja prostych, podstawowych operacji może być przykładowo następująca: 1 cqueue queue ("my - queue "); 2 // utworzenie 10 komunikatów i wstawienie do kolejki 3 cmessage * komunikat ; 4 for ( int i =0; i <10; i ++) 5 { 6 komunikat = new cmessage ; 7 queue. insert ( komunikat ); 8 } // usuwanie komunikatów 11 while (! queue. empty () ) 12 { 13 komunikat = ( cmessage *) queue. pop (); 14 delete komunikat ; 15 } Na początku tworzymy 10 komunikatów, następnie w pętli usuwamy komunikaty z kolejki (tak długo, dopóki znajdują się w niej jeszcze jakieś elementy) Tablice Tablice dynamiczne, będące wygodnymi kontenerami dla wszelkich obiektów symulacji (pochodzących od klasy cobject) reprezentuje klasa carray. Oczywiście carray także pochodzi od klasy bazowej cobject. 37 W tym wypadku wykorzystywany jest operator >>, który może być przeciążany.

82 78 ROZDZIAŁ 2. PAKIET OMNET++ Klasa ta (podobnie jak poprzednio opisywana klasa kolejek cqueue) w rzeczywistości przechowuje wskaźniki obiektów, o czym trzeba pamiętać podczas tworzenia i usuwania obiektów symulacji. Jej rozmiar zmienia się dynamicznie, w miarę wzrostu liczby obiektów 38. Najważniejsze metody obsługujące tę klasę to add(), dodająca nowy element, find(), zwracająca indeks szukanego elementu oraz remove(), zwracająca indeks szukanego elementu z jednoczesnym usunięciem go z tablicy. Poza tym klasa obsługuje operator indeksowania [ ], pozwalając odczytywać elementy klasy analogicznie jak w przypadku tradycyjnych, statycznych tablic. Poniżej zaprezentowano przykłady wykorzystania tej klasy dla podstawowych operacji. Utworzenie obiektu klasy carray oraz nadanie mu nazwy: carray mojatabl("mojatablica"); Dodanie elementu (jest nim obiekt parametrów, klasy cpar) oraz zapamiętanie indeksu wstawionego elementu: cpar *p = new cpar("mojparametr"); int index = mojatabl.add( p ); Operację wstawiana można także przeprowadzić podając pozycję (indeks) w tablicy. Jeśli jednak wskazana pozycja jest zajęta, rezultatem będzie komunikat o błędzie: int index2 = mojatabl.addat(5,p); Pobieranie wskaźników do elementów w tablicy można zrealizować wykorzystując operator indeksowania, i wykonując rzutowanie na właściwy typ, np.: cpar *p = (cpar *) mojatabl[index]; //wskaźnik na obiekt dalej pozostaje w tablicy! Aby uzyskać wskaźnik elementu należy najpierw ustalić jego indeks metodą find(). Można go ustalić albo przez inny wskaźnik na ten obiekt: int index = mojatabl.find(p); albo przez nazwę obiektu (właściwość klasy cobject): int index = mojatabl.find("par"); Obiekty można usuwać z tablicy na określając albo ich nazwę, albo konkretną pozycję, albo podając wskaźnik na element do usunięcia, np: mojatabl.remove("par"); mojatabl.remove(index); mojatabl.remove( p ); Należy pamiętać, że metoda ta usuwa jedynie wskaźnik na obiekt, ale nie usuwa samego obiektu. Można wykorzystać właściwość, że metoda zwraca wskaźnik na obiekt i zapisać np.: cpar *p = (cpar *) delete mojatabl.remove( index ); Można także od razu usunąć obiekt z tablicy i z pamięci, np.: delete mojatabl.remove( index ); Czasami przydatna jest możliwość wykonania określonych operacji na wszystkich elementach w strukturze tablicy. Do przeprowadzania operacji na wszystkich elementach tablicy (np. w pętlach) przydatna jest metoda items(), zwracająca liczbę indeksów w tablicy (o 1 większa niż maksymalny indeks, bo indeksy numerowane są o zera). Należy pamiętać, że ze względu na sposób implementacji klasy carray nie wszystkie pozycje muszą być zajęte. Pętla więc iteruje po wszystkich możliwych indeksach. Dla 38 W rzeczywistości implementacja jest następująca: tablica ma ustalony rozmiar, a gdy dodawany jest kolejny obiekt, wykraczający poza ten rozmiar, tablica alokuje nowy, większy obszar pamięci i przenosi do niego wskaźniki obiektów składowych.

83 2.10. GENERATORY LICZB LOSOWYCH 79 każdej pozycji niezbędne jest zbadanie, czy dana pozycja jest zajęta (wskaźnik różny od NULL), np. (dla tablicy carray o identyfikatorze mojatabl) : 1 for ( int i =0; i< mojatabl. items (); i ++) 2 { 3 if ( mojatabl [i]) //!= NULL? 4 { 5 cobject * obj = mojatabl [ i]; 6 ev << " Poz.:" << i << " nazwa :" << obj - > name () << endl ; 7 } 2.10 Generatory liczb losowych Biblioteka symulacyjna OMNeT++ oferuje dwie podstawowe funkcje, zwracające wartości pseudolosowe w oparciu o szybki generator o bardzo długim cyklu. Są to: intrand(n) - zwracająca wartość typu int z zakresu [0, n - 1] dblrand() - zwracająca wartość typu double z zakresu [0, 1). Aby na przykład zamodelować rzut kostką można napisać: int kostka = 1 + intrand(6); Biblioteka dostarcza także szerokiego zestawu funkcji zwracających wartości pseudolosowe zgodnie z określonymi rozkładami. Funkcje ciągłe oparte są na funkcji dblrand() a dyskretne na intrand(). Są to odpowiednio: Rozkłady ciągłe: uniform(a, b, rng=0) - rozkład równomierny w zakresie [a,b), exponential(mean, rng=0) - rozkład wykładniczy o wartości średniej mean, normal(mean, stddev, rng=0) - rozkład normalny o wartości średniej mean i odchyleniu stddev, truncnormal(mean, stddev, rng=0) - rozkład normalny, ograniczony do wartości dodatnich, gamma_d(alpha, beta, rng=0) - rozkład gamma o parametrach rozkładu alpha>0 i beta>0, beta(alpha1, alpha2, rng=0) - rozkład beta o parametrach rozkładu alpha1>0 i alpha2>0, erlang_k(k, mean, rng=0) - rozkład Erlanga z fazą k i o określonej średniej mean, chi_square(k, rng=0) - rozkład chi o k stopniach swobody, student_t(i, rng=0) - rozkład t-studenta o k stopniach swobody, cauchy(a, b, rng=0) - rozkład Cauchy ego o parametrach a i b, triang(a, b, c, rng=0) - rozkład trójkątny o parametrach a<=b<=c, a!=c, lognormal(m, s, rng=0) - rozkład logarytmiczno-normalny o wartości średniej mean i wariancji s>0, weibull(a, b, rng=0) - rozkład weibull a o parametrach a>0 i b>0, pareto_shifted(a, b, c, rng=0) przesunięty rozkład Pareto o parametrach a i b i przesunięciu c.

84 80 ROZDZIAŁ 2. PAKIET OMNET++ Rozkłady dyskretne: intuniform(a, b, rng=0) - rozkład dyskretny równomierny w zakresie [a..b]; bernoulli(p, rng=0) - rozkład Bernaulli ego z prawdopodobieństwem 0<=p<=1 w każdej próbie, daje 1 z prawdopodobieństwem p i 0 z prawdopodobieństwem (1-p)); geometric(p, rng=0) - rozkład geometryczny z parametrem 0<=p<=1; binomial(n, p, rng=0) - rozkład dwumianowy, o parametrze n>=0 i parametrze 0<=p<=1; negbinomial(n, p, rng=0) - rozkład dwumianowy zanegowany, o parametrze n>=0 i parametrze 0<=p<=1; poisson(lambda, rng=0) - rozkład Poisson a z parametrem lambda; Przydatna jest możliwość korzystania z tych funkcji do określania parametrów w plikach.ned, a także do ustalania wartości tych parametrów w pliku konfiguracyjnym omnetpp.ini. Jest to szczególnie przydatne, gdy chcemy w różnych konfiguracjach symulacji zadawać różne rozkłady np. dla generatorów ruchu. Poza wymienionymi funkcjami użytkownik może dodawać własne, rejestrując je w pakiecie OMNeT++, a następnie wykorzystując tak, jak pozostałe, predefiniowane funkcje. Zastosowanie to nie ogranicza się do funkcji pseudolosowych, można dodawać dowolne funkcje, np. matematyczne. Przydatną możliwością jest generowanie wartości losowych na podstawie rozkładu wartości zgromadzonych przez zbór klas histogramów (patrz ). Po zebraniu dostatecznej liczby próbek można wywołać na obiekcie histogramu metodę random() zwracającą wartość pseudolosową zgodną z rozkładem wartości histogramu Biblioteka klas OMNeT++ Czytelnik, po zapoznaniu się z materiałem zawartym w rozdziale powinien mieć już orientację wśród klas, składających się na bibliotekę symulacyjną. Większość najczęściej wykorzystywanych klas została przedstawiona, a tworzenie obiektów tych klas i podstawowe metody zostały opisane. W przypadku jednak opracowywania większych, bardziej złożonych modeli konieczna jest dokładniejsza wiedza na temat hierarchicznej struktury klas całej biblioteki. Określone klasy bazowe pełnią ważną rolę, uogólniając pewne zagadnienia dla całej rodziny klas pochodnych. Aby korzystać z biblioteki symulacyjnej konieczne jest zawsze włączenie pliku nagłówkowego: #include <omnetpp.h>. Klasą bazową dla niemal wszystkich klas OMNeT++ jest cpolymorphic, jednak znacznie ważniejszą rolę z praktycznego punktu widzenia pełni kolejna w hierarchii klasa cobject. Ma ona podstawowe znaczenie dla implementacji większości mechanizmów symulacji. Definiuje między innymi takie elementy jak: nazwa obiektu, atrybut name, który jest łańcuchem znaków szeroko wykorzystywanym do identyfikacji obiektów (np. nazwy parametrów, nazwy obiektów w kontenerach, nazwy w hierarchii ścieżek w ramach modelu itp), z dostępnymi metodami setname(nazwa) i name(); nazwa klasy, do której dostęp można uzyskać za pomocą metody classname(), która jest łańcuchem znaków będącym nazwą klasy, do której należy obiekt; mechanizmy kopiowania i duplikacji obiektów (kopiowanie związane jest z przekazaniem własności obiektu i wykorzystuje przeciążony operator przypisania=, duplikowanie obiektu odbywa się w oparciu o metodę dup()) ;

85 2.12. KOMPILACJA I TWORZENIE BIBLIOTEK SYMULACYJNYCH 81 mechanizm kontroli własności obiektów (patrz Duplikowanie komunikatów); mechanizm kontroli i podglądu obiektów z poziomu środowiska graficznego Tkenv; mechanizm serializacji, niezbędny przy rozproszonym uruchamianiu symulacji. W większości przypadków, tworząc własne klasy, warto pośrednio lub bezpośrednio budować je w oparciu o klasę bazową cobject. Tworząc nową klasę należy pamiętać o włączeniu jej do struktury OMNeT++ poprzez rejestrację za pomocą makra Register_Class(NowaKlasa). Dokładny opis biblioteki symulacyjnej znacznie wykracza poza zakres tej książki. Wiele szczegółowych informacji na temat klas i ich metod zostało pominiętych także w instrukcji obsługi [OMN]. Najlepszym źródłem informacji pozostaje bardzo dobrze opracowany interfejs programowy aplikacji (API - ang. Application Programming Interface), który jest dostępny zarówno na stronie domowej OMNeT++ jak też w katalogu Documentation każdej pełnej instalacji OMNeT Kompilacja i tworzenie bibliotek symulacyjnych Warto uporządkować wiadomości dotyczące procesu kompilacji, tworzenia bibliotek symulacyjnych i uruchamiania symulacji. Procesy te można przeprowadzać na kilka różnych sposobów, w zależności od potrzeb, przeznaczenia symulacji i zakresu modyfikacji, które chce przeprowadzić użytkownik. Można wyróżnić trzy podstawowe przypadki (lista wariantów może być szersza): modyfikacja parametrów i topologii modelu, bez potrzeby kompilacji kodu źródłowego w języku C++ (zakładające, że istnieje odpowiedni kod wykonywalny); przygotowanie symulacji od podstaw, od poziomu topologii do implementacji aktywności modułów prostych w C++; przygotowanie biblioteki modułów, które mogą być później wykorzystane w innych symulacjach; Czytelnik zapewne orientuje się już, że pliki źródłowe symulacji obejmują opis topologii w języku NED, definicje komunikatów w plikach z rozszerzeniem *.msg (jeśli występują) oraz implementacje modułów prostych w postaci pliku lub plików w języku C++. Proces tworzenia i uruchamiania symulacji jest przedstawiony schematycznie na Rys Poszczególne kroki związane z kompilacją plików źródłowych różnią się, w zależności od wybranego przez użytkownika systemu operacyjnego i środowiska programistycznego, ale ogólna zasada pozostaje taka sama. Pierwszym krokiem jest przekształcenie plików *.msg do postaci odpowiednich klas w języku C++. Procedura ta jest realizowana z wykorzystaniem programu opp_msgc (Zob ). Następnie można zdecydować się na jedną z dwóch możliwości, związanych z przetwarzaniem plików w NED. Pierwsza to przekształcenia ich do postaci kodów źródłowych w języku C++. Należy w tym celu skorzystać z programu translatora o nazwie nedtool. Otrzymane kody źródłowe otrzymują nazwę odpowiadającą nazwie modułu z przyrostkiem _n. Na przykład wywołanie: nedtool modul.ned przekształca plik modul.ned do postaci źródłowej C++ o nazwie modul_n.cc. Tak przekształcone pliki pozwalają wówczas utworzyć plik wynikowy, który przy uruchamianiu symulacji potrzebuje jedynie pliku konfiguracyjnego, nie są mu natomiast potrzebne pliki NED. Ograniczeniem tego rozwiązania jest brak

86 82 ROZDZIAŁ 2. PAKIET OMNET++ Rysunek 2.17: Proces tworzenia i uruchamiania symulacji. możliwości modyfikacji topologii modelu (zmiana topologii pociąga za sobą konieczność ponownej translacji programem nedtool oraz kompilacji wszystkich plików źródłowych do postaci pliku wykonywalnego symulacji). Drugą możliwością, która jest obecnie zalecana 39 jest dynamiczne dołączanie plików w języku NED. Wówczas nie należy już przekształcać plików NED do postaci źródłowej, zamiast tego pliki NED stają się integralnym elementem plików wykonywalnych. Aby skorzystać z tej możliwości w pliku konfiguracyjnym omnetpp.ini w sekcji General należy umieścić linię: preload-ned-files = *.ned topologie/*.ned W linii tej należy wskazać konkretne pliki lub grupy plików wraz z ich lokalizacjami. Należy podkreślić zalety takiego rozwiązania. W każdej chwili można zmodyfikować topologię modelu i przeprowadzić symulację bez konieczności ponownej, uciążliwej kompilacji. W ten sposób tworzone są też często biblioteki modułów i protokołów (np. pakiet INET), gdzie główny plik wykonywalny zawiera skompilowane wersje wszystkich modułów, jednak opis tych modułów na poziomie topologii zawarty jest w wielu poszczególnych plikach NED, reprezentujących moduły proste, następnie moduły złożone odpowiadają elementom funkcjonalnym (routery, przełączniki itp) a także przykładowe symulacje także 39 Od wersji 4.x OMNeT++ nie ma już możliwości uruchamiania symulacji bez plików NED.

Lekcja 1. Środowisko OMNeT++

Lekcja 1. Środowisko OMNeT++ Lekcja 1. Środowisko OMNeT++ W przygotowanym materiale zostanie omówione środowisko OMNeT++, pokazane zostanie, w jaki sposób tworzyć modele topologii. Język topologii NED Model OMNeT ++ składa się z hierarchicznie

Bardziej szczegółowo

Uniwersytet Mikołaja Kopernika w Toruniu. Profilowanie ruchu sieciowego w systemie GNU/Linux

Uniwersytet Mikołaja Kopernika w Toruniu. Profilowanie ruchu sieciowego w systemie GNU/Linux Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Michał Ferliński Nr albumu: 187386 Praca magisterska na kierunku Informatyka

Bardziej szczegółowo

ZMODYFIKOWANY Szczegółowy opis przedmiotu zamówienia

ZMODYFIKOWANY Szczegółowy opis przedmiotu zamówienia ZP/ITS/11/2012 Załącznik nr 1a do SIWZ ZMODYFIKOWANY Szczegółowy opis przedmiotu zamówienia Przedmiotem zamówienia jest: Przygotowanie zajęć dydaktycznych w postaci kursów e-learningowych przeznaczonych

Bardziej szczegółowo

Komputerowe Systemy Przemysłowe: Modelowanie - UML. Arkadiusz Banasik arkadiusz.banasik@polsl.pl

Komputerowe Systemy Przemysłowe: Modelowanie - UML. Arkadiusz Banasik arkadiusz.banasik@polsl.pl Komputerowe Systemy Przemysłowe: Modelowanie - UML Arkadiusz Banasik arkadiusz.banasik@polsl.pl Plan prezentacji Wprowadzenie UML Diagram przypadków użycia Diagram klas Podsumowanie Wprowadzenie Języki

Bardziej szczegółowo

Spis treści. Analiza i modelowanie_nowicki, Chomiak_Księga1.indb :03:08

Spis treści. Analiza i modelowanie_nowicki, Chomiak_Księga1.indb :03:08 Spis treści Wstęp.............................................................. 7 Część I Podstawy analizy i modelowania systemów 1. Charakterystyka systemów informacyjnych....................... 13 1.1.

Bardziej szczegółowo

Efekt kształcenia. Ma uporządkowaną, podbudowaną teoretycznie wiedzę ogólną w zakresie algorytmów i ich złożoności obliczeniowej.

Efekt kształcenia. Ma uporządkowaną, podbudowaną teoretycznie wiedzę ogólną w zakresie algorytmów i ich złożoności obliczeniowej. Efekty dla studiów pierwszego stopnia profil ogólnoakademicki na kierunku Informatyka w języku polskim i w języku angielskim (Computer Science) na Wydziale Matematyki i Nauk Informacyjnych, gdzie: * Odniesienie-

Bardziej szczegółowo

INFORMATYKA, TECHNOLOGIA INFORMACYJNA ORAZ INFORMATYKA W LOGISTYCE

INFORMATYKA, TECHNOLOGIA INFORMACYJNA ORAZ INFORMATYKA W LOGISTYCE Studia podyplomowe dla nauczycieli INFORMATYKA, TECHNOLOGIA INFORMACYJNA ORAZ INFORMATYKA W LOGISTYCE Przedmiot JĘZYKI PROGRAMOWANIA DEFINICJE I PODSTAWOWE POJĘCIA Autor mgr Sławomir Ciernicki 1/7 Aby

Bardziej szczegółowo

Międzyplatformowy interfejs systemu FOLANessus wykonany przy użyciu biblioteki Qt4

Międzyplatformowy interfejs systemu FOLANessus wykonany przy użyciu biblioteki Qt4 Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Agnieszka Holka Nr albumu: 187396 Praca magisterska na kierunku Informatyka

Bardziej szczegółowo

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Program, to lista poleceń zapisana w jednym języku programowania zgodnie z obowiązującymi w nim zasadami. Celem programu jest przetwarzanie

Bardziej szczegółowo

Teraz bajty. Informatyka dla szkół ponadpodstawowych. Zakres rozszerzony. Część 1.

Teraz bajty. Informatyka dla szkół ponadpodstawowych. Zakres rozszerzony. Część 1. Teraz bajty. Informatyka dla szkół ponadpodstawowych. Zakres rozszerzony. Część 1. Grażyna Koba MIGRA 2019 Spis treści (propozycja na 2*32 = 64 godziny lekcyjne) Moduł A. Wokół komputera i sieci komputerowych

Bardziej szczegółowo

Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej.

Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej. Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej. Dział Zagadnienia Wymagania podstawowe Wymagania ponadpodstawowe Arkusz kalkulacyjny (Microsoft Excel i OpenOffice) Uruchomienie

Bardziej szczegółowo

Nazwa wariantu modułu (opcjonalnie): Laboratorium programowania w języku C++

Nazwa wariantu modułu (opcjonalnie): Laboratorium programowania w języku C++ Uniwersytet Śląski w Katowicach str. 1 Kierunek i poziom studiów: Chemia, poziom pierwszy Sylabus modułu: Laboratorium programowania (0310-CH-S1-019) Nazwa wariantu modułu (opcjonalnie): Laboratorium programowania

Bardziej szczegółowo

Zarządzanie infrastrukturą sieciową Modele funkcjonowania sieci

Zarządzanie infrastrukturą sieciową Modele funkcjonowania sieci W miarę rozwoju sieci komputerowych pojawiały się różne rozwiązania organizujące elementy w sieć komputerową. W celu zapewnienia kompatybilności rozwiązań różnych producentów oraz opartych na różnych platformach

Bardziej szczegółowo

<Nazwa firmy> <Nazwa projektu> Specyfikacja dodatkowa. Wersja <1.0>

<Nazwa firmy> <Nazwa projektu> Specyfikacja dodatkowa. Wersja <1.0> Wersja [Uwaga: Niniejszy wzór dostarczony jest w celu użytkowania z Unified Process for EDUcation. Tekst zawarty w nawiasach kwadratowych i napisany błękitną kursywą

Bardziej szczegółowo

Nadzorowanie stanu serwerów i ich wykorzystania przez użytkowników

Nadzorowanie stanu serwerów i ich wykorzystania przez użytkowników Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Tomasz Kapelak Nr albumu: 187404 Praca magisterska na kierunku Informatyka

Bardziej szczegółowo

Kurs programowania. Wykład 12. Wojciech Macyna. 7 czerwca 2017

Kurs programowania. Wykład 12. Wojciech Macyna. 7 czerwca 2017 Wykład 12 7 czerwca 2017 Czym jest UML? UML składa się z dwóch podstawowych elementów: notacja: elementy graficzne, składnia języka modelowania, metamodel: definicje pojęć języka i powiazania pomiędzy

Bardziej szczegółowo

biegle i poprawnie posługuje się terminologią informatyczną,

biegle i poprawnie posługuje się terminologią informatyczną, INFORMATYKA KLASA 1 1. Wymagania na poszczególne oceny: 1) ocenę celującą otrzymuje uczeń, który: samodzielnie wykonuje na komputerze wszystkie zadania z lekcji, wykazuje inicjatywę rozwiązywania konkretnych

Bardziej szczegółowo

System zarządzający grami programistycznymi Meridius

System zarządzający grami programistycznymi Meridius System zarządzający grami programistycznymi Meridius Instytut Informatyki, Uniwersytet Wrocławski 20 września 2011 Promotor: prof. Krzysztof Loryś Gry komputerowe a programistyczne Gry komputerowe Z punktu

Bardziej szczegółowo

Analiza i projektowanie oprogramowania. Analiza i projektowanie oprogramowania 1/32

Analiza i projektowanie oprogramowania. Analiza i projektowanie oprogramowania 1/32 Analiza i projektowanie oprogramowania Analiza i projektowanie oprogramowania 1/32 Analiza i projektowanie oprogramowania 2/32 Cel analizy Celem fazy określania wymagań jest udzielenie odpowiedzi na pytanie:

Bardziej szczegółowo

MODEL WARSTWOWY PROTOKOŁY TCP/IP

MODEL WARSTWOWY PROTOKOŁY TCP/IP MODEL WARSTWOWY PROTOKOŁY TCP/IP TCP/IP (ang. Transmission Control Protocol/Internet Protocol) protokół kontroli transmisji. Pakiet najbardziej rozpowszechnionych protokołów komunikacyjnych współczesnych

Bardziej szczegółowo

Układy VLSI Bramki 1.0

Układy VLSI Bramki 1.0 Spis treści: 1. Wstęp... 2 2. Opis edytora schematów... 2 2.1 Dodawanie bramek do schematu:... 3 2.2 Łączenie bramek... 3 2.3 Usuwanie bramek... 3 2.4 Usuwanie pojedynczych połączeń... 4 2.5 Dodawanie

Bardziej szczegółowo

Programowanie sterowników przemysłowych / Jerzy Kasprzyk. wyd. 2 1 dodr. (PWN). Warszawa, Spis treści

Programowanie sterowników przemysłowych / Jerzy Kasprzyk. wyd. 2 1 dodr. (PWN). Warszawa, Spis treści Programowanie sterowników przemysłowych / Jerzy Kasprzyk. wyd. 2 1 dodr. (PWN). Warszawa, 2017 Spis treści Przedmowa 11 ROZDZIAŁ 1 Wstęp 13 1.1. Rys historyczny 14 1.2. Norma IEC 61131 19 1.2.1. Cele i

Bardziej szczegółowo

Efekty kształcenia dla kierunku studiów INFORMATYKA, Absolwent studiów I stopnia kierunku Informatyka WIEDZA

Efekty kształcenia dla kierunku studiów INFORMATYKA, Absolwent studiów I stopnia kierunku Informatyka WIEDZA Symbol Efekty kształcenia dla kierunku studiów INFORMATYKA, specjalność: 1) Sieciowe systemy informatyczne. 2) Bazy danych Absolwent studiów I stopnia kierunku Informatyka WIEDZA Ma wiedzę z matematyki

Bardziej szczegółowo

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1 Podstawy programowania. Wykład Funkcje Krzysztof Banaś Podstawy programowania 1 Programowanie proceduralne Pojęcie procedury (funkcji) programowanie proceduralne realizacja określonego zadania specyfikacja

Bardziej szczegółowo

PROGRAMOWALNE STEROWNIKI LOGICZNE

PROGRAMOWALNE STEROWNIKI LOGICZNE PROGRAMOWALNE STEROWNIKI LOGICZNE I. Wprowadzenie Klasyczna synteza kombinacyjnych i sekwencyjnych układów sterowania stosowana do automatyzacji dyskretnych procesów produkcyjnych polega na zaprojektowaniu

Bardziej szczegółowo

NS-2. Krzysztof Rusek. 26 kwietnia 2010

NS-2. Krzysztof Rusek. 26 kwietnia 2010 NS-2 Krzysztof Rusek 26 kwietnia 2010 1 Opis ćwiczenia Symulator ns-2 jest potężnym narzędziem, szeroko stosowanym w telekomunikacji. Ćwiczenie ma na cele przedstawić podstawy symulatora oraz symulacji

Bardziej szczegółowo

Przesyłania danych przez protokół TCP/IP

Przesyłania danych przez protokół TCP/IP Przesyłania danych przez protokół TCP/IP PAKIETY Protokół TCP/IP transmituje dane przez sieć, dzieląc je na mniejsze porcje, zwane pakietami. Pakiety są często określane różnymi terminami, w zależności

Bardziej szczegółowo

Webowy generator wykresów wykorzystujący program gnuplot

Webowy generator wykresów wykorzystujący program gnuplot Uniwersytet Mikołaja Kopernika Wydział Fizyki, Astronomii i Informatyki Stosowanej Marcin Nowak nr albumu: 254118 Praca inżynierska na kierunku informatyka stosowana Webowy generator wykresów wykorzystujący

Bardziej szczegółowo

Państwowa Wyższa Szkoła Techniczno-Ekonomiczna w Jarosławiu

Państwowa Wyższa Szkoła Techniczno-Ekonomiczna w Jarosławiu Załącznik nr 1 do Uchwały nr 9/12 Rady Instytutu Inżynierii Technicznej PWSTE w Jarosławiu z dnia 30 marca 2012r Państwowa Wyższa Szkoła Techniczno-Ekonomiczna w Jarosławiu EFEKTY KSZTAŁCENIA DLA KIERUNKU

Bardziej szczegółowo

Definicje. Algorytm to:

Definicje. Algorytm to: Algorytmy Definicje Algorytm to: skończony ciąg operacji na obiektach, ze ściśle ustalonym porządkiem wykonania, dający możliwość realizacji zadania określonej klasy pewien ciąg czynności, który prowadzi

Bardziej szczegółowo

Referencyjny model OSI. 3 listopada 2014 Mirosław Juszczak 37

Referencyjny model OSI. 3 listopada 2014 Mirosław Juszczak 37 Referencyjny model OSI 3 listopada 2014 Mirosław Juszczak 37 Referencyjny model OSI Międzynarodowa Organizacja Normalizacyjna ISO (International Organization for Standarization) opracowała model referencyjny

Bardziej szczegółowo

Analiza i projektowanie aplikacji Java

Analiza i projektowanie aplikacji Java Analiza i projektowanie aplikacji Java Modele analityczne a projektowe Modele analityczne (konceptualne) pokazują dziedzinę problemu. Modele projektowe (fizyczne) pokazują system informatyczny. Utrzymanie

Bardziej szczegółowo

SIECI KOMPUTEROWE Adresowanie IP

SIECI KOMPUTEROWE  Adresowanie IP Adresowanie IP Podstawowa funkcja protokołu IP (Internet Protocol) polega na dodawaniu informacji o adresie do pakietu danych i przesyłaniu ich poprzez sieć do właściwych miejsc docelowych. Aby umożliwić

Bardziej szczegółowo

Opracowanie ćwiczenia laboratoryjnego dotyczącego wykorzystania sieci przemysłowej Profibus. DODATEK NR 4 Instrukcja laboratoryjna

Opracowanie ćwiczenia laboratoryjnego dotyczącego wykorzystania sieci przemysłowej Profibus. DODATEK NR 4 Instrukcja laboratoryjna Wydział Informatyki i Zarządzania Opracowanie ćwiczenia laboratoryjnego dotyczącego wykorzystania sieci przemysłowej Profibus DODATEK NR 4 Instrukcja laboratoryjna. Opracował: Paweł Obraniak Wrocław 2014

Bardziej szczegółowo

DLA SEKTORA INFORMATYCZNEGO W POLSCE

DLA SEKTORA INFORMATYCZNEGO W POLSCE DLA SEKTORA INFORMATYCZNEGO W POLSCE SRK IT obejmuje kompetencje najważniejsze i specyficzne dla samego IT są: programowanie i zarządzanie systemami informatycznymi. Z rozwiązań IT korzysta się w każdej

Bardziej szczegółowo

Podstawy programowania skrót z wykładów:

Podstawy programowania skrót z wykładów: Podstawy programowania skrót z wykładów: // komentarz jednowierszowy. /* */ komentarz wielowierszowy. # include dyrektywa preprocesora, załączająca biblioteki (pliki nagłówkowe). using namespace

Bardziej szczegółowo

SYSTEMY OPERACYJNE: STRUKTURY I FUNKCJE (opracowano na podstawie skryptu PP: Królikowski Z., Sajkowski M. 1992: Użytkowanie systemu operacyjnego UNIX)

SYSTEMY OPERACYJNE: STRUKTURY I FUNKCJE (opracowano na podstawie skryptu PP: Królikowski Z., Sajkowski M. 1992: Użytkowanie systemu operacyjnego UNIX) (opracowano na podstawie skryptu PP: Królikowski Z., Sajkowski M. 1992: Użytkowanie systemu operacyjnego UNIX) W informatyce występują ściśle obok siebie dwa pojęcia: sprzęt (ang. hardware) i oprogramowanie

Bardziej szczegółowo

Urządzenia sieciowe. Tutorial 1 Topologie sieci. Definicja sieci i rodzaje topologii

Urządzenia sieciowe. Tutorial 1 Topologie sieci. Definicja sieci i rodzaje topologii Tutorial 1 Topologie sieci Definicja sieci i rodzaje topologii Definicja 1 Sieć komputerowa jest zbiorem mechanizmów umożliwiających komunikowanie się komputerów bądź urządzeń komputerowych znajdujących

Bardziej szczegółowo

Instytut Mechaniki i Inżynierii Obliczeniowej Wydział Mechaniczny Technologiczny Politechnika Śląska

Instytut Mechaniki i Inżynierii Obliczeniowej  Wydział Mechaniczny Technologiczny Politechnika Śląska Instytut Mechaniki i Inżynierii Obliczeniowej www.imio.polsl.pl fb.com/imiopolsl @imiopolsl Wydział Mechaniczny Technologiczny Politechnika Śląska Języki programowania z programowaniem obiektowym Laboratorium

Bardziej szczegółowo

KIERUNKOWE EFEKTY KSZTAŁCENIA

KIERUNKOWE EFEKTY KSZTAŁCENIA WYDZIAŁ INFORMATYKI I ZARZĄDZANIA Kierunek studiów: INFORMATYKA Stopień studiów: STUDIA I STOPNIA Obszar Wiedzy/Kształcenia: OBSZAR NAUK TECHNICZNYCH Obszar nauki: DZIEDZINA NAUK TECHNICZNYCH Dyscyplina

Bardziej szczegółowo

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery

XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery http://xqtav.sourceforge.net XQTav - reprezentacja diagramów przepływu prac w formacie SCUFL przy pomocy XQuery dr hab. Jerzy Tyszkiewicz dr Andrzej Kierzek mgr Jacek Sroka Grzegorz Kaczor praca mgr pod

Bardziej szczegółowo

Programowanie w języku Python. Grażyna Koba

Programowanie w języku Python. Grażyna Koba Programowanie w języku Python Grażyna Koba Kilka definicji Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i

Bardziej szczegółowo

Programowanie w języku C++ Grażyna Koba

Programowanie w języku C++ Grażyna Koba Programowanie w języku C++ Grażyna Koba Kilka definicji: Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i zasad

Bardziej szczegółowo

Narzędzia uruchomieniowe dla systemów Embedded firmy Total Phase

Narzędzia uruchomieniowe dla systemów Embedded firmy Total Phase 1 Narzędzia uruchomieniowe dla systemów Embedded firmy Total Phase Narzędzia uruchomieniowe dla systemów Embedded firmy Total Phase Jednym z głównych aspektów procesu programowania systemów wbudowanych

Bardziej szczegółowo

Laboratorium Technologii Informacyjnych. Projektowanie Baz Danych

Laboratorium Technologii Informacyjnych. Projektowanie Baz Danych Laboratorium Technologii Informacyjnych Projektowanie Baz Danych Komputerowe bazy danych są obecne podstawowym narzędziem służącym przechowywaniu, przetwarzaniu i analizie danych. Gromadzone są dane w

Bardziej szczegółowo

SCENARIUSZ LEKCJI. TEMAT LEKCJI: Zastosowanie średnich w statystyce i matematyce. Podstawowe pojęcia statystyczne. Streszczenie.

SCENARIUSZ LEKCJI. TEMAT LEKCJI: Zastosowanie średnich w statystyce i matematyce. Podstawowe pojęcia statystyczne. Streszczenie. SCENARIUSZ LEKCJI OPRACOWANY W RAMACH PROJEKTU: INFORMATYKA MÓJ SPOSÓB NA POZNANIE I OPISANIE ŚWIATA. PROGRAM NAUCZANIA INFORMATYKI Z ELEMENTAMI PRZEDMIOTÓW MATEMATYCZNO-PRZYRODNICZYCH Autorzy scenariusza:

Bardziej szczegółowo

Web frameworks do budowy aplikacji zgodnych z J2EE

Web frameworks do budowy aplikacji zgodnych z J2EE Web frameworks do budowy aplikacji zgodnych z J2EE Jacek Panachida promotor: dr Dariusz Król Przypomnienie Celem pracy jest porównanie wybranych szkieletów programistycznych o otwartym kodzie źródłowym

Bardziej szczegółowo

Tworzenie i obsługa wirtualnego laboratorium komputerowego

Tworzenie i obsługa wirtualnego laboratorium komputerowego Uniwersytet Mikołaja Kopernika Wydział Fizyki, Astronomii i Informatyki Stosowanej Michał Ochociński nr albumu: 236401 Praca magisterska na kierunku informatyka stosowana Tworzenie i obsługa wirtualnego

Bardziej szczegółowo

Uniwersytet Śląski w Katowicach str. 1 Wydział Informatyki i Nauki o Materiałach

Uniwersytet Śląski w Katowicach str. 1 Wydział Informatyki i Nauki o Materiałach Uniwersytet Śląski w Katowicach str. 1 Efekty dla: nazwa kierunku poziom profil Informatyka inżynierska pierwszy ogólnoakademicki Kod efektu (kierunek) K_1_A_I_W01 K_1_A_I_W02 K_1_A_I_W03 K_1_A_I_W04 K_1_A_I_W05

Bardziej szczegółowo

Zastosowania Robotów Mobilnych

Zastosowania Robotów Mobilnych Zastosowania Robotów Mobilnych Temat: Zapoznanie ze środowiskiem Microsoft Robotics Developer Studio na przykładzie prostych problemów nawigacji. 1) Wstęp: Microsoft Robotics Developer Studio jest popularnym

Bardziej szczegółowo

PRZEWODNIK PO PRZEDMIOCIE

PRZEWODNIK PO PRZEDMIOCIE Nazwa przedmiotu: Algorytmy i programowanie Algorithms and Programming Kierunek: Zarządzanie i Inżynieria Produkcji Rodzaj przedmiotu: kierunkowy Poziom studiów: studia I stopnia forma studiów: studia

Bardziej szczegółowo

Technologie informacyjne - wykład 12 -

Technologie informacyjne - wykład 12 - Zakład Fizyki Budowli i Komputerowych Metod Projektowania Instytut Budownictwa Wydział Budownictwa Lądowego i Wodnego Politechnika Wrocławska Technologie informacyjne - wykład 12 - Prowadzący: Dmochowski

Bardziej szczegółowo

OfficeObjects e-forms

OfficeObjects e-forms OfficeObjects e-forms Rodan Development Sp. z o.o. 02-820 Warszawa, ul. Wyczółki 89, tel.: (+48-22) 643 92 08, fax: (+48-22) 643 92 10, http://www.rodan.pl Spis treści Wstęp... 3 Łatwość tworzenia i publikacji

Bardziej szczegółowo

Instalacja SQL Server Express. Logowanie na stronie Microsoftu

Instalacja SQL Server Express. Logowanie na stronie Microsoftu Instalacja SQL Server Express Logowanie na stronie Microsoftu Wybór wersji do pobrania Pobieranie startuje, przechodzimy do strony z poradami. Wypakowujemy pobrany plik. Otwiera się okno instalacji. Wybieramy

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

Podstawy i języki programowania

Podstawy i języki programowania Podstawy i języki programowania Laboratorium 2 - wprowadzenie do zmiennych mgr inż. Krzysztof Szwarc krzysztof@szwarc.net.pl Sosnowiec, 23 października 2017 1 / 26 mgr inż. Krzysztof Szwarc Podstawy i

Bardziej szczegółowo

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04 Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04 Cel zajęć. Celem zajęć jest zapoznanie się ze sposobem działania popularnych kolekcji. Wprowadzenie teoretyczne. Rozważana w ramach niniejszych

Bardziej szczegółowo

Marek Parfieniuk, Tomasz Łukaszuk, Tomasz Grześ. Symulator zawodnej sieci IP do badania aplikacji multimedialnych i peer-to-peer

Marek Parfieniuk, Tomasz Łukaszuk, Tomasz Grześ. Symulator zawodnej sieci IP do badania aplikacji multimedialnych i peer-to-peer Marek Parfieniuk, Tomasz Łukaszuk, Tomasz Grześ Symulator zawodnej sieci IP do badania aplikacji multimedialnych i peer-to-peer Plan prezentacji 1. Cel projektu 2. Cechy systemu 3. Budowa systemu: Agent

Bardziej szczegółowo

Wykład I. Wprowadzenie do baz danych

Wykład I. Wprowadzenie do baz danych Wykład I Wprowadzenie do baz danych Trochę historii Pierwsze znane użycie terminu baza danych miało miejsce w listopadzie w 1963 roku. W latach sześcdziesątych XX wieku został opracowany przez Charles

Bardziej szczegółowo

Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Instytut Fizyki

Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Instytut Fizyki Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Instytut Fizyki Tomasz Pawłowski Nr albumu: 146956 Praca magisterska na kierunku

Bardziej szczegółowo

Rok szkolny 2014/15 Sylwester Gieszczyk. Wymagania edukacyjne w technikum. SIECI KOMPUTEROWE kl. 2c

Rok szkolny 2014/15 Sylwester Gieszczyk. Wymagania edukacyjne w technikum. SIECI KOMPUTEROWE kl. 2c Wymagania edukacyjne w technikum SIECI KOMPUTEROWE kl. 2c Wiadomości Umiejętności Lp. Temat konieczne podstawowe rozszerzające dopełniające Zapamiętanie Rozumienie W sytuacjach typowych W sytuacjach problemowych

Bardziej szczegółowo

Modelowanie i Programowanie Obiektowe

Modelowanie i Programowanie Obiektowe Modelowanie i Programowanie Obiektowe Wykład I: Wstęp 20 październik 2012 Programowanie obiektowe Metodyka wytwarzania oprogramowania Metodyka Metodyka ustandaryzowane dla wybranego obszaru podejście do

Bardziej szczegółowo

Modelowanie jako sposób opisu rzeczywistości. Katedra Mikroelektroniki i Technik Informatycznych Politechnika Łódzka

Modelowanie jako sposób opisu rzeczywistości. Katedra Mikroelektroniki i Technik Informatycznych Politechnika Łódzka Modelowanie jako sposób opisu rzeczywistości Katedra Mikroelektroniki i Technik Informatycznych Politechnika Łódzka 2015 Wprowadzenie: Modelowanie i symulacja PROBLEM: Podstawowy problem z opisem otaczającej

Bardziej szczegółowo

SYLABUS DOTYCZY CYKLU KSZTAŁCENIA Bieżący sylabus w semestrze zimowym roku 2016/17

SYLABUS DOTYCZY CYKLU KSZTAŁCENIA Bieżący sylabus w semestrze zimowym roku 2016/17 Załącznik nr 4 do Uchwały Senatu nr 430/01/2015 SYLABUS DOTYCZY CYKLU KSZTAŁCENIA 2016-2018 Bieżący sylabus w semestrze zimowym roku 2016/17 1.1. PODSTAWOWE INFORMACJE O PRZEDMIOCIE/MODULE Nazwa przedmiotu/

Bardziej szczegółowo

Rozdział ten zawiera informacje na temat zarządzania Modułem Modbus TCP oraz jego konfiguracji.

Rozdział ten zawiera informacje na temat zarządzania Modułem Modbus TCP oraz jego konfiguracji. 1 Moduł Modbus TCP Moduł Modbus TCP daje użytkownikowi Systemu Vision możliwość zapisu oraz odczytu rejestrów urządzeń, które obsługują protokół Modbus TCP. Zapewnia on odwzorowanie rejestrów urządzeń

Bardziej szczegółowo

PROGRAM PRAKTYKI ZAWODOWEJ. Technikum Zawód: technik informatyk

PROGRAM PRAKTYKI ZAWODOWEJ. Technikum Zawód: technik informatyk PROGRAM PRAKTYKI ZAWODOWEJ Technikum Zawód: technik informatyk 351203 Lp. Temat 1 Zajęcia wprowadzające. Zapoznanie z zakładem, regulaminem pracy, przepisami BHP oraz instruktaż bhp. 2 Montaż i eksploatacja

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia.

Bardziej szczegółowo

Odniesienie do efektów kształcenia dla obszaru nauk EFEKTY KSZTAŁCENIA Symbol

Odniesienie do efektów kształcenia dla obszaru nauk EFEKTY KSZTAŁCENIA Symbol KIERUNKOWE EFEKTY KSZTAŁCENIA Wydział Informatyki i Zarządzania Kierunek studiów INFORMATYKA (INF) Stopień studiów - pierwszy Profil studiów - ogólnoakademicki Projekt v1.0 z 18.02.2015 Odniesienie do

Bardziej szczegółowo

Monitorowanie i zarządzanie urządzeniami sieciowymi przy pomocy narzędzi Net-SNMP

Monitorowanie i zarządzanie urządzeniami sieciowymi przy pomocy narzędzi Net-SNMP Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Informatyki Stosowanej Szymon Klimuk Nr albumu: 187408 Praca magisterska na kierunku Informatyka Monitorowanie

Bardziej szczegółowo

Zakładane efekty kształcenia dla kierunku Wydział Telekomunikacji, Informatyki i Elektrotechniki

Zakładane efekty kształcenia dla kierunku Wydział Telekomunikacji, Informatyki i Elektrotechniki Jednostka prowadząca kierunek studiów Nazwa kierunku studiów Specjalności Obszar kształcenia Profil kształcenia Poziom kształcenia Forma kształcenia Tytuł zawodowy uzyskiwany przez absolwenta Dziedziny

Bardziej szczegółowo

Szybkie prototypowanie w projektowaniu mechatronicznym

Szybkie prototypowanie w projektowaniu mechatronicznym Szybkie prototypowanie w projektowaniu mechatronicznym Systemy wbudowane (Embedded Systems) Systemy wbudowane (ang. Embedded Systems) są to dedykowane architektury komputerowe, które są integralną częścią

Bardziej szczegółowo

Informatyka I stopień (I stopień / II stopień) Ogólnoakademicki (ogólno akademicki / praktyczny)

Informatyka I stopień (I stopień / II stopień) Ogólnoakademicki (ogólno akademicki / praktyczny) Załącznik nr 7 do Zarządzenia Rektora nr 10/12 z dnia 21 lutego 2012r. KARTA MODUŁU / KARTA PRZEDMIOTU Kod Nazwa Nazwa w języku angielskim Obowiązuje od roku akademickiego 2012/2013 Programy grafiki rastrowej,

Bardziej szczegółowo

SCENARIUSZ LEKCJI. Streszczenie. Czas realizacji. Podstawa programowa

SCENARIUSZ LEKCJI. Streszczenie. Czas realizacji. Podstawa programowa Autorzy scenariusza: SCENARIUSZ LEKCJI OPRACOWANY W RAMACH PROJEKTU: INFORMATYKA MÓJ SPOSÓB NA POZNANIE I OPISANIE ŚWIATA. PROGRAM NAUCZANIA INFORMATYKI Z ELEMENTAMI PRZEDMIOTÓW MATEMATYCZNO-PRZYRODNICZYCH

Bardziej szczegółowo

Generated by Foxit PDF Creator Foxit Software http://www.foxitsoftware.com For evaluation only. System Szablonów

Generated by Foxit PDF Creator Foxit Software http://www.foxitsoftware.com For evaluation only. System Szablonów System Szablonów System szablonów System szablonów to biblioteka, która pozwala oddzielić warstwę prezentacji od warstwy logicznej. Aplikacja WWW najpierw pobiera wszystkie dane, przetwarza je i umieszcza

Bardziej szczegółowo

Zdalne monitorowanie i zarządzanie urządzeniami sieciowymi

Zdalne monitorowanie i zarządzanie urządzeniami sieciowymi Uniwersytet Mikołaja Kopernika w Toruniu Wydział Matematyki i Informatyki Wydział Fizyki, Astronomii i Infomatyki Stosowanej Piotr Benetkiewicz Nr albumu: 168455 Praca magisterska na kierunku Informatyka

Bardziej szczegółowo

KOMPLEKSOWA OFERTA SZKOLEŃ MS EXCEL W FINANSACH. z konsultacjami

KOMPLEKSOWA OFERTA SZKOLEŃ MS EXCEL W FINANSACH. z konsultacjami KOMPLEKSOWA OFERTA SZKOLEŃ MS EXCEL W FINANSACH z konsultacjami Przedmiot oferty Pakiet szkoleń przygotowujących w sposób kompleksowy do optymalnego wykorzystania arkuszy kalkulacyjnych w codziennej pracy

Bardziej szczegółowo

PRZEWODNIK PO PRZEDMIOCIE

PRZEWODNIK PO PRZEDMIOCIE Nazwa przedmiotu: Podstawy Informatyki Basic Informatics Kierunek: Zarządzanie i Inżynieria Produkcji Rodzaj przedmiotu: ogólny Poziom studiów: studia I stopnia forma studiów: studia stacjonarne Rodzaj

Bardziej szczegółowo

router wielu sieci pakietów

router wielu sieci pakietów Dzisiejsze sieci komputerowe wywierają ogromny wpływ na naszą codzienność, zmieniając to, jak żyjemy, pracujemy i spędzamy wolny czas. Sieci mają wiele rozmaitych zastosowań, wśród których można wymienić

Bardziej szczegółowo

I. KARTA PRZEDMIOTU CEL PRZEDMIOTU

I. KARTA PRZEDMIOTU CEL PRZEDMIOTU I. KARTA PRZEDMIOTU 1. Nazwa przedmiotu: TECHNOLOGIA INFORMACYJNA 2. Kod przedmiotu: Ot 3. Jednostka prowadząca: Wydział Mechaniczno-Elektryczny 4. Kierunek: Automatyka i Robotyka 5. Specjalność: Informatyka

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 03 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas abstrakcyjnych i interfejsów. Wprowadzenie

Bardziej szczegółowo

Nauczanie na odległość

Nauczanie na odległość P o l i t e c h n i k a W a r s z a w s k a Nauczanie na odległość a standaryzacja materiałów edukacyjnych Krzysztof Kaczmarski Nauczanie na odległość T Nauczanie ustawiczne T Studia przez Internet? T

Bardziej szczegółowo

ARCHICAD 21 podstawy wykorzystania standardu IFC

ARCHICAD 21 podstawy wykorzystania standardu IFC ARCHICAD 21 podstawy wykorzystania standardu IFC IFC (Industry Foundation Classes) to otwarty format wymiany danych. Powstał z myślą o ułatwieniu międzydyscyplinarnej współpracy z wykorzystaniem cyfrowych

Bardziej szczegółowo

Typy, klasy typów, składnie w funkcji

Typy, klasy typów, składnie w funkcji Typy, klasy typów, składnie w funkcji Typy w Haskell Każde wyrażenie w Haskell posiada zdefiniowany typ. Dzięki temu już na etapie kompilacji kodu następuje sprawdzenie poprawności kodu i zabezpiecza nas

Bardziej szczegółowo

Smarty PHP. Leksykon kieszonkowy

Smarty PHP. Leksykon kieszonkowy IDZ DO PRZYK ADOWY ROZDZIA SPIS TREœCI KATALOG KSI EK KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG Smarty PHP. Leksykon kieszonkowy Autor: Daniel Bargie³ ISBN: 83-246-0676-9 Format: B6, stron: 112 TWÓJ KOSZYK

Bardziej szczegółowo

Efekty uczenia się na kierunku. Logistyka (studia pierwszego stopnia o profilu praktycznym)

Efekty uczenia się na kierunku. Logistyka (studia pierwszego stopnia o profilu praktycznym) Efekty uczenia się na kierunku Załącznik nr 2 do uchwały nr 412 Senatu Uniwersytetu Zielonogórskiego z dnia 29 maja 2019 r. Logistyka (studia pierwszego stopnia o profilu praktycznym) Tabela 1. Kierunkowe

Bardziej szczegółowo

ZAMAWIAJĄCY. CONCEPTO Sp. z o.o.

ZAMAWIAJĄCY. CONCEPTO Sp. z o.o. Grodzisk Wielkopolski, dnia 11.02.2013r. ZAMAWIAJĄCY z siedzibą w Grodzisku Wielkopolskim (62-065) przy ul. Szerokiej 10 realizując zamówienie w ramach projektu dofinansowanego z Programu Operacyjnego

Bardziej szczegółowo

Grzegorz Ruciński. Warszawska Wyższa Szkoła Informatyki 2011. Promotor dr inż. Paweł Figat

Grzegorz Ruciński. Warszawska Wyższa Szkoła Informatyki 2011. Promotor dr inż. Paweł Figat Grzegorz Ruciński Warszawska Wyższa Szkoła Informatyki 2011 Promotor dr inż. Paweł Figat Cel i hipoteza pracy Wprowadzenie do tematu Przedstawienie porównywanych rozwiązań Przedstawienie zalet i wad porównywanych

Bardziej szczegółowo

Instrukcja obsługi Multiconverter 2.0

Instrukcja obsługi Multiconverter 2.0 Instrukcja obsługi Multiconverter 2.0 Opis: Niniejsza instrukcja opisuje wymogi użytkowania aplikacji oraz zawiera informacje na temat jej obsługi. DHL Multiconverter powstał w celu ułatwienia oraz usprawnienia

Bardziej szczegółowo

I. KARTA PRZEDMIOTU CEL PRZEDMIOTU

I. KARTA PRZEDMIOTU CEL PRZEDMIOTU I. KARTA PRZEDMIOTU 1. Nazwa przedmiotu: TECHNOLOGIA INFORMACYJNA 2. Kod przedmiotu: Ot 3. Jednostka prowadząca: Wydział Mechaniczno-Elektryczny 4. Kierunek: Automatyka i Robotyka 5. Specjalność: Elektroautomatyka

Bardziej szczegółowo

Projekt i implementacja filtra dzeń Pocket PC

Projekt i implementacja filtra dzeń Pocket PC Projekt i implementacja filtra pakietów w dla urządze dzeń Pocket PC Jakub Grabowski opiekun pracy: prof. dr hab. Zbigniew Kotulski 2005-10-25 Zagrożenia Ataki sieciowe Problemy z bezpieczeństwem sieci

Bardziej szczegółowo

Zagadnienia (1/3) Data-flow diagramy przepływów danych ERD diagramy związków encji Diagramy obiektowe w UML (ang. Unified Modeling Language)

Zagadnienia (1/3) Data-flow diagramy przepływów danych ERD diagramy związków encji Diagramy obiektowe w UML (ang. Unified Modeling Language) Zagadnienia (1/3) Rola modelu systemu w procesie analizy wymagań (inżynierii wymagań) Prezentacja różnego rodzaju informacji o systemie w zależności od rodzaju modelu. Budowanie pełnego obrazu systemu

Bardziej szczegółowo

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main. Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo

Bardziej szczegółowo

zakładane efekty kształcenia

zakładane efekty kształcenia Załącznik nr 1 do uchwały nr 41/2018 Senatu Politechniki Śląskiej z dnia 28 maja 2018 r. Efekty kształcenia dla kierunku: INFORMATYKA WYDZIAŁ AUTOMATYKI, ELEKTRONIKI I INFORMATYKI WYDZIAŁ ELEKTRYCZNY nazwa

Bardziej szczegółowo

Efekty kształcenia dla: nazwa kierunku

Efekty kształcenia dla: nazwa kierunku Uniwersytet Śląski w Katowicach str. 1 Efekty dla: nazwa kierunku Informatyka poziom pierwszy (licencjat) profil ogólnoakademicki Załącznik nr 46 do uchwały nr. Senatu Uniwersytetu Śląskiego w Katowicach

Bardziej szczegółowo

4. Podstawowa konfiguracja

4. Podstawowa konfiguracja 4. Podstawowa konfiguracja Po pierwszym zalogowaniu się do urządzenia należy zweryfikować poprawność licencji. Można to zrobić na jednym z widżetów panelu kontrolnego. Wstępną konfigurację można podzielić

Bardziej szczegółowo

Rozkład materiału do nauczania informatyki w liceum ogólnokształcącym Wersja II

Rozkład materiału do nauczania informatyki w liceum ogólnokształcącym Wersja II Zespół TI Instytut Informatyki Uniwersytet Wrocławski ti@ii.uni.wroc.pl http://www.wsip.com.pl/serwisy/ti/ Rozkład materiału do nauczania informatyki w liceum ogólnokształcącym Wersja II Rozkład wymagający

Bardziej szczegółowo

PRZEWODNIK PO PRZEDMIOCIE

PRZEWODNIK PO PRZEDMIOCIE Nazwa przedmiotu: Kierunek: Mechatronika Rodzaj przedmiotu: dla specjalności Systemy Sterowania w ramach kierunku Mechatronika Rodzaj zajęć: Wykład, laboratorium Systemy Operacyjne Czasu Rzeczywistego

Bardziej szczegółowo

Uniwersalny Konwerter Protokołów

Uniwersalny Konwerter Protokołów Uniwersalny Konwerter Protokołów Autor Robert Szolc Promotor dr inż. Tomasz Szczygieł Uniwersalny Konwerter Protokołów Szybki rozwój technologii jaki obserwujemy w ostatnich latach, spowodował że systemy

Bardziej szczegółowo

PRZEWODNIK PO PRZEDMIOCIE

PRZEWODNIK PO PRZEDMIOCIE Nazwa przedmiotu: Kierunek: ENERGETYKA Rodzaj przedmiotu: podstawowy Rodzaj zajęć: wykład, laboratorium I KARTA PRZEDMIOTU CEL PRZEDMIOTU PRZEWODNIK PO PRZEDMIOCIE C1. Zapoznanie studentów z metodami i

Bardziej szczegółowo