Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Systemy rozproszone W. Bartkiewicz Wykład 4. Komunikacja międzyprocesowa.

Podobne prezentacje


Prezentacja na temat: "Systemy rozproszone W. Bartkiewicz Wykład 4. Komunikacja międzyprocesowa."— Zapis prezentacji:

1 Systemy rozproszone W. Bartkiewicz Wykład 4. Komunikacja międzyprocesowa

2 Komunikacja międzyprocesowa w Unix Pamięć dzielona Pliki odwzorowane w pamięci – Memory Mapped Files Anonimowe potoki – Anonymous Pipes Nazwane potoki – Named Pipes Kolejki komunikatów Gniazda – Sockets Zdalne wywołania procedur – Remote Procedure Call, RPC

3 Komunikacja międzyprocesowa w MS Windows Komunikaty WM COPYDATA Schowek Windows Pamięć dzielona bibliotek DLL Pliki odwzorowane w pamięci – Memory Mapped Files Anonimowe potoki – Anonymous Pipes Nazwane potoki – Named Pipes Gniazda poczty – Mailslots Dynamiczna wymiana danych – Dynamic Data Exchange, (Net)DDE NetBios Gniazda – Sockets Zdalne wywołania procedur – Remote Procedure Call, RPC COM, DCOM – (Distributed) Component Object Model MSMQ – Microsoft Message Queue

4 Pamięć dzielona pamięć dzielona pamięć fizyczna logiczna przestrzeń adresowa procesu A logiczna przestrzeń adresowa procesu B

5 Właściwości pamięci dzielonej Pamięć dzielona jest specjalnym zakresem adresów tworzonym przez mechanizmy IPC na użytek jednego procesu i odwzorowanym w jego przestrzeni adresowej. Inne procesy mogą następnie dołączyć segment pamięci dzielonej do swoich przestrzeni adresowych. Wszystkie procesy mogą używać pamięci dzielonej zupełnie tak samo, zazwyczaj w sposób zbliżony jak pamięci dynamicznej (np.. Przydzielonej przez malloc). Jeżeli jeden proces dokona zapisu do pamięci dzielonej, zmiany stają się natychmiast widoczne dla wszystkich innych procesów mających do niej dostęp. Pamięć dzielona nie udostępnia żadnych mechanizmów synchronizacji. Nie ma możliwości aby automatycznie zapobiegać odczytywaniu pamięci przez jeden proces, zanim inny zakończy ją zapisywać. Odpowiedzialność do synchronizacji dostępu spoczywa więc na programiście.

6 Tworzenie pamięci dzielonej (Linux) Funkcje wykorzystywane do utworzenia regionu wspólnej pamięci: –Utworzenie pamięci dzielonej: shmget. –Odwzorowanie segmentu pamięci wspólnej w przestrzeń adresową procesu i uzyskanie wskaźnika, którego można użyć odwołując się do wspólnej pamięci: shmat. –Dezaktualizacja wskaźnika do pamięci: shmdt. –Zwolnienie (i ogólniej kontrolowanie) wspólnej pamięci: shmctl. –Nagłówki syst/shm.h, sys/ipc.h.

7 Tworzenie pamięci dzielonej (Linux) int shmget( key_t key, // klucz (identyfikator) pamięci dzielonej – liczba całkowita size_t size, // rozmiar pamięci dzielonej int shmflag // flagi tworzenia segmentu pamięci dzielonej ); shmflag Alternatywa bitowa IPC_CREAT i wybranych znaczników zezwoleń, np.: S_IRUSR, S_IWUSR – prawo do odczytu, zapisu przez właściciela (proces tworzący). S_IROTH, S_IWOTH – prawo do odczytu, zapisu przez innych – uprawnienia do wszystkiego dla wszystkich.

8 Tworzenie pamięci dzielonej (Linux) void* shmat( int shm_id, // identyfikator pamięci dzielonej (zwracany przez shmget) const void* shm_addr, // adres segmentu (0 – decyduje system) int shmflag // flagi tworzenia segmentu pamięci dzielonej ); shmflag Zazwyczaj 0. SHM_RND – jeśli shm_addr różne od 0 zaokrąglanie w dół wartości adresu shm_addr do wielokrotności rozmiaru strony. SHM_RDONLY – dostęp wyłącznie do odczytu.

9 Pamięć dzielona w Linux-ie. Przykład int main( ) { int seg_id; char* base; char buf[256]; seg_id = shmget(1234, 4096, 0666 | IPC_CREAT); if ( seg_id == -1 ) exit(1); base = (char*)shmat(seg_id, 0, 0); if ( base == (void*)-1 ) exit(1); printf("quit - wyjscie\n"); printf(">tekst - wprowadzanie do pamieci wspolnej\n"); printf("< - wyswietlenie pamieci wspolnej\n"); do { printf("OK: "); gets(buf); if ( buf[0] == '>' ) { strcpy(base, buf+1); printf("Zmieniono zawartosc pamieci wspolnej\n"); } else if ( buf[0] == '<' ) printf("%s\n", base); } while ( strcmp(buf, "quit") ); shmdt(base); shmctl(seg_id, IPC_RMID, 0); return 0; }

10 Pamięć dzielona w MS Windows. Pliki odwzorowywane w pamięci MS Windows posiada mechanizm, pozwalający odwoływać się do zawartości pliku, bezpośrednio poprzez pewien przyporządkowany mu obszar pamięci (na podobnych zasadach jak np. w przypadku pliku wymiany). Pliki odwzorowywane w pamięci (Memory Mapped Files) stanowią oficjalny sposób tworzenia pamięci wspólnej w systemie Windows. Dwa procesy mogą współdzielić plik przez obiekt odwzorowania pliku, co umożliwia im wspólną komunikację. Aby uniknąć obniżenia wydajności wynikającego z dostępu do pamięci zewnętrznej, Jako uchwytu odwzorowywanego pliku możemy użyć INVALID_HANDLE_VALUE, co spowoduje, że strony pamięci tak naprawdę nie będą łączone z żadnym plikiem dyskowym (poza plikiem wymiany), a jedynie dostępne będą dla różnych procesów poprzez uchwyt odwzorowania.

11 Pliki odwzorowywane w pamięci Funkcje wykorzystywane do utworzenia regiony wspólnej pamięci: –Utworzenie instancji odwzorowania pliku: CreateFileMapping. –Uzyskanie wskaźnika, którego można użyć odwołując się do wspólnej pamięci: MapViewOfFile lub MapViewOfFileEx. –Dezaktualizacja wskaźnika do pamięci: UnmapViewOfFile. –Zwolnienie wspólnej pamięci: CloseHandle z uchwytem uzyskanym przez CreateFileMapping. Funkcje wykorzystywane do odwołania się do wspólnej pamięci z innych procesów: –Otworzenie obszaru wspólnej pamięci: OpenFileMapping. Nazwa odwzorowania pliku musi być taka sama jak w CreateFileMapping. –Uzyskanie wskaźnika, którego można użyć odwołując się do wspólnej pamięci: MapViewOfFile lub MapViewOfFileEx. –Dezaktualizacja wskaźnika do pamięci: UnmapViewOfFile. –Zwolnienie wspólnej pamięci: CloseHandle z uchwytem uzyskanym przez OpenFileMapping.

12 Pliki odwzorowywane w pamięci HANDLE CreateFileMapping( HANDLE hFile, // uchwyt do pliku LPSECURITY_ATTRIBUTES lpAttributes, // bezpieczeństwo DWORD flProtect, // ochrona DWORD dwMaximumSizeHigh,// wyższy DWORD rozmiaru DWORD dwMaximumSizeLow, // niższy DWORD rozmiaru LPCTSTR lpName // nazwa obiektu ); flProtect Flagi statusu ochrony pamięci przydzielonej plikowi odwzorowanemu. Podstawowe wartości, jakie mogą być tu użyte: PAGE_READONLY, PAGE_READWRITE i PAGE_WRITECOPY.

13 Pliki odwzorowywane w pamięci LPVOID MapViewOfFile( HANDLE hFileMappingObject, // uchwyt do obiektu odwzorowania DWORD dwDesiredAccess, // tryb dostępu DWORD dwFileOffsetHigh, // wyższy DWORD przesunięcia DWORD dwFileOffsetLow, // niższy DWORD przesunięcia SIZE_T dwNumberOfBytesToMap // liczba bajtów do odwzorowania ); dwDesiredAccess określenie trybu dostępu do odwzorowanego pliku: FILE_MAP_WRITE, FILE_MAP_READ, FILE_MAP_ALL_ACCESS, FILE_MAP_COPY

14 Pliki odwzorowywane w pamięci int main(int argc, char* argv[]) { HANDLE map; char* base; char buf[256]; map = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, "MySharedMemory"); if ( !map ) exit(1); base = (char*)MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0); if ( !base ) exit(1); printf("quit - wyjscie\n"); printf(">tekst - wprowadzanie do pamieci wspolnej\n"); printf("< - wyswietlenie pamieci wspolnej\n"); do { printf("OK: "); gets(buf); if ( buf[0] == '>' ){ strcpy(base, buf+1); printf("Zmieniono zawartosc pamieci wspolnej\n"); } else if ( buf[0] == '<' ) printf("%s\n", base); } while ( strcmp(buf, "quit") ); UnmapViewOfFile(base); CloseHandle(map); return 0; }

15 Komunikacja sieciowa

16 Protokoły Protokoły – zbiory reguł rządzących formatem, treścią i znaczeniem wysyłanych i przyjmowanych komunikatów. Aby komputery w systemie rozproszonym mogły się komunikować ze sobą poprzez sieć, należy uzgodnić protokoły, których będą używać. –W protokołach połączeniowych nadawca i odbiorca przed wysłaniem danych jawnie nawiązują połączenie i ewentualnie negocjują protokół, którego będą używać. Kiedy kończą, muszą zakończyć połączenie. –Protokołach bezpołączeniowe nie wymagają żadnych czynności wstępnych. Nadawca wysyła pierwszy komunikat, gdy jest do tego gotowy. Model wzorcowy połączeń w systemach otwartych (Open Systems Interconnection Reference Model), tzw. model ISO OSI definiuje siedem warstw modelu komunikacji. Zbiór wszystkich protokołów wykonujących w danym systemie zadania na poszczególnych poziomach komunikacji nazywamy stosem protokołów (protocol stack) lub kompletem protokołów (protocol suite).

17 Warstwy i protokoły w modelu OSI Zastosowanie Prezentacja Sesja Transport Sieć Łącze danych Poziom fizyczny Protokół aplikacji Protokół prezentacji Protokół sesji Protokół transportu Protokół sieci Protokół łącza danych Protokół fizyczny Sieć

18 Budowa komunikatu sieciowego Komunikat Nagłówek warstwy łącza danych Nagłówek warstwy zastosowań Nagłówek warstwy prezentacji Nagłówek warstwy sesji Nagłówek warstwy transportu Nagłówek warstwy sieciowej Ogon warstwy łącza danych

19 Protokoły niższego poziomu Warstwa fizyczna. –Standaryzuje parametry interfejsów elektrycznych, mechanicznych i sygnalizacyjnych (np. napięcie dla poszczególnych stanów binarnych, szybkość transmisji, transmisja jedno i dwukierunkowa, rozmiar i kształt złącza sieciowego (wtyku), liczba i znaczenie igieł, itp.). –Wiele standardów dla różnych nośników. Np. standard RS-232-C linii komunikacji szeregowej. Warstwa łącza danych. –Grupuje dane w pakiety (ramki), odpowiada za ich bezbłędne przekazywanie. –Dodanie specjalnego szablonu bitów na początku i na końcu każdej ramki w celu jej oznaczenia. –Obliczanie i sprawdzanie sumy kontrolnej.

20 Protokoły niższego poziomu Warstwa sieciowa. –Odpowiada za przesyłanie pakietów danych. Podstawowym zadaniem warstwy sieciowej jest określenie trasy w sieci rozległej. –Bezpołączeniowy protokół sieciowy to np. IP. Pakiet IP jest wysyłany beż żadnych przygotowań i kierowany do miejsca przeznaczenia trasą wyznaczaną niezależnie od innych pakietów. Nie wybiera się, ani nie zapamiętuje żadnej wewnętrznej drogi. –Przykładem protokołu połączeniowego może być kanał wirtualny w sieciach ATM.

21 Protokoły transportowe Warstwa transportu tworzy ostatnią część tego, co można nazwać podstawowym stosem protokołów sieciowych, przekształcając znajdującą się pod nią sieć w coś, czego może używać budowniczy aplikacji. Zadaniem warstwy transportu jest obsługa przesyłu komunikatów. Jest to najniższy poziom na którym obsługiwane są komunikaty, a nie pakiety. Komunikaty adresuje się do portów komunikacyjnych. Po otrzymaniu komunikatu od warstwy aplikacji, warstwa transportu przed wysłaniem dzieli dzieli go na pakiety, przydzielając im numer porządkowy. Wymiana informacji w nagłówku warstwy transportu dotyczy kontroli wysyłek pakietów, ich odbioru, ilości wolnego miejsca pozostałego u odbiorcy, niezbędnych retransmisji, itp.

22 Protokoły transportowe Transportowe protokoły połączeniowe, zapewniające niezawodność połączenia transportowego, mogą być budowane na szczycie połączeniowych lub bezpołączeniowych usług sieciowych. W pierwszym przypadku wszystkie pakiety nadchodzą we właściwej kolejności (jeśli nadchodzą w ogóle), w drugim natomiast oprogramowanie warstwy transportu porządkuje nadchodzące pakiety, tak by zachować ich kolejność. Przykładem takiego rozwiązania jest połączeniowy internetowy protokół transportowy TCP, zbudowany na bezpołączeniowym protokole IP. Kombinacja TCP/IP stanowi obecnie de facto standard komunikacji sieciowej. Przykładem bezpołączeniowego protokołu transportowego może być protokół UDP.

23 Protokoły sesji Warstwa sesji jest w istocie poszerzoną wersją warstwy transportu. Umożliwia kontrolę dialogu kontaktujących się stron, dostarcza środków synchronizacji i wykonuje obsługę błędów. W praktyce warstwą sesji interesuje się niewiele aplikacji, toteż jej występowanie jest rzadkie. Nie ma jej w zestawie protokołów internetowych.

24 Protokoły prezentacji Protokoły na tym poziomie umożliwiają przesyłanie danych w reprezentacji sieciowej, niezależnej od reprezentacji używanych w poszczególnych komputerach. Na żądanie w tej warstwie dokonuje się również szyfrowania.

25 Protokoły aplikacji Na przykład protokoły FTP, HTTP, SMTP, itd.

26 Komunikacja oparta na komunikatach Komunikacja trwała (persistent) – komunikat przedłożony do przesłania odbiorcy jest pamiętany przez system tak długo, jak trzeba aby dostarczyć go odbiorcy. Aplikacja nadawcza nie musi kontynuować działania po przedłożeniu komunikatu. Aplikacja odbiorcza również nie musi działać w czasie przedłożenia komunikatu. Komunikacja przejściowa – komunikat przechowywany jest w systemie tylko na czas działania aplikacji nadawczej i odbiorczej.

27 Komunikacja przejściowa oparta na komunikatach Wiele systemów rozproszonych budowanych jest bezpośrednio powyżej prostego modelu opartego na komunikatach, oferowanego przez warstwę transportu. Przykładami interfejsów systemowych do tego typu usług mogą być: –Potoki nazwane (MS Windows). –Gniazda (wieloplatformowy).

28 Potoki nazwane (Named Pipes) Prosty mechanizm komunikacji sieciowej między procesami. Zalety: –Niezależność od protokołu sieciowego. –Wykorzystanie uprawnień dostępu systemu Windows. Identyfikacja potoków nazwanych w oparciu o format UNC: \\server\pipe\[path]name Dwa tryby komunikacji w oparciu o potoki nazwane: –Tryb strumieniowy (byte mode). –Tryb oparty na komunikatach (message mode).

29 Potoki nazwane Serwery potoków nazwanych w systemach Windows: NT/2000/XP. Klienty potoków nazwanych w systemach Windows: 95/98/Me/NT /2000/XP. Typowe operacje wykonywane przez serwer potoku nazwanego: –Utworzenie instancji potoku nazwanego: funkcja CreateNamedPipe(... ). –Oczekiwanie na połączenie klienta: funkcja ConnectNamedPipe(... ). –Czytanie i wysyłanie danych z/do potoku: np. funkcje ReadFile(... ), WriteFile(... ). –Zamknięcie połączenia: funkcja DisconnectNamedPipe(... ). –Zamknięcie uchwytu potoku: funkcja CloseHandle(... ). Typowe operacje wykonywane przez klienta potoku nazwanego: –Oczekiwanie aż instancja potoku stanie się dostępna: funkcja WaitNamedPipe(... ). –Połączenie z potokiem: funkcja CreateFile(... ). –Czytanie i wysyłanie danych z/do potoku: np. funkcje ReadFile(... ), WriteFile(... ). –Zamknięcie sesji potoku: funkcja CloseHandle(... ).

30 Potoki nazwane HANDLE CreateNamedPipe ( LPCTSTR lpName, / / nazwa potoku DWORD dwOpenMode, / / tryb otwarcia potoku DWORD dwPipeMode, / / tryb pracy potoku ( np. byte, message ) DWORD nMaxInstances, / / maksymalna liczba instancji potoku DWORD nOutBufferSize, / / rozmiar bufora wyjściowego DWORD nInBufferSize, / / rozmiar bufora wejściowego DWORD nDefaultTimeOut, / / domyślny time-out operacji LPSECURITY_ATTRIBUTES lpSecurityAttributes / / SD ) ; dwOpenMode PIPE_ACCESS_INBOUND – serwer w trybie czytania z potoku, klient musi otworzyć plik w trybie GENERIC WRITE PIPE_ACCESS_OUTBOUND – serwer w trybie pisania do potoku, klient musi otworzyć plik w trybie GENERIC READ PIPE_ACCESS_DUPLEX – potok dwukierunkowy, klient może otworzyć plik w trybie GENERIC WRITE i/lub GENERIC READ FILE_FLAG_WRITE_THROUGH – funkcje zapisu do potoku wstrzymują działania do momentu, gdy dane nie znajdą się w buforze po stronie odbiorcy (tylko gdy serwer i klient na różnych komputerach)

31 Potoki nazwane HANDLE CreateNamedPipe ( LPCTSTR lpName, / / nazwa potoku DWORD dwOpenMode, / / tryb otwarcia potoku DWORD dwPipeMode, / / tryb pracy potoku ( np. byte, message ) DWORD nMaxInstances, / / maksymalna liczba instancji potoku DWORD nOutBufferSize, / / rozmiar bufora wyjściowego DWORD nInBufferSize, / / rozmiar bufora wejściowego DWORD nDefaultTimeOut, / / domyślny time-out operacji LPSECURITY_ATTRIBUTES lpSecurityAttributes / / SD ) ; dwOpenMode PIPE_TYPE_BYTE – potok typu strumieniowego, dane zapisywane w postaci strumienia bajtów, nie można łączyć z PIPE_READMODE_MESSAGE PIPE_TYPE_MESSAGE – potok oparty na komunikatach, dane zapisywane w postaci komunikatów, można łączyć z PIPE_READMODE_MESSAGE lub PIPE_READMODE_BYTE PIPE_READMODE_BYTE – dane odczytywane z potoku w postaci strumienia bajtów, można używać z PIPE_TYPE_BYTE lub PIPE_TYPE_MESSAGE PIPE_READMODE_MESSAGE – dane odczytywane z potoku w postaci komunikatów, można używać tylko z lub PIPE_TYPE_MESSAGE

32 Potoki nazwane HANDLE CreateNamedPipe ( LPCTSTR lpName, / / nazwa potoku DWORD dwOpenMode, / / tryb otwarcia potoku DWORD dwPipeMode, / / tryb pracy potoku ( np. byte, message ) DWORD nMaxInstances, / / maksymalna liczba instancji potoku DWORD nOutBufferSize, / / rozmiar bufora wyjściowego DWORD nInBufferSize, / / rozmiar bufora wejściowego DWORD nDefaultTimeOut, / / domyślny time-out operacji LPSECURITY_ATTRIBUTES lpSecurityAttributes / / SD ) ; Czyli np. można łączyć: PIPE_TYPE_MESSAGE i PIPE_READMODE_BYTE, ale nie: PIPE_TYPE_BYTE i PIPE_READ_MODE_MESSAGE. Gdy z potoku działającego w trybie komunikatów odebrano mniej danych ni˙z wysłano, ReadFile generuje błąd ERROR_MORE_DATA. Dla trybu strumieniowego ReadFile odczytuje tylko tyle ile zadeklarowano, dalszą część danych poprzez kolejne wywołanie ReadFile.

33 Potoki nazwane - serwer (1) void main() { HANDLE pipeHandle; DWORD bytesRead; char buf[256]; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; sa.nLength = sizeof(sa); sa.bInheritHandle = FALSE; InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.lpSecurityDescriptor = &sd; pipeHandle = CreateNamedPipe("\\\\.\\pipe\\MySimplePipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 0, 0, 1000, &sa); if ( pipeHandle == INVALID_HANDLE_VALUE ) { printf("Funkcja 'CreateNamedPipe' zakończona bledem: %d\n", GetLastError()); return; } printf("Serwer uruchomiony...\n");

34 Potoki nazwane - serwer (2) if ( ConnectNamedPipe(pipeHandle, NULL) == 0 ) { printf("Funkcja 'ConnectNamedPipe' zakończona bledem: %d\n", GetLastError()); CloseHandle(pipeHandle); return; } if ( ReadFile(pipeHandle, buf, sizeof(buf), &bytesRead, NULL) <= 0 ) { printf("Funkcja 'ReadFile' zakończona bledem: %d\n", GetLastError()); CloseHandle(pipeHandle); return; } printf("%d %s\n", bytesRead, buf); if ( DisconnectNamedPipe(pipeHandle) == 0 ) { printf("Funkcja ' DisconnectNamedPipe' zakończona bledem: %d\n", GetLastError()); CloseHandle(pipeHandle); return; } CloseHandle(pipeHandle); printf("Nacisnij Enter...\n"); getchar(); }

35 Potoki nazwane - klient (1) void main(int argc, char* argv[]) { HANDLE pipeHandle; DWORD bytesWritten; char nameBuf[256]; if ( argc == 1 ) sprintf(nameBuf, "\\\\%s\\pipe\\MySimplePipe", "."); else sprintf(nameBuf, "\\\\%s\\pipe\\MySimplePipe", argv[1]); printf("Oczekiwanie na serwer MySimplePipe...\n"); while ( WaitNamedPipe(nameBuf,1000 ) == 0 ) { if (MessageBox(NULL, "Nie mogŕ poczyŠ siŕ z serwerem", NULL, MB_RETRYCANCEL) != IDRETRY ) { return; }

36 Potoki nazwane - klient (2) pipeHandle = CreateFile(nameBuf, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( pipeHandle == INVALID_HANDLE_VALUE ) { printf("Funkcja 'CreateFile' zako˝czona bledem: %d\n", GetLastError()); return; } printf("Nawiazano polaczenie z serwerem MySimplePipe...\n"); if ( WriteFile(pipeHandle, "To jest test",13, &bytesWritten, NULL) == 0 ) { printf("Funkcja 'WriteFile' zako˝czona bledem: %d\n", GetLastError()); CloseHandle(pipeHandle); return; } printf("Zapisano %d bajtow...\n", bytesWritten); CloseHandle(pipeHandle); printf("Nacisnij Enter...\n"); getchar(); }

37 Gniazda Gniazda są standardowym mechanizmem komunikowania się poprzez sieć TCP/IP. Implementowane są więc przez niemal wszystkie systemy operacyjne, komunikacja tego typu ma więc charakter wieloplatformowy. Każde gniazdo posiada unikalny numer portu. System rezerwuje pewne numery portów dla gniazd ogólnie znanych usług (np. 80 – HTTP, 21 – FTP). Aby nie trafić na porty zajęte już przez inną aplikację lub usługę systemową, aplikacje użytkowników powinny wybierać porty z zakresu 1024 – Serwery tworzą gniazda o ogólnie znanych numerach portów. Następnie serwer nasłuchuje połączeń przychodzących przez to gniazdo. Klient po swojej stronie tworzy gniazdo o ogólnym numerze portu, przypisywanym losowo przez system. Gniazdo to następnie używane jest do nawiązania połączenia z gniazdem serwera.

38 Gniazda Połączenia z ogólnie znanym gniazdem na maszynie serwera są przechwytywane i przekierowywane do nowego gniazda o losowym numerze portu. Dzięki temu ogólnie znane gniazdo dostępne jest cały czas do obsługi nowych połączeń. Istnieje możliwość tworzenia gniazd bezpołączeniowych. Ich użycie pozwala na uzyskanie większej efektywności, ale nie gwarantuje poprawnego dostarczenia danych.

39 Gniazda – główne operacje Typowe operacje wykonywane przez serwer: –Utworzenie gniazda: funkcja socket(... ). –Związanie gniazda z adresem: funkcja bind(... ). –Nasłuchiwanie na utworzonym gnieździe: funkcja listen(... ). –Akceptacja połączenia: funkcja accept(... ). –Czytanie i wysyłanie danych z/do gniazda: np. funkcje send(... ), recv(... ). –Powiadomienie o zamknięciu połączenia: funkcja shutdown(... ). –Zamknięcie gniazda: funkcja closesocket(... ). Typowe operacje wykonywane przez klienta: –Utworzenie gniazda: funkcja socket(... ). –Odwzorowanie nazwy serwera. –Zainicjowanie połączenia: funkcja connect(... ). –Czytanie i wysyłanie danych z/do gniazda: np. funkcje send(... ), recv(... ). –Powiadomienie o zamknięciu połączenia: funkcja shutdown(... ). –Zamknięcie gniazda: funkcja closesocket(... ).

40 Tworzenie gniazda IP SOCKET socket( int af, // rodzina adresów protokołu int type, // typ protokołu int protocol // protokół ); af Dla protokołu IP musi być AF_INET type SOCK_STREAM – dla gniazda TCP SOCK_DGRAM – dla gniazda UDP protocol IPPROTO_IP (lub po prostu 0) – dla gniazda TCP IPPROTO_UDP – dla gniazda UDP

41 Związanie gniazda IP z adresem (serwer) int bind( // związanie gniazda z adresem SOCKET s, // gniazdo const struct sockaddr FAR *name, // adres int namelen // długość adresu ); name struct sockaddr { u_short sa_family; char sa_data[14]; }; Dla TCP/IP struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; Dla TCP/IP struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } s_un_b; struct { u_short s_w1,s_w2; } s_un_w; u_long s_addr; } S_un; };

42 Mapowanie adresu – przydatne funkcje adr.sin_family = AF_INET; adr.sin_port = htons(5150); adr.sin_addr.s_addr = inet_addr(" "); struct hostent *host = NULL;... host = gethostbyname("localhost"); CopyMemory(&adr.sin_addr, host->h_addr_list[0], host->h_length); adr.sin_addr.s_addr = htonl(INADDR_ANY);

43 Nasłuchiwanie i akceptacja połączeń (serwer) int listen( // przełączenie gniazda w stan nasłuchiwania SOCKET s, // gniazdo int backlog // długość kolejki połączeń oczekujących ); SOCKET accept( // akceptacja połączenia SOCKET s, // gniazdo struct sockaddr FAR *addr, // adres klienta int FAR *addrlen // długość adresu );

44 Gniazda – prosty serwer (1) int main(int argc, char **argv) { WSADATA wsd; SOCKET sListen, sClient; int iAddrSize; struct sockaddr_in local, client; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { printf("Nie mozna wczytac biblioteki Winsock!\n"); return 1; } sListen = socket(AF_INET, SOCK_STREAM, 0); if (sListen == INVALID_SOCKET) { printf("Funckja socket() zakonczona bledem: %d\n", WSAGetLastError()); return 1; } local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_family = AF_INET; local.sin_port = htons(5150); //port na ktorym nasluchujemy if (bind(sListen, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR) { printf("Funkcja bind() zakonczona bledem: %d\n", WSAGetLastError()); return 1; } listen(sListen, 2);

45 Gniazda – prosty serwer (2) int main(int argc, char **argv) {... printf("Serwer wystartowal\n"); while (1) { iAddrSize = sizeof(client); sClient = accept(sListen, (struct sockaddr *)&client, &iAddrSize); if (sClient == INVALID_SOCKET) { printf("Funkcja accept() zakonczona bledem: %d\n", WSAGetLastError()); break; } printf("Zaakceptowano klienta: %s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); ClientService(sClient); } closesocket(sListen); WSACleanup(); return 0; }

46 Nadawanie i odbiór (serwer i klient) int recv( // odbiór komunikatu SOCKET s, // gniazdo char FAR *buf, // bufor dla pobieranych danych int len, // długość bufora int flags // flagi określające sposób wywołania (zazwyczaj 0) ); int send( // wysłanie komunikatu SOCKET s, // gniazdo char FAR *buf, // bufor zawierający wysyłane dane int len, // długość bufora int flags // flagi określające sposób wywołania (zazwyczaj 0) );

47 Gniazda – prosty serwer (3) DWORD WINAPI ClientService(SOCKET sock) { char szBuff[DEFAULT_BUFFER]; int ret, nLeft, idx; while(1) { ret = recv(sock, szBuff, DEFAULT_BUFFER, 0); if (ret == 0) break; // Zamknięcie uzgodnione else if (ret == SOCKET_ERROR) { printf("Blad: %d\n",WSAGetLastError()); break; } szBuff[ret] = '\0'; printf("ODBIOR: '%s'\n", szBuff); nLeft = ret; idx = 0; while(nLeft > 0) { ret = send(sock, &szBuff[idx], nLeft, 0); if (ret == 0) break; else if (ret == SOCKET_ERROR) { printf("Blad: %d\n",WSAGetLastError()); break; } nLeft -= ret; idx += ret; } return 0; }

48 Podłączanie się do gniazda (klient) int connect( // nawiązanie połączenia z gniazdem SOCKET s, // gniazdo lokalne klienta const struct sockaddr FAR *name, // adres gniazda docelowego int namelen // długość adresu );

49 Gniazda – prosty klient (1) int main(int argc, char **argv) { WSADATA wsd; SOCKET sClient; int ret, i; char szBuffer[DEFAULT_BUFFER], szMessage[1024]; struct sockaddr_in server; struct hostent *host = NULL; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { printf("Nie mozna wczytac biblioteki Winsock!\n"); return 1; } sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sClient == INVALID_SOCKET) { printf("Blad: %d\n", WSAGetLastError()); return 1; } server.sin_family = AF_INET; server.sin_port = htons(5150); //server.sin_addr.s_addr = inet_addr(" "); host = gethostbyname("localhost"); if (host == NULL) { printf("Nie udalo sie odwzorować adresu serwera\n"); return 1; } CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length); if (connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) { printf("Blad: %d\n", WSAGetLastError()); return 1; }

50 Gniazda – prosty klient (2) while (1) { printf("OK>"); gets(szMessage); ret = send(sClient, szMessage, strlen(szMessage), 0); if (ret == 0) break; else if (ret == SOCKET_ERROR) { printf("Blad: %d\n", WSAGetLastError()); break; } printf("Wyslano %d bajtow\n", ret); ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0); if (ret == 0) break; // Zamknięcie uzgodnione else if (ret == SOCKET_ERROR) { printf("Blad: %d\n", WSAGetLastError()); break; } szBuffer[ret] = '\0'; printf("ODBIOR [%d bajtow]: '%s'\n", ret, szBuffer); } closesocket(sClient); WSACleanup(); return 0; }


Pobierz ppt "Systemy rozproszone W. Bartkiewicz Wykład 4. Komunikacja międzyprocesowa."

Podobne prezentacje


Reklamy Google