440 likes | 621 Views
Uniwersytet Łódzki Katedra Informatyki. W. Bartkiewicz. Systemy rozproszone. Wykład 5. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej - RPC. Katedra Informatyki. Oprogramowanie warstwy pośredniej.
E N D
Uniwersytet Łódzki Katedra Informatyki W. Bartkiewicz Systemy rozproszone Wykład 5. Komunikacja międzyprocesowa z wykorzystaniem usług warstwy pośredniej - RPC
Katedra Informatyki Oprogramowanie warstwy pośredniej • Oprogramowanie warstwy pośredniej to aplikacja, która logicznie przynależy do warstwy zastosowań, lecz zawiera wiele protokołów ogólnego przeznaczenia, niezależnych od innych, bardziej konkretnych aplikacji. • Protokoły komunikacyjne oprogramowania warstwy pośredniej tworzą podstawy usług komunikacyjnych wysokiego poziomu. • Do podstawowych usług komunikacyjnych oprogramowania warstwy pośredniej należą: • Zdalne wywołania procedur (RPC). • Zdalne wywołania obiektów. • Obsługa kolejek komunikatów. • Zaplecze strumieni komunikacji nośników ciągłych.
Katedra Informatyki Protokół fizyczny Protokół łącza danych Protokół sieci Protokół aplikacji Protokół transportu Zastosowanie 6 Protokół warstwy pośredniej Warstwa pośrednia 5 Transport 4 Sieć 3 Łącze danych 2 Poziom fizyczny 1 Sieć Zmodyfikowany model komunikacji sieciowej
Katedra Informatyki RPC – Wywołania procedur zdalnych • RPC jest konstrukcją ukrywającą działania komunikacyjne pod znaną abstrakcją wywołania procedury. • Odwołanie do serwera ma po stronie klienta postać identyczną jak zwykłe wywołanie podprogramu. • Abstrakcja ta ukrywa w rzeczywistości wysłanie odpowiedniego komunikatu do procesu serwera (określającego procedurę jaka ma zostać wykonana przez serwer), wykonanie przez serwer odpowiadającego mu przetwarzania i odesłanie odpowiedzi. • Dane przesyłane przez klienta i niezbędne do wykonania przez serwer procedury, podawane są jako wartości parametrów. Odpowiedź serwera przekształcana jest na wartości parametrów wyjściowych oraz wartości powrotne z funkcji.
Katedra Informatyki Semantyka wywołań RPC • Definicja zdalnej procedury określa parametry wejściowe i wyjściowe. • Parametry wejściowe przekazywane są serwerowi jako wartości argumentów w komunikacie zamawiającym i kopiowane do zmiennych, które są przekazywane jako parametry do procedury w środowisku wykonawczym serwera. • Parametry wyjściowe zwracane są klientowi w komunikacie z odpowiedzią, gdzie używa się ich do zastąpienia wartości odpowiednich zmiennych w środowisku wywołania. • Jeśli parametr używany jest jako wejściowy i wyjściowy, to jego wartość musi zostać przesłana zarówno w zamówieniu jak i w odpowiedzi. • Dostarczenie informacji o tym czy parametr używany jest na wejściu, wyjściu, czy w obu przypadkach powoduje konieczność zastosowania w każdym systemie RPC języka opisu interfejsu (IDL - Interface Definition Language).
Katedra Informatyki Namiastki klienta i serwera • Jeśli dana procedura ma być wykonana zdalnie, to system RPC w programie klienta umieszcza jej inną wersję, tzw. namiastkę procedury (stub procedure) nazywaną namiastką klienta (client stub). Jest to normalny, lokalny podprogram o sygnaturze zgodnej z procedurą zdalną. Zgodność sygnatury osiągana jest poprzez wspólną definicję interfejsu. • Namiastka klienta umieszcza identyfikator procedury oraz parametry w komunikacie, który wysyła do serwera wykorzystując lokalny SO. Następnie blokuje się w oczekiwaniu na odpowiedź serwera. • W programie serwera system RPC instaluje tzw. ekspedytora (dispatcher) oraz namiastki procedur serwera (server stubs). Ekspedytor na podstawie identyfikatora procedury w komunikacie z zamówieniem wybiera odpowiednią namiastkę procedury, przekazując jej argumenty.
Katedra Informatyki Namiastki klienta i serwera (c.d.) • Namiastka serwera rozpakowuje parametry z komunikatu, tworząc w środowisku serwera odpowiednie bufory zarówno dla danych wejściowych jak i wyników działania. Następnie wywołuje (również poprzez zwykłe wywołanie lokalne) procedurę zdalną serwera. Wykonuje ona swoje zadanie, zwracając również w normalny sposób wynik namiastce serwera. • Namiastka serwera umieszcza wynik działania procedury w komunikacie z odpowiedzią dla klienta, wysyła go a następnie przechodzi w stan oczekiwania na nadejście następnego komunikatu. • Namiastka klienta odbiera komunikat, rozpakowuje z niego wyniki, kopiuje je do obszarów pamięci w których oczekuje ich podprogram klienta wywołujący procedurę zdalną i kończy działanie w zwykły sposób.
Katedra Informatyki Działanie RPC Komputer klienta Komputer serwera Proces klienta Odwrotne przetaczanie parametrów Przetaczanie wyników Przetaczanie parametrów Odwrotne przetaczanie wyników Przyjęcie zamówienia Wysłanie odpowiedzi Wykona-nie procedury Powrót Wywoła- nie lokalne Lokalny powrót Wysyłanie zamówienia Przyjęcie odpowiedzi Wybór procedury Moduł komunikacyjny (SO) Moduł komunikacyjny (SO) Namiastka procedury serwera Namiastka procedury klienta Procedura usługowa Klient Ekspedytor
Katedra Informatyki Specyfika wywołań RPC • Procedura zdalna wykonywana jest w środowisku odmiennym od miejsca jej wywołania, toteż nie ma dostępu do zmiennych środowiska wywołania, np. do zmiennych globalnych zadeklarowanych w programie wywołującym. • Proces przekazywania danych między różnymi środowiskami wykonawczymi nazywamy przetaczaniem (marshaling). • W wieloplatformowych środowiskach RPC występuje konieczność uwzględnienia różnych reprezentacji binarnych danych, tzn. zdefiniowania protokołów ich przesyłania wspólnych dla serwera i klienta. • Przekazywanie przez proces w komunikacie do innych procesów adresów komórek pamięci lub ich równoważników (np. odniesień, referencji, uchwytów) jest bezcelowe. Tak więc generalnie argumenty i wyniki procedur zdalnych nie powinny zawierać struktur danych ze wskaźnikami do komórek pamięci. • Systemy RPC radzą sobie zwykle z przetaczaniem wskaźników (odniesień) do prostych tablic i struktur, kopiując (przesyłając) między namiastkami klienta i serwera całe wskazywane dane.
Katedra Informatyki Język Opisu Interfejsu (IDL) • Aby uprościć korzystanie z mechanizmów RPC, interfejsy definiujące zbiory podprogramów realizowanych przez serwer i możliwych do wywołania przez klienta, określane są zazwyczaj w specjalnym języku opisu interfejsu (IDL – Interface Definition Language). • Zastosowanie wspólnej definicji interfejsu zarówno dla serwera, jak i klienta zapewnia, że typy argumentów i wartości powrotnych oraz protokoły przetaczania ich wartości, używane przez klienta będą zgodne ze zdefiniowanymi na serwerze. • Definicje interfejsów zapisane w IDL kompilowane są przy użyciu kompilatora interfejsu, tworzącego składowe konsolidowane z programami serwera i klienta.
Katedra Informatyki Zadania kompilatora interfejsu • Generowanie namiastek procedur klienta, odpowiadających sygnaturom procedur w interfejsie. Namiastki te zostaną skompilowane i połączone z programem klienta. • Generowanie namiastek procedur serwera odpowiadających sygnaturom procedur w interfejsie. Namiastki te zostaną skompilowane i połączone z programem serwera. • Na podstawie sygnatur procedur z interfejsu, określających typy argumentów i wartości powrotnych, wygenerowanie operacji przetaczania oraz odwrotnego przetaczania w każdej namiastce procedury. • Wygenerowanie dla każdej procedury z interfejsu szablonu bibliotecznego charakterystycznego dla danego języka programowania (na przykład w języku C/C++ pliku nagłówkowego z deklaracjami sygnatur poszczególnych procedur). Programista dostarcza następnie ich implementacji.
Katedra Informatyki Wiązanie • Definicja interfejsu określa tekstową nazwę usługi za pomocą której odwołują się do niej klienty. Dla celów komunikacyjnych niezbędne jest jednak dostarczenie klientom informacji o punkcie końcowym serwera. • Przez wiązanie (binding) rozumiemy odwzorowanie nazwy usługi na konkretny identyfikator komunikacyjny, określający punkt końcowy serwera (identyfikator portu, grupy portów lub dowolna inna forma miejsca przeznaczenia) do którego wysyłane będą komunikaty. • Program klienta zawierać może sieciowy adres serwera. Oznacza to jednak, że przy każdym przemieszczeniu serwera niezbędne jest poinformowanie o tym wszystkich klientów. • Łącznik (binder) jest odrębną usługą utrzymującą tablicę odwzorowań nazw usług na punkty końcowe serwerów. Łącznik jest przykładem usług nazewniczych, w których rejestruje się serwery aby umożliwić ich lokalizację przez klientów.
Katedra Informatyki Uszkodzenia dostaw • Komunikaty od czasu do czasu są gubione przez nadawców, odbiorców oraz bramy sieci. • Sieci mogą ulegać podziałowi. Oznacza to, że jeden lub więcej węzłów sieci może zostać oddzielony od reszty sieci. • Procesy ulegają niekiedy awariom. Ogólnie biorąc nadawca nie jest w stanie odróżnić awarii procesu od awarii komunikacyjnej. Jeśli proces nie odpowiada pomimo wykonania ustalonej liczby N prób skomunikowania się z nim, to zakłada się, że jest nieosiągalny. Wybór N jest trudny: jeśli będzie za małe, to można omyłkowo uznać proces za uszkodzony, natomiast gdy N będzie za duże to czas potrzebny na wykrycie uszkodzenia może stać się zbyt długi. • Nie ma uszkodzeń danych. Komunikaty są odbierane poprawnie – zapewniają to mechanizmy wykrywania błędów na poziomie sieci.
Katedra Informatyki Protokoły wymiany RPC • Protokół zamówienia (request – R). Może być używany w sytuacji, gdy procedura zdalna nie musi zwracać żadnej wartości, a klient nie wymaga potwierdzenia, że ją wykonano. Klient może kontynuować działanie natychmiast po wysłaniu komunikatu z zamówieniem, gdyż nie musi czekać na komunikat z odpowiedzią. • Protokół zamówienie – odpowiedź (request-reply – RR). Polega na wymianie pary komunikatów zamówienie – odpowiedź. Nie są wymagane komunikaty potwierdzające, gdyż za potwierdzenie zamówienia klienta służy odpowiedź serwera. • Protokół zamówienie – odpowiedź – potwierdzenie (request-reply-acknowledge reply – RRA).Zakłada wymianę trzech komunikatów, z dodatkowym potwierdzeniem od klienta do serwera. Komunikat potwierdzający odpowiedź zawiera identyfikator zamówienia, wzięty z odpowiedzi. Jego nadejście powoduje potraktowanie przez serwer wszystkich odpowiedzi o mniejszych identyfikatorach zamówień jako potwierdzonych. Tak więc zgubienie jakiegoś potwierdzenia jest nieszkodliwe.
Katedra Informatyki Problemy gwarancji dostaw • Na wypadek awarii serwera, lub zagubień komunikatów z zamówieniami lub odpowiedziami, namiastka klienta powinna stosować odliczanie czasu przy czekaniu na odpowiedź od serwera. • Po wyczerpaniu czasu oczekiwania namiastka klienta może przerwać swoje działanie i wrócić do klienta, przekazując informację, że operacja się nie powiodła. Zazwyczaj jednak powtarza ona (retransmituje) wysyłanie komunikatu zamawiającego do czasu aż skończy się to powodzeniem lub stanie się prawie pewne, że opóźnienie wynika z braku odpowiedzi od serwera, a nie z zaginięcia komunikatu. • W przypadku retransmitowania komunikatu z zamówieniem, serwer może go otrzymać więcej niż jeden raz, a więc może wykonać operację kilkukrotnie. Jest to dopuszczalne jeśli operacja realizowana przez serwer jest idempotentna, tzn. wykonanie wielokrotne ma taki sam skutek jak jednokrotne.
Katedra Informatyki Problemy gwarancji dostaw • Jeśli powtórki komunikatów dochodzą do serwera podczas realizacji zadania (ponieważ jego wykonanie jest bardziej czasochłonne niż limit czasu przewidziany przez klienta), to aby uniknąć powtórzenia operacji, serwer może implementować protokół rejestracji i rozpoznawania zamówień tego samego klienta, w celu odfiltrowania duplikatów o takim samym identyfikatorze zamówienia. Duplikaty będą ignorowane, odpowiedź przesłana po zakończeniu zadania. • Jeśli powtórne zamówienie dochodzi po wysłaniu odpowiedzi, serwer może korzystać z rejestru (historii) odpowiedzi. Wyszukując odpowiedź na zamówienie o danym identyfikatorze od danego klienta, serwer retransmituje ponownie komunikat z odpowiedzią, bez konieczności powtórnej realizacji zadania. • Strategia ta może być kosztowna pod względem alokacji zasobów. Zazwyczaj serwer przechowuje tylko ostatnią odpowiedź dla danego klienta – przyjście od klienta nowego zamówienia traktowane jest jako potwierdzenie otrzymania odpowiedzi na poprzednie. • Jeśli klient nie zgłasza nowych zadań, komunikaty z rejestru odpowiedzi usuwane są ponadto po upływie określonego czasu.
Katedra Informatyki Semantyki niezawodności wywołań RPC • Semantyka wywołania ewentualnego. Nie zakłada tolerowania uszkodzeń. Jeśli komunikat z odpowiedzią nie nadejdzie po wyznaczonym czasie i nie ponawia się prób, to nie ma pewności czy procedura została wykonana. Nie wiadomo bowiem, czy zaginął komunikat z zamówieniem lub awarii uległ serwer, czy też wykonanie doszło do skutku, a zaginął komunikat z odpowiedzią. Na ogół trudno taką semantykę zaakceptować. • Semantyka wywołania co najmniej jednokrotnego. Retransmitowanie komunikatów odbywa się bez odfiltrowania powtórzeń, tak więc serwer może go otrzymać i wykonać więcej niż raz. Klient w końcu otrzyma odpowiedź, albo zostanie poinformowany, że serwer uległ awarii. Po zakończeniu wywołania RPC serwer nie będzie wiedział ile razy je wykonano. Semantyka ta jest do przyjęcia, jeśli wszystkie procedury serwera mogą być zaprojektowane za pomocą działań idempotentnych.
Katedra Informatyki Semantyki niezawodności wywołań RPC • Semantyka wywołania co najwyżej jednokrotnego. Zachodzi odfiltrowywanie powtórzeń oraz retransmitowanie odpowiedzi bez ponownego wykonywania działań. Jeśli serwer nie ulegnie awarii i klient otrzyma wynik wywołania, to procedura została wykonana dokładnie jeden raz. W przeciwnym przypadku następuje sygnalizacja sytuacji wyjątkowej. Tę semantykę wybiera się zazwyczaj w implementacjach RPC, zwłaszcza do realizacji operacji nieidempotentnych.
Katedra Informatyki Sun RPC • Jednym z najbardziej znanych uniksowych systemów zdalnych wywołań procedur jest system Sun RPC. • Początkowo zaprojektowany został do komunikacji klient/serwer w sieciowym systemie plików Sun NFS. • Sun RPC jest załączane jako część rozmaitych systemów operacyjnych firmy Sun i również jest dostępne w innych instalacjach systemu NFS. • Programiści maja do wyboru użytkowanie RPC ponad protokołami UDP/IP lub TCP/IP. • System Sun RPC zawiera język opisu interfejsu nazywany XDR oraz kompilator interfejsu o nazwie rpcgen.
Katedra Informatyki Język Sun XDR • Interfejs identyfikowany jest poprzez tzw. numer programu i numer wersji. • Opis interfejsu składa się z definicji procedur, stałych oraz typów. Obok typów prostych, dopuszczalne jest definiowanie struktur, wyliczeń oraz unii. Składnia definicji typów jest taka sama jak w języku C. • Definicja procedury określa jej sygnaturę oraz numer (począwszy od 1). Numer zero zarezerwowany jest dla automatycznie generowanej procedury pustej, służącej do testowania dostępności serwera. • Dozwolony jest tylko jeden parametr wejściowy. • Zarówno typ parametru wejściowego jak i wartości powrotnej mogą mieć charakter prosty lub zmiennej strukturalnej. • Procedury wieloparametrowe muszą więc przekazywać parametry jako elementy jednej struktury.
Katedra Informatyki Język Sun XDR const MAX = 100; typedef int plik_id; typedef int plik_wsk; typedef int dlugosc; struct Dane { int len; char bufor[MAX]; }; struct pisz_arg { plik_id p; plik_wsk pozycja; Dane dane; }; struct czyt_arg { plik_id p; plik_wsk pozycja; dlugosc len; }; Program CZYTAJPISZPLIK { version WERSJA { Dane CZYTAJ(czyt_arg) = 1; void PISZ(pisz_arg) = 2; } = 2; } = 9999;
Katedra Informatyki Kompilator rpcgen Kompilator interfejsu rpcgen generuje: • Namiastki procedur klienta. • Namiastki procedur serwera, ekspedytora oraz procedurę główną (main) serwera. • Procedury XDR przetaczania i odwrotnego przetaczania danych na użytek ekspedytora oraz namiastek klienta oraz serwera. • Plik nagłówkowy o nazwie takiej samej jak nazwa interfejsu (programu), np. CzytajPiszPlik.h, z deklaracjami wspólnych zmiennych i typów do użytku w programach klienta i serwera. Sygnatury procedur usługowych podane są w postaci prototypów funkcji języka C. • Nazwy procedur są takie same jak w interfejsie, z tym że zamienia się je na małe litery, dodaje znak podkreślenia oraz numer wersji. • Argumentem każdej procedury użytkowej jest wskaźnik do jednego argumentu lub struktury zawierającej wszystkie argumenty. • Podobnie jest w przypadku wartości powrotnej – zwracany jest wskaźnik do wyniku lub struktury z wynikami.
Katedra Informatyki Program serwera • Program serwera implementuje funkcje usługowe, zgodnie z prototypami wygenerowanymi w pliku nagłówkowym przez rpcgen. • Wartość powrotna jest wskaźnikiem, musi więc być to adres zmiennej statycznej. • Moduł zawierający procedury użytkowe musi zostać skonsolidowany z wygenerowanymi przez rpcgen modułami bibliotecznymi zawierającymi funkcję main, procedurę ekspedytora, i namiastki serwera i procedury przetaczające. • Sun RPC działa bez ogólnosieciowych usług wiązania. Zamiast tego udostępnia na komputerze serwera lokalne usługi wiązania, nazywane programami odwzorowania portów (port mapper). • Funkcja main tworzy gniazdo do przyjmowania komunikatów z zamówieniami klientów, a następnie eksportuje interfejs usługi, podając lokalnemu programowi odwzorowania portów numer programu (interfejsu), numer wersji oraz identyfikator portu serwera.
Katedra Informatyki Serwer Sun RPC #include <stdio.h> #include <rpc/rpc.h> #include „CzytajPiszPlik.h” void* pisz_2(pisz_arg* a) { /* kod procedury zapisu*/ } Dane* czytaj_2(czyt_arg* a) { static Dane wynik; /*kod procedury zapisu*/ return &wynik; }
Katedra Informatyki Program klienta • Moduł zawierający procedury użytkowe musi zostać skonsolidowany z wygenerowanymi przez rpcgen modułami bibliotecznymi zawierającymi namiastki procedur klienta i procedury przetaczające. • Do pobrania interfejsu punktu końcowego serwera służy funkcja clnt_create, zwracająca uchwyt klienta zawierający informacje niezbędne do komunikacji z portem serwera. W parametrach podajemy nazwę serwera, numer programu i wersji. Funkcja ta kontaktuje się z usługami odwzorowania portu w celu pobrania pełnej informacji komunikacyjnej. Porty serwerów nie muszą więc być ogólnie znane. • Program klienta wywołuje funkcje usługowe, zgodnie z prototypami wygenerowanymi w pliku nagłówkowym przez rpcgen, rozszerzonymi o dodatkowy parametr uchwytu klienta. • Semantyka wywołania procedury serwera jest co najmniej jednokrotna. Odstęp czasu miedzy kolejnymi próbami ma wartość domyślną, którą można określić podczas uzyskiwani uchwytu.
Katedra Informatyki Klient Sun RPC #include <stdio.h> #include <rpc/rpc.h> #include „CzytajPiszPlik.h” main() { CLIENT* client_handle; char* nazwa_serw = ”kkkk”; czyt_arg a; Dane* ptr; client_handle = clnt_create(nazwa_serw, CZYTAJPISZPLIK, WERSJA, ”udp”); if ( client_handle == NULL ) { clnt_pcreateerror(nazwa_serw); exit(1); } a.p = 10; a.pozycja = 100; a.len = 1000; ptr = czytaj_2(&a, client_handle); clnt_destroy(client_handle); }
Katedra Informatyki DCE RPC • DCE (Distributed Computing Environment) jest rozproszonym środowiskiem obliczeniowym, opracowanym przez konsorcjum OSF (Open Software Foundation – obecnie Open Software Group). • DCE opracowane początkowo dla systemu UNIX zostało przeniesione do wszystkich głównych systemów operacyjnych, łącznie z systemami VMS, Windows, a także systemami operacyjnymi komputerów osobistych. • Specyfikacje DCE RPC zostały zaadaptowane przez Microsoft jako podstawowy system obliczeń rozproszonych. • Wiele modeli obiektów rozproszonych stanowi bezpośrednie rozwinięcie koncepcji zawartych w DCE RPC.
Katedra Informatyki DCE RPC • Interfejs specyfikowany jest z wykorzystaniem specjalnego języka o nazwie IDL. • Pliki IDL zawierają deklaracje prototypów funkcji specyfikowane w formie zbliżonej do składni języka C. Zawierać mogą również deklaracje typów, stałych oraz informacje inne potrzebne do przetaczania parametrów i wyników. • Interfejs DCE RPC identyfikowany jest przez jednoznaczny identyfikator UID, składający się ze 128 bitowej liczby dwójkowej. Identyfikatory UID generowane są przez generator uuidgen, na podstawie informacji o lokalizacji komputera oraz czasu. • Wiązanie w DCE RPC ma charakter lokalny, tzn. środowisko utrzymuje na maszynie serwera proces zwany demonem DCE (DCE daemon), wykonujący usługę odwzorowania portów. • Środowisko DCE dostarcza jednak również globalnych usług wiązania. Serwer RPC może zostać zarejestrowany w globalnej usłudze katalogowej.
Katedra Informatyki DCE RPC • Usługi DCE RPC realizowane mogą być na bazie różnych protokołów. • Domyślna semantyka wywołania procedury zdalnej ma charakter co najwyżej jednokrotny. • Procedura może zostać jednak oznaczona w pliku IDL jako idempotentna. Wówczas wywołana będzie co najmniej jednokrotnie.
Katedra Informatyki Przykład: Korzystanie z DCE RPC w systemie Windows • Generujemy pusty plik interfejsu przy użyciu programu uuidgen z opcją /I. W naszym przykładzie będzie to plik motd.idl. • Modyfikujemy otrzymany plik IDL, definiując interfejs usługi. • Zmieniamy nazwę interfejsu na MOTD, deklarujemy procedurę zdalną GetMOTD. Opis funkcji jest w zasadzie taki sam jak w C. W nawiasach kwadratowych informujemy kompilator interfejsu jak mają być traktowane parametry. Opisy te nazywamy atrybutami. uuid(9ebec1c7-bb8a-4063-ac06-d6441c6badea), version(1.0) ] interface MOTD { void GetMOTD([out, string, max_is(ct)] char* msg, [in] unsigned int ct); }
Katedra Informatyki Przykład: Korzystanie z DCE RPC w systemie Windows • Istnieje wiele innych atrybutów, które można użyć do opisu innych typów parametrów (np. takich jak tablice). Można również definiować własne typy. • Parametry mogą być również jednocześnie wejściowe i wyjściowe. Należy jednak robić tak jedynie w przypadku gdy rzeczywiście potrzebny nam jest przepływ danych w obie strony. Pozwoli to uniknąć przetaczania przez sieć śmieci. uuid(9ebec1c7-bb8a-4063-ac06-d6441c6badea), version(1.0) ] interface MOTD { void GetMOTD([out, string, max_is(ct)] char* msg, [in] unsigned int ct); }
Katedra Informatyki Przykład: Korzystanie z DCE RPC w systemie Windows • Tworzymy nowy, pusty plik o takiej samej nazwie jak plik IDL i rozszerzeniu ACF. Będzie on zawierał linię tworzącą niejawny uchwyt używany przez mechanizm RPC dla naszego interfejsu. [implicit_handle (handle_t MOTDHandle)] interface MOTD {}
Katedra Informatyki Przykład: Korzystanie z DCE RPC w systemie Windows • Kompilujemy stworzony interfejs z wykorzystaniem programu MIDL. Tworzy on plik nagłówkowy motd.h, który włączany będzie zarówno do kodu klienta jak i serwera, oraz dwa pliki motd_c.c (plik funkcji pośrednich po stronie klienta) i motd_s.c (funkcje pośrednie po stronie serwera). • Piszemy kod serwera. Do projektu włączamy również plik motd_s.c oraz rpcrt4.lib – bibliotekę zawierającą funkcje środowiska RPC. • Piszemy kod klienta. Konsolidujemy go z plikiem modt_c.c oraz również z biblioteką rpcrt4.lib.
Katedra Informatyki Serwer RPC dla Windows – przydatne funkcje RPC_STATUS RPC_ENTRY RpcServerUseProtseqEp( //definiuje punkt końcowy unsigned char *Protseq, // Identyfikator protokołu unsigned int MaxCalls, // Długość kolejki wywołań unsigned char *Endpoint,// Id. punktu końcowego (numer gniazda, id potoku) void *SecurityDescriptor //Deskryptor zabezpieczeń (tylko potoki) ); ProtseqIdentyfikator (tekstowy) protokołu, np. ”ncacn_np” dla nazwanych potoków, ”ncacn_ip_tcp” dla tcp. EndpointIdentyfikator (tekstowy) punktu końcowego, np. dla ”ncacn_np” identyfikator potoku, dla ”ncacn_ip_tcp” numer gniazda.
Katedra Informatyki Serwer RPC dla Windows – przydatne funkcje RPC_STATUS RPC_ENTRY RpcServerRegisterIf( //rejestracja interfejsu RPC_IF_HANDLEIfSpec, // uchwyt interfejsu (wygenerowany przez MIDL) UUID*MgrTypeUuid, // UUID menedżera interfejsu (zazwyczaj NULL) RPC_MGR_EPV*MgrEpv // Menedżer interfejsu (NULL to defaultowy // wygenerowany przez MIDL) ); RPC_STATUS RPC_ENTRY RpcServerListen( //start nasłuchiwania unsigned intMinimumCallThreads, // Min. liczba wątków serwera (zazw. 1) unsigned intMaxCalls, // Max liczba jednoczesnych k;ientów unsigned intDontWait // Zazwyczaj 0 );
Katedra Informatyki Serwer RPC dla Windows (1) #include <stdio.h> #include <stdlib.h> #include "motd.h" void main() { RPC_STATUS status; unsigned int cMaxCalls = 20; //dla gniazd //status = RpcServerUseProtseqEp((unsigned char*)"ncacn_ip_tcp", // cMaxCalls, (unsigned char*)"201", NULL); status = RpcServerUseProtseqEp((unsigned char*)"ncacn_np", cMaxCalls, (unsigned char*)"\\pipe\\MOTD", NULL); if ( status ) { exit(status); } status = RpcServerRegisterIf(MOTD_v1_0_s_ifspec, NULL, NULL); if ( status ) { exit(status); } status = RpcServerListen(1, cMaxCalls, 0); if ( status ) { exit(status); } }
Katedra Informatyki Serwer RPC dla Windows (2) void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) { return malloc(len); } void __RPC_USER MIDL_user_free( void __RPC_FAR * ptr) { free(ptr); }
Katedra Informatyki Serwer RPC dla Windows (3) static char *motd[]= { "Yawn a more Roman way", "Rats live on no evil star.", "If I had a hi-fi", "Rise to vote sir", "Evil Olive", "Never odd or even", "No lemons, no melon" }; /* Funkcja(e)*/ void GetMOTD(unsigned char __RPC_FAR *msg, unsigned int ct) { static int n=0; char tmp[1024]; sprintf(tmp,"%d: %s",++n,motd[n%(sizeof(motd)/sizeof(char *))]); strncpy((char*)msg,tmp,ct); }
Katedra Informatyki Klient RPC dla Windows – przydatne funkcje RPC_STATUS RPC_ENTRY RpcStringBindingCompose( unsigned char*ObjUuid, // Ident. interfejsu unsigned char*ProtSeq, // Ident. protokołu unsigned char*NetworkAddr, // Adres sieciowy komputera unsigned char*EndPoint, // Id. punktu końcowego unsigned char*Options, // Opcje unsigned char**StringBinding // Łańcuch połączenia (parametr wyjściowy) ); ProtseqIdentyfikator (tekstowy) protokołu, np. ”ncacn_np” dla nazwanych potoków, ”ncacn_ip_tcp” dla tcp. NetworkAddrAdres sieciowy komputera serwera, np. dla ”ncacn_np” nazwa Windows, dla ”ncacn_ip_tcp” adres IP lub nazwa domenowa. EndpointIdentyfikator (tekstowy) punktu końcowego, np. dla ”ncacn_np” identyfikator potoku, dla ”ncacn_ip_tcp” numer gniazda.
Katedra Informatyki Klient RPC dla Windows – przydatne funkcje RPC_STATUS RPC_ENTRY RpcBindingFromStringBinding( unsigned char *StringBinding, // Łańcuch połączenia RPC_BINDING_HANDLE *Binding// Adres uchwytu klienta ); RPC_STATUS RPC_ENTRY RpcStringFree( unsigned char **String ); RPC_STATUS RPC_ENTRY RpcBindingFree( RPC_BINDING_HANDLE *Binding );
Katedra Informatyki Klient RPC dla Windows (1) #include <stdio.h> #include <stdlib.h> #include "motd.h" unsigned char* pszStringBinding = NULL; RPC_STATUS RPC_init(int argc, char* argv[]) { RPC_STATUS status; unsigned char* pszNetworkAddres = NULL; if ( argc ==2 ) pszNetworkAddres = (unsigned char*)argv[1]; // Dla gniazd // status = RpcStringBindingCompose(NULL, (unsigned char*)"ncacn_ip_tcp", // pszNetworkAddres, (unsigned char*)"201", // NULL, &pszStringBinding); status = RpcStringBindingCompose(NULL, (unsigned char*)"ncacn_np", pszNetworkAddres, (unsigned char*)"\\pipe\\MOTD", NULL, &pszStringBinding); if ( status ) {return status;} status = RpcBindingFromStringBinding(pszStringBinding, &MOTDHandle); return status; }
Katedra Informatyki Klient RPC dla Windows (2) RPC_STATUS RPC_close() { RPC_STATUS status; status = RpcStringFree(&pszStringBinding); if ( status ) {return status;} status = RpcBindingFree(&MOTDHandle); return status; } void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len) { return malloc(len); } void __RPC_USER MIDL_user_free( void __RPC_FAR * ptr) { free(ptr); }
Katedra Informatyki Klient RPC dla Windows (3) void main(int argc, char* argv[]) { unsigned long ulCode; char msg[100]; RPC_STATUS status = RPC_init(argc, argv); if ( status ) { printf("Blad laczenia z RPC\n"); exit(status); } GetMOTD((unsigned char*)msg, sizeof(msg)); printf("Z serwera: %s\n", msg); status = RPC_close(); if ( status ) { exit(status);} }
Katedra Informatyki Klient RPC dla Windows (4) – Przechwytywanie wyjątków RPC void main(int argc, char* argv[]) { unsigned long ulCode; char msg[100]; RPC_STATUS status = RPC_init(argc, argv); if ( status ) { printf("Blad laczenia z RPC\n"); exit(status); } RpcTryExcept { GetMOTD((unsigned char*)msg, sizeof(msg)); printf("Z serwera: %s\n", msg); } RpcExcept(1) { ulCode = RpcExceptionCode(); printf("Runtime reported exception 0x%lx = %ld\n", ulCode, ulCode); } RpcEndExcept status = RPC_close(); if ( status ) { exit(status);} }