Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałJustyn Roszkiewicz Został zmieniony 10 lat temu
1
12. GNIAZDA BSD Biblioteka funkcji związanych z gniazdami jest interfejsem programisty do obsługi protokołów komunikacyjnych. Została utworzona dla Unixa BSD, głównie w związku z implementacją protokołów rodziny TCP/IP. Gniazda umożliwiają komunikację zarówno między procesami umiejscowionymi w jednym komputerze (komunikację w dziedzinie Unixa), jak i między procesami w różnych komputerach (komunikację w dziedzinie Internetu). Z punktu widzenia programisty posługiwanie się funkcjami jest w obu przypadkach podobne - podstawowa różnica związana jest z adresowaniem gniazd. W przypadku komunikacji w dziedzinie Unixa gniazda (podobnie, jak łącza komunikacyjne) mogą mieć nazwy i być uwidocznione w systemie plików, lub mogą być bezimienne (nienazwane). W przypadku komunikacji w dziedzinie Internetu gniazda są identyfikowane poprzez adres IP komputera oraz numer portu. Gniazda umożliwiają łączność dwukierunkową (zarówno zapis, jak i odczyt danych).
2
Biblioteka funkcji związanych z gniazdami została zaprojektowana pod kątem tworzenia par programów typu klient - serwer (w szczególności serwerów współbieżnych). Przesyłanie informacji pomiędzy klientem a serwerem może mieć charakter połączeniowy (analogia: rozmowa telefoniczna) lub bezpołączeniowy (analogia: wysyłanie telegramów). Abstrakcją transmisji połączeniowej jest strumień danych (zapewniający zachowanie kolejności przesyłanych informacji i niezawodność ich dostarczania). Abstrakcją transmisji bezpołączeniowej jest ciąg oddzielnych pakietów informacji, tak zwanych datagramów (o ograniczonej wielkości), które mogą wędrować różnymi drogami, docierać w zmienionej kolejności, a czasem ulegać zagubieniu lub zduplikowaniu. klient serwer Protokół połączeniowy klient serwer Protokół bezpołączeniowy
3
Uwaga. 1) Protokół połączeniowy (szczególnie w przypadku połączenia między różnymi komputerami) jest wielokrotnie wolniejszy od bezpołączeniowego (potwierdzenia, sprawdzanie sum kontrolnych...). 2) W przypadku protokołu bezpołączeniowego programista musi sam zabezpieczać swoje programy przed skutkami jego zawodności. 3) Zawodność transmisji bezpołączeniowej objawia się zwykle tylko w przypadku przesłań pomiędzy oddzielnymi komputerami (i to nie w obrębie jednej sieci lokalnej). Typowym przykładem protokołu połączeniowego jest TCP (Transmission Control Protocol), protokołu bezpołączeniowego - UDP (User Datagram Protocol), oba działające na bazie (bezpołączeniowego) protokołu niższego poziomu IP (Internet Protocol).
4
Podstawowe funkcje operujące na gniazdach Typowa kolejność wywoływania funkcji w przypadku transmisji połączeniowych i bezpołączeniowych (wg W.R. Stevensa): serwer socket ( ); bind ( ); listen ( ); accept ( ); read ( ); przetwarzanie danych write ( ); klient socket ( ); connect ( ); write ( ); read ( ); oczekiwanie na uzys- kanie połączenia oczekiwanie na wyniki a) transmisja połączeniowa dane wyniki
5
serwer socket ( ); bind ( ); recvfrom ( ); przetwarzanie danych sendto ( ); klient socket ( ); bind ( ); sendto ( ); recvfrom ( ); oczekiwanie na dane oczekiwanie na wyniki b) transmisja bezpołączeniowa dane wyniki Gniazda zamykamy zwykle funkcją close( ) (tak, jak zwykłe pliki).
6
Istotnym problemem dla transmisji połączeniowej pomiędzy oddzielnymi komputerami jest synchronizacja pomiędzy zapisem (write) i odczytem (read). Problem ten nie występuje dla połączeń w dziedzinie Unixa, bo zapis i odczyt są wykonywane jako niepodzielne operacje przez to samo jądro. W przypadku połączenia w dziedzinie Internetu zwykle funkcja read wykonywana jest w pętli aż do upewnienia się przez program, że już wszystkie przekazywane dane zostały przeczytane. Uwaga. Dla zapewnienia komunikacji przez gniazda procesów spokrewnionych zwykle stosujemy funkcję socketpair, która generuje deskryptory pary gniazd (podobnie, jak funkcja pipe) i od razu ustala pomiędzy nimi połączenie. Dalsze postępowanie wygląda również podobnie, jak w przypadku łącz nienazwanych (utworzenie procesów potomnych dziedziczących deskryptory, zamykanie niepo- trzebnych deskryptorów itd.).
7
int socketpair (int rodzina, int typ, int protokół, int deskr [2] ); Zwraca: 0 w przypadku sukcesu; -1 w przypadku błędu. rodzina - oznaczenie rodziny protokołów komunikacyjnych (w tym przypadku może być tylko PF_UNIX ) ( uwaga: oznaczenie AF_UNIX jest równoważne ) typ - oznaczenie typu gniazd: SOCK_STREAM (gniazdo strumieniowe) lub SOCK_DGRAM (gniazdo datagramowe) protokół - zwykle podajemy wartość 0, żeby system dobrał wartości domyślne (TCP dla strumieni, UDP dla datagramów) deskr [2] - para deskryptorów gniazd (podobnie, jak dla pary łącz nienazwanych) Działanie: tworzy parę gniazd nienazwanych i w przypadku gniazd strumieniowych otwiera połączenie pomiędzy nimi.
8
int socket ( int rodzina, int typ, int protokół ); Zwraca: deskryptor gniazda w przypadku sukcesu; -1 w przypadku błędu. Znaczenie argumentów - takie samo, jak dla funkcji socketpair. Działanie: tworzy gniazdo nienazwane podanego typu. int bind (int deskryptor, struct sockaddr adres, int długość ); Zwraca: 0 w przypadku sukcesu; -1 w przypadku błędu. deskryptor - wartość zwrócona przez funkcję socket adres - wskaźnik do struktury zawierającej adres gniazda (interpretacja zawartości tej struktury zależy od używanego protokołu)
9
długość - długość adresu gniazda (nie uwzględniając znaku pustego kończącego łańcuch) Działanie: robi z gniazda nienazwanego gniazdo nazwane (w przypadku operowania w dziedzinie Unixa umiejscawia je w strukturze plików, zaś w przypadku operowania w dziedzinie Internetu wiąże je z adresem IP danego komputera i numerem portu). Uwaga. 1) Nie ma potrzeby bezpośredniego wpisywania adresu IP własnego komputera (można to zrobić automatycznie). 2) Numer portu może być wpisany bezpośrednio (jest to wskazane w przypadku serwera, którego adres musi być ogólnie znany), lub wygenerowany automatycznie przez wpisanie wartości 0 (jest to zwykle praktykowane w przypadku klienta).
10
int listen (int deskryptor, int rozmkolejki); Zwraca: 0 w przypadku sukcesu; -1 w przypadku błędu. deskryptor - jak poprzednio rozmkolejki - maksymalny rozmiar kolejki zgłoszeń klientów (typowa wartość wynosi 5) Działanie: tworzy kolejkę dla zgłoszeń klientów chcących połączyć się z danym gniazdem. Jeśli w którymś momencie kolejka przepełni się, klienci chcący nawiązać połączenie będą otrzymywali sygnał błędu.
11
int connect (int deskryptor, struct socksddr serwadres, int długość); Zwraca: 0 w przypadku sukcesu; -1 w przypadku błędu. deskryptor - jak poprzednio serwadres - wskaźnik do struktury zawierającej adres gniazda serwera (o postaci zależnej od używanego protokołu) długość - długość adresu gniazda serwera Działanie: spowodowanie (jeśli to możliwe) wpisania zgłoszenia klienta do kolejki serwera, a następnie nawiązanie połączenia pomiędzy gniazdem klienta a gniazdem serwera.
12
int accept (int deskryptor, struct sockaddres kliadres, int długość); Zwraca: nową wartość deskryptora gniazda w przypadku sukcesu; -1 w przypadku błędu. deskryptor - jak poprzednio kliadres - wskaźnik do struktury, do której w wyniku wykonania funkcji zostanie wpisany adres gniazda klienta, którego żądanie połączenia oczekuje jako najwcześniejsze w kolejce długość - w wyniku wykonania funkcji zostaje tu wpisana długość adresu gniazda klienta Działanie: jeśli kolejka jest pusta, proces serwera zostaje zawieszony. Kiedy w kolejce pojawią się zgłoszenia, pobrane jest najwcześniejsze z nich, utworzone jest nowe gniazdo serwera i połączone jest z gniazdem klienta (którego adres gniazda i jego długość są zwracane przez drugi i trzeci argument funkcji).
13
int sendto (int deskryptor, char bufor, int wielkość, int flagi, strust sockaddr adres, int długość); Zwraca: liczbę faktycznie wysłanych bajtów w przypadku sukcesu; -1n w przypadku błędu. deskryptor - jak poprzednio bufor - wskaźnik do bufora zawierającego dane do wysłania wielkość - liczba bajtów danych flagi - różne znaczenia (mogą na przykład nadać danym wyższy priorytet) adres - wskaźnik do struktury zawierającej adres gniazda odbiorcy długość - długość adresu gniazda odbiorcy Działanie: wysyła porcję informacji zgromadzonej w buforze z gniazda o danym deskryptorze do gniazda o podanym adresie
14
int recvfrom (int deskryptor, char bufor, int wielkość, int flagi, struct sockaddr adres, int długość); Zwraca: liczbę faktycznie odebranych bajtów w przypadku sukcesu; -1 w przypadku błędu. deskryptor - jak poprzednio bufor - wskaźnik do bufora przeznaczonego do przyjęcia danych wielkość - rozmiar tego bufora flagi - różne znaczenia (mogą na przykład spowodować skopiowanie zamiast przeniesienia danych do bufora) adres - wskaźnik do struktury, do której w wyniku wykonania funkcji zostaje wpisany adres gniazda nadawcy długość - wskaźnik do zmiennej, do której w wyniku działania funkcji zostaje wpisana długość adresu gniazda nadawcy Działanie: zawiesza proces odbiorcy, jeśli nie ma żadnych danych do odebrania. Jeśli są, pobiera do bufora dane wysłane do gniazda o danym deskryptorze. Adres gniazda nadawcy i jego długość zostają zwrócone przez dwa ostatnie argumenty funkcji.
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.