Systemy rozproszone

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

description

Uniwersytet Łódzki Katedra Informatyki. W. Bartkiewicz. Systemy rozproszone. Wykład 4. Komunikacja międzyprocesowa. Katedra Informatyki. Komunikacja międzyprocesowa w Unix. Pamięć dzielona Pliki odwzorowane w pamięci – Memory Mapped Files Anonimowe potoki – Anonymous Pipes - PowerPoint PPT Presentation

Transcript of Systemy rozproszone

Page 1: Systemy rozproszone

Systemy rozproszone

W. Bartkiewicz

Wykład 4. Komunikacja międzyprocesowa

Page 2: Systemy rozproszone

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

Page 3: Systemy rozproszone

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

Page 4: Systemy rozproszone

Pamięć dzielona

pamięć dzielona

pamięć fizycznalogiczna

przestrzeń adresowa procesu A

logiczna przestrzeń adresowa procesu B

Page 5: Systemy rozproszone

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.

Page 6: Systemy rozproszone

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.

Page 7: Systemy rozproszone

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.0666 – uprawnienia do wszystkiego dla wszystkich.

Page 8: Systemy rozproszone

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.

Page 9: Systemy rozproszone

Pamięć dzielona w Linux-ie. Przykładint 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;

}

Page 10: Systemy rozproszone

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.

Page 11: Systemy rozproszone

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.

Page 12: Systemy rozproszone

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.

Page 13: Systemy rozproszone

Pliki odwzorowywane w pamięciLPVOID 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

Page 14: Systemy rozproszone

Pliki odwzorowywane w pamięciint 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;

}

Page 15: Systemy rozproszone

Komunikacja sieciowa

Page 16: Systemy rozproszone

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

Page 17: Systemy rozproszone

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ć

7

6

5

4

3

2

1

Page 18: Systemy rozproszone

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

Page 19: Systemy rozproszone

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.

Page 20: Systemy rozproszone

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.

Page 21: Systemy rozproszone

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.

Page 22: Systemy rozproszone

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.

Page 23: Systemy rozproszone

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.

Page 24: Systemy rozproszone

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.

Page 25: Systemy rozproszone

Protokoły aplikacji

• Na przykład protokoły FTP, HTTP, SMTP, itd.

Page 26: Systemy rozproszone

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.

Page 27: Systemy rozproszone

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

Page 28: Systemy rozproszone

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

Page 29: Systemy rozproszone

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

Page 30: Systemy rozproszone

Potoki nazwaneHANDLE 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)

Page 31: Systemy rozproszone

Potoki nazwaneHANDLE 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

Page 32: Systemy rozproszone

Potoki nazwaneHANDLE 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.

Page 33: Systemy rozproszone

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

Page 34: Systemy rozproszone

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

Page 35: Systemy rozproszone

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

elsesprintf(nameBuf, "\\\\%s\\pipe\\MySimplePipe", argv[1]);

printf("Oczekiwanie na serwer MySimplePipe...\n");while ( WaitNamedPipe(nameBuf,1000 ) == 0 ) {

if (MessageBox(NULL, "Nie mogŕ po│╣czyŠ siŕ z serwerem", NULL, MB_RETRYCANCEL) != IDRETRY ) {

return;}

}

Page 36: Systemy rozproszone

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

Page 37: Systemy rozproszone

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 – 49151.

• 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.

Page 38: Systemy rozproszone

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.

Page 39: Systemy rozproszone

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

Page 40: Systemy rozproszone

Tworzenie gniazda IPSOCKET 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

Page 41: Systemy rozproszone

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);namestruct sockaddr {

u_short sa_family; char sa_data[14];

}; Dla TCP/IPstruct sockaddr_in {

short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8];

};

Dla TCP/IPstruct 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; };

Page 42: Systemy rozproszone

Mapowanie adresu – przydatne funkcje

adr.sin_family = AF_INET;adr.sin_port = htons(5150);

adr.sin_addr.s_addr = inet_addr("127.0.0.1");

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

Page 43: Systemy rozproszone

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

Page 44: Systemy rozproszone

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

Page 45: Systemy rozproszone

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;}

Page 46: Systemy rozproszone

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

Page 47: Systemy rozproszone

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;}

Page 48: Systemy rozproszone

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

Page 49: Systemy rozproszone

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("127.0.0.1"); 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; }

Page 50: Systemy rozproszone

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 uzgodnioneelse 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;}