Programowanie aplikacji równoległych i rozproszonych …icis.pcz.pl/~olas/parr/wyklad4.pdfWykład...

Post on 30-Mar-2021

0 views 0 download

Transcript of Programowanie aplikacji równoległych i rozproszonych …icis.pcz.pl/~olas/parr/wyklad4.pdfWykład...

Programowanie aplikacjirównoległych i rozproszonych

Wykład 4Dr inz. Tomasz Olas

olas@icis.pcz.pl

Instytut Informatyki Teoretycznej i Stosowanej

Politechnika Czestochowska

Wykład 4 – p. 1/44

Gniazda - Wstep

Podstawa mechanizmu wejscia-wyjscia dla sieci w systemieUnix jest abstrakcyjny mechanizm znany jako gniazda (ang.socket).

Gniazdo nalezy traktowac jako jako uogólnienie mechanizmudostepu do plików udostepniajace jeden z konców łaczakomunikacyjnego.

Kazdy z komunikujacych sie ze soba procesów tworzy poswojej stronie jedno gniazdo.

Główna róznica pomiedzy deskryptorami plików i gniazdamipolega na tym, ze system operacyjny wiaze deskryptorz okreslonym plikiem lub urzadzeniem, natomiast gniazdamozna tworzyc bez wiazania ich z okreslonym adresemodbiorcy.

Gniazdo jest opisywane za pomoca kombinacji trzechatrybutów: domeny adresowej, sposobu komunikacjii protokołu sieciowego.

Wykład 4 – p. 2/44

Domena adresowa

Domena adresowa okresla domene w której bedzierealizowana komunikacja:

PF_LOCAL (PF_UNIX) - komunikacja w obrebie jednejmaszyny,PF_INET - Internet, czyli uzywamy protokołów z rodzinyTCP/IP,PF_IPX - protokoły IPX/SPX (Novell),PF_PACKET- niskopoziomowy interfejs do odbieraniapakietów w tzw. surowej (ang. raw) postaci.

Zamiennie uzywa sie notacji PF_xxx (PF - Protocol Family)oraz AF_xxx (AF - Address Family).

Wykład 4 – p. 3/44

Sposób komunikacji

Gniazda typu SOCK_STREAM- komunikacja w modelupołaczeniowym (zwykle zwiazane z protokołem TCP warstwytransportowej)

Gniazda typu SOCK_DGRAM- komunikacja w modelubezpołaczeniowym korzystajaca z tzw. datagramów (zwyklezwiazane z protokołem UDP warstwy transportowej)

Gniazda typu SOCK_RAW- komunikacja na niskim poziomie -dostep do surowych pakietów na poziomie warstwy sieciowejTCP/IP.

Wykład 4 – p. 4/44

Funkcja socketpair

Do tworzenia gniazdek w domenie unixowej moze zostacwykorzystana funkcja socketpair :#include <sys/types.h>

#include <sys/socket.h>

int socketpair(int family, int type, int protocol, int sock vec[2]);

Funkcja zwraca deskryptor gniazda.

family - oznacza domene komunikacyjna (czyli rodzine protokołów adresów) wjakiej bedzie funkcjonowac nowe gniazdo. W systemie Linux jedyna obsługiwanadomena jest PF_UNIX.

type - okresla rodzaj gniazda,

protocol - protokół z jakiego gniazdo korzysta,

sockver - gdy nie wystapi bład zostana do tej zmiennej zapisana paradeskryptorów gniazd w domenie Unixa. Otrzymuje sie w ten sposób łaczestrumieniowe z mozliwoscia dwustronnej komunikacji.

Wykład 4 – p. 5/44

Zamkniecie gniazda

Funkcje close słuzy do zamykania gniazda i konczeniapołaczenia:int close(int fd);

fd - deskryptor gniazda,wynik:

0 - w przypadku sukcesu,-1 - jesli wystapił bład.

Przy wywoływaniu funkcji close zmniejszany jest licznikodwołan do deskryptora.

Gdy proces sie konczy, system operacyjny zamyka wszystkiegniazda, które były wówczas otwarte.

Wykład 4 – p. 6/44

Przesyłanie danych

Przesyłanie danych poprzez gniazda moze odbywac sie zwykorzystaniem pieciu róznych funkcji systemowych:send/write , sendto/recvfrom , sendmsg/recvmsg ,write/read , writev/readv .Procedury send/recv , sendto/redvfrom orazsendmsg/recvmsg wymagaja aby gniazdo było przyłaczone,gdyz nie umozliwiaja podania adresu odbiorcy.

wiele dodatkowe adres informacje

buforów znaczniki partnera kontrolne

read/write

readv/writev +

send/recv +

sendto/recvfrom + +

sendmsg/recvmsg + + + +

Wykład 4 – p. 7/44

read/write

ssize_t read(int fd, void * buf, size_t count)

ssize_t write(int fd, const void * buf, size_t count)

fd - deskryptor,

buff - adres danych do odczytania/zapisania,

length - rozmiar danych do odczytania/zapisania.

wynik:liczba odczytanych/zapisanych bajtów - w przypadkusukcesu,-1 - w przypadku błedu.

Wykład 4 – p. 8/44

socketpair - przykład (1)

#include <sys/types.h>

#include <sys/socket.h>

#include <unistd.h>

#include <iostream>

const int SIZE = 40;

int main()

{

int sockets[2];

socketpair(PF_UNIX, SOCK_STREAM, 0, sockets);

int pid = fork();

if (pid == 0) { // proces potomny

close(sockets[1]);

char buf[SIZE];

sprintf(buf, "proces potomny: %d", getpid());

write(sockets[0], buf, sizeof(buf) + 1);

read(sockets[0], buf, SIZE);

close(sockets[0]);

std::cout << "#1: " << getpid() << "\n#1: " << buf << std::endl ;

}

Wykład 4 – p. 9/44

socketpair - przykład (2)

...

else

{ // proces macierzysty

close(sockets[0]);

char buf[SIZE];

read(sockets[1], buf, SIZE);

std::cout << "#0: " << getpid() << "\n#0: " << buf << std::endl ;

sprintf(buf, "proces macierzysty: %d", getpid());

write(sockets[1], buf, sizeof(buf) + 1);

close(sockets[1]);

}

return 0;

}

Wykład 4 – p. 10/44

socketpair - przykład (3)

Przykładowy rezultat działania programu:#0: 1458

#0: proces potomny: 1459

#1: 1459

#1: proces macierzysty: 1458

Wykład 4 – p. 11/44

Komunikacja bezpołaczeniowa

Wykład 4 – p. 12/44

Tworzenie gniazd

Uzytkownik identyfikuje gniazda za pomoca deskryptorów(wykorzystywanych przy kazdorazowym odwoływaniu sie dogniazda)

Funkcja socket tworzy nowe gniazdo i zwraca jegodeskryptor:int socket (int family, int type, int protocol);

family - oznacza domene komunikacyjna (czyli rodzine protokołów adresów) wjakiej bedzie funkcjonowac nowe gniazdo, np:

PF_INET - domena internetowa - siec TCP/IP,PF_UNIX - domena uniksowa - komunikacja lokalna (system plików systemuUnix),PF_APPLETALK- siec firmy Apple Computer Incorporated,

type - okresla rodzaj gniazda,

protocol - protokół z jakiego gniazdo korzysta (w przypadku 0 bedzie todomyslny protokół dla danego rodzaju gniazda).

Wykład 4 – p. 13/44

Okreslanie adresu lokalnego

Poczatkowo nowo utworzone gniazdo nie jest zwiazane zzadnym adresem lokalnym ani odległym.

Po utworzeniu gniazda serwer wiaze z nim adres lokalny zapomoca funkcji systemowej bind :int bind(int fd, struct sockaddr * my_addr, int addrlen)

fd - deskryptor gniazda,my_addr - wskaznik na strukture adresów odpowiednia dlarodziny protokołów, do której nalezy gniazdo,addrlen - rozmiar tej struktury.

Wykład 4 – p. 14/44

Struktura sockaddr

Dla domeny uniksowej:struct sockaddr_un

{

short sun_family; / * AF_UNIX * /

char sun_data; / * scie zka * /

};

Dla domeny internetowej:struct sockaddr_in

{

short sin_family; / * AF_INET * /

u_short sin_port; / * 16-bitowy numer portu * /

struct in_addr sin_addr; / * 32-bitowy internetowy * /

/ * adres hosta * /

char sin_zero[8]; / * zarezerwowane * /

};

Wykład 4 – p. 15/44

Funkcje send i sendto

ssize_t send(int s, const void * buf, size_t len, int flags);

ssize_t sendto(int s, const void * buf, size_t len, int flags,

const struct sockaddr * to, socklen_t tolen);

ssize_t recvfrom(int s, void * buf, size_t len, int flags,

struct sockaddr * from, socklen_t * fromlen);

s - deskryptor gniazda, przez które wysyłamy dane,

buf - wskaznik do bufora, który chcemy wysłac,

len - liczba bajtów bufora do wysłania,

flags - dodatkowe flagi (np. codeMSG_DONTWAIT -Przełacza funkcje w tryb nieblokujacy),

to - wskaznik do struktury zawierajacej adres odbiorcy,

addrlen - rozmiar struktury zawierajacej adres.

wynik:liczba odczytanych/zapisanych bajtów - w przypadkusukcesu,-1 - w przypadku błedu. Wykład 4 – p. 16/44

Funkcje recv i recvfrom

ssize_t recv(int s, void * buf, size_t len, int flags);

ssize_t recvfrom(int s, void * buf, size_t len, int flags,

struct sockaddr * from, socklen_t * fromlen);

s - deskryptor gniazda, przez które odbieramy dane,

buf - adres (wskaznik) bufora, który bedzie zawierał dane poich odebraniu,

len - rozmiar bufora (maksymalna liczba bajtów, która moznajednorazowo odebrac),

flags - dodatkowe flagi,

to - wwskaznik do struktury, przez która zwrócony zostanieadres nadawcy,

addrlen - rozmiar struktury zawierajacej adres.

Wykład 4 – p. 17/44

Przykład (I)

const char name[] = "my_socket";

int main()

{

int orginal_socket = socket(AF_UNIX, SOCK_DGRAM, 0);

unlink(name);

sockaddr_un server_address;

server_address.sun_family = AF_UNIX;

strcpy(server_address.sun_path, name);

bind(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address.sun_family) + sizeof(server_add ress.sun_path));

char buf[255];

while (true) {

socklen_t client_length;

recvfrom(orginal_socket, buf, sizeof(buf), 0,

(sockaddr * )&server_address, &client_length);

std::cout << buf << std::endl;

}

close(orginal_socket); return 0;

} Wykład 4 – p. 18/44

Przykład (II)

const char name[] = "my_socket";

int main(int argc, char ** argv)

{

int orginal_socket = socket(AF_UNIX, SOCK_DGRAM, 0);

sockaddr_un server_address;

server_address.sun_family = AF_UNIX;

strcpy(server_address.sun_path, name);

bind(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address.sun_family) + sizeof(server_add ress.sun_path));

sendto(orginal_socket, argv[1], sizeof(argv[1]), 0,

(sockaddr * )&server_address, sizeof(sockaddr));

close(orginal_socket);

return 0;

}

Wykład 4 – p. 19/44

Model klient serwer

Termin serwer odnosi sie do kazdego programu, który oferujeusługe dostepna poprzez siec. Serwer przyjmuje przez sieczamówienia, wykonuje usługe i zwraca wyniki zamawiajacemu.

Klientem staje sie program, który wysyła zamówienie doserwera i czeka na odpowiedz.

W przypadku modelu klient serwer kazde połaczenie sieciowejest tworzone przez klienta wysyłajacego zadania do staleoczekujacego na nie serwera.

Gniazda uzywane przez procesy klienckie nazywane sagniazdami aktywnymi (one inicjuja połaczenie), natomiastgnizda wykorzystywane w serwerach nazywane saanalogicznie gniazdami pasywnymi.

Wykład 4 – p. 20/44

Komunikacja połaczeniowa

Wykład 4 – p. 21/44

Serwer - przyjmowanie połacze n (I)

Serwer uzywa funkcji socket , bind i listen do utworzeniagniazda. Wywołanie bind wiaze gniazdo z powszechnieznanym portem protokołu, ale nie powoduje podłaczeniagniazda do zadnego odległego odbiorcy. Zamiast odległegoodbiorcy podaje sie adres uogólniajacy (ang. wildcard), bygniazdo mogło przyjmowac połaczenia od dowolnych klientów.

Po utworzeniu gniazda serwer czeka na połaczenia. W tymcelu wywołuje procedure systemowa accept .

Wykład 4 – p. 22/44

Serwer - przyjmowanie połacze n (II)

Gdy nadchodzi zadanie, system wypełnia strukture addradresem klienta, który je zgłosił.

Nastepnie system tworzy nowe gniazdo, które jest połaczone zklientem i dostarcza wywołujacemu programowi deskryptortego gniazda.

Pierwotne gniazdo nadal nie jest połaczone z zadnymkonkretnym odległym klientem i pozostaje w dalszym ciaguotwarte. Dzieki temu serwer nadal moze czekac na zadanianadchodzace za posrednictwem tego gniazda.

Wywołanie accept konczy sie po nadejsciu zadaniapołaczenia.

Serwer moze obsługiwac nadchodzace zadania po kolei, badztez współbieznie.

Wykład 4 – p. 23/44

listen

Funkcja listen ustala maksymalna długosc kolejki klientówoczekujacych na połaczenie.#include <sys/types.h>

#include <sys/socket.h>

int listen(int fd, int backlog);

fd - deskryptor gniazda,backlog - maksymalna liczba zgłoszen połaczenia zserwerem.wynik:

0 - w przypadku sukcesu,wartosc ujemna - jesli wystapił bład.

W przypadku domeny uniksowej gniazdo musi bycstrumieniowe i miec dowiazana nazwe.

W przypadku domeny internetowej, jesli gniazdo nie manazwy, to funkcja listen automatycznie je dowiaze.

Wykład 4 – p. 24/44

accept

Funkcja accept słuzy do oczekiwania na połaczenie - procesjest blokowany az do momentu nawiazania połaczenia przezklienta. W momencie nawiazania połaczenia funkcja acceptzwraca nowy deskryptor gniazda, który nastepnie jest uzywanydo komunikacji z klientem:#include <sys/types.h>

#include <sys/socket.h>

int accept(int fd, struct sockaddr * upeer_sockaddr,

int * upeer_addrlen);

fd - deskryptor gniazda,

upeer_sockaddr - wskaznik na nazwe gniazda klienta (jako dodatkowy wynik)

upeer_addrlen - rozmiar nazwy upeer_sockaddr (jako dodatkowy wynik)

wynik:0 - w przypadku sukcesu,-1 - jesli wystapił bład.

Wykład 4 – p. 25/44

Serwer - przykład (I)

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <unistd.h>

#include <iostream>

const char name[] = "my_socket";

int main()

{

int orginal_socket = socket(AF_UNIX, SOCK_STREAM, 0);

sockaddr_un server_address;

server_address.sun_family = AF_UNIX;

strcpy(server_address.sun_path, name);

unlink(name);

bind(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address.sun_family) +

sizeof(server_address.sun_path));

Wykład 4 – p. 26/44

Server - przykład (II)

listen(orginal_socket, 1);

sockaddr_un client_address;

socklen_t client_length = sizeof(client_address);

int new_socket = accept(orginal_socket, (sockaddr * )&client_address,

&client_length);

char buf[255];

read(new_socket, buf, sizeof(buf));

std::cout << buf << std::endl;

close(new_socket);

close(orginal_socket);

unlink(name);

return 0;

}

Wykład 4 – p. 27/44

Łaczenie gniazda z adresem odbiorcy

Bezposrednio po utworzeniu gniazda znajduje sie ono w stanieniepołaczonym , co oznacza, ze nie jest ono zwiazane z zadnymadresatem.

Procedura systemowa connect trwale łaczy gniazdo zadresem odbiorcy, zmieniajac jednoczesnie stan gniazda napołaczony .

W przypadku komunikacji w trybie połaczeniowym klient przedrozpoczeciem przesyłania danych za posrednictwem gniazdamusi wywołac procedure connect w celu uzyskaniapołaczenia.

Gniazda uzywane w trybie bezpołaczeniowym nie wymagajapodłaczania przed uzyciem, ale dzieki podłaczeniu moznawysyłac dane do gniazda, nie okreslajac za kazdym razemadresu odbiorcy.

Wykład 4 – p. 28/44

connect

Funkcja connect :int connect(int fd, struct sockaddr * uservaddr, int addrlen);

fd - deskryptor gniazda,uservaddr - struktura okreslajaca adres, z którym nalezyzwiazac wskazane gniazdo,addrlen - rozmiar struktury uservaddr .wynik:

0 - w przypadku sukcesu,wartosc ujemna - w przypadku błedu, np:· EBADF- fd jest nieprawidłowym deskryptorem,· ENOTSOCK- fd nie jest deskryptorem gniazda,· EISCONN- jest juz zrealizowane polaczenie.

Wykład 4 – p. 29/44

Klient - przykład

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/un.h>

#include <unistd.h>

#include <iostream>

const char name[] = "my_socket";

int main()

{

int orginal_socket = socket(AF_UNIX, SOCK_STREAM, 0);

sockaddr_un server_address;

server_address.sun_family = AF_UNIX;

strcpy(server_address.sun_path, name);

connect(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address.sun_family) + sizeof(server_add ress.sun_path));

char buf[] = "hello";

write(orginal_socket, buf, sizeof(buf));

close(orginal_socket);

return 0;

} Wykład 4 – p. 30/44

Adres sieciowy

Kazdy host w sieci ma przynajmniej dwa tylko własciwe sobieadresy:

48-bitowy adres ethernetowy (przypisywany ethernetowejkarcie sieciowej przez producenta),32-bitowy adres internetowy (tzw. numer IP). W interakcji zuzytkownikiem jest on podzielony na cztery 8-bitowe liczbydziesietne separowane kropkami. Kazda z tych liczb mozesie zawierac w przedziale od 0 do 255, choc wartoscibrzegowe sa uzywane jako wartosci specjalnegoprzeznaczenia.

Wykład 4 – p. 31/44

Numer portu

Numer portu jest liczba 16-bitowa bez znaku.

Jednoznacznie identyfikuje połaczenie sieciowe w ramachjednego adresu IP.

Para (adres IP, numer portu) jednoznacznie okresla komputerw sieci, jak równiez konkretny proces działajacy na tymkomputerze.

Wykład 4 – p. 32/44

Funkcja gethostbyname (I)

W przypadku domeny internetowej procesy muszadysponowac swoimi adresami hostów i numerami portów, abymogły ze soba nawiazac kontakt.

Funkcja gethostbyname zwraca pełne informacje o hoscie,którego nazwe podano w argumentach:#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

hostent * gethostbyname(const char * name);

name - wskaznik na napis zawierajacy nazwe hosta.

Jesli nazwa hosta zostanie znaleziona funkcja zwróci wskaznik na strukturehostent , w przeciwnym wypadku zwróci NULL.

Wykład 4 – p. 33/44

Funkcja gethostbyname (II)

struct hostent

{

char * h_name;

char ** h_aliases;

int h_addrtype;

int h_length;

char ** h_addr_list;

#define h_addr h_addr_list[0]

};

h_name - oficjalna nazwa hosta,

h_aliases - lista aliasów,

h_addrtype - typ adresu hosta,

h_length - długosc adresu,

h_addr_list - lista adresów z serwera nazw.

Wykład 4 – p. 34/44

Zmiana kolejno sci bajtów

Poszczególne typy komputerów róznia sie sposobemprzechowywania liczb, a protokoły TCP/IP okreslaja niezaleznyod maszyny standard porzadku bajtów liczb.

System Unix BSD oferuje cztery procedury bibliotecznesłuzace do konwersji miedzy porzadkiem bajtów na danymkomputerze oraz sieciowym porzadkiem bajtów(<netinet/in.h> ):

Do zamiany liczby z reprezentacji sieciowej do reprezentacji lokalnej (network tohost) słuza funkcje:

uint16_t ntohs(uint16_t netshort);

uint32_t ntohl(uint32_t netlong);

Do konwersji liczb z porzadku danego komputera na porzadek sieciowy (host tonetwork) słuza funkcje:

uint16_t htons(uint16_t hostshort);

uint32_t htonl(uint32_t hostlong);

Wykład 4 – p. 35/44

gethostbyname - przykład (I)

hostent * host;

std::string hostName;

std::cout << "Podaj nazwe hosta: " << std::flush;

std::getline(std::cin, hostName);

host = gethostbyname(hostName.c_str());

if (host != NULL)

{

std::cout << "Oficialna nazwa: " << host->h_name << std::en dl

<< "Aliasy: " << std::endl;

while ( * host->h_aliases)

{

std::cout << " " << * host->h_aliases << std::endl;

++host->h_aliases;

}

std::cout << "Typ adresu: " << host->h_addrtype << std::end l

<< "Dlugosc adresu: " << host->h_length << std::endl

<< "Lista adresów: " << std::endl;

Wykład 4 – p. 36/44

gethostbyname - przykład (II)

while ( * host->h_addr_list) {

in_addr in;

memcpy(&in.s_addr, * host->h_addr_list, sizeof(in.s_addr));

std::cout << "[" << host->h_addr_list << "] = "

<< inet_ntoa(in) << std::endl;

++host->h_addr_list;

}

}

}

Przykładowy wynik działania programu:Podaj nazwe hosta: icis

Oficialna nazwa: icis.pcz.pl

Aliasy:

Typ adresu: 2

Dlugosc adresu: 4

Lista adresów:

[0x6031d0] = 212.87.224.6

Wykład 4 – p. 37/44

Domena internetowa - serwer (I)

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <unistd.h>

#include <iostream>

#include "local.h"

int main()

{

int orginal_socket = socket(AF_INET, SOCK_STREAM, 0);

if (orginal_socket < 0)

{

perror("blad generowania");

exit(1);

}

sockaddr_in server_address;

memset(&server_address, 0, sizeof(sockaddr_in));

server_address.sin_family = AF_INET;

server_address.sin_addr.s_addr = htonl(INADDR_ANY);

server_address.sin_port = htons(PORT);Wykład 4 – p. 38/44

Domena internetowa - serwer (II)

if (bind(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address)) < 0) {

perror("blad dowiazania");

exit(2);

}

if (listen(orginal_socket, 5) < 0) {

perror("blad nasluchu");

exit(3);

}

do {

sockaddr_in client_address;

socklen_t client_len = sizeof(client_address);

int new_socket = accept(orginal_socket,

(sockaddr * )&client_address,

&client_len);

if (new_socket < 0) {

perror("blad akceptowania");

exit(4);

}

Wykład 4 – p. 39/44

Domena internetowa - serwer (III)

if (fork() == 0) {

int len;

const int BUFSIZE = 255;

char buf[BUFSIZE];

while ((len = read(new_socket, buf, BUFSIZE)) > 0)

{

for (int i = 0; i < len; i++)

buf[i] = toupper(buf[i]);

write(new_socket, buf, len);

if (buf[0] == ’.’)

break;

}

close(new_socket);

exit(0);

}

else

close(new_socket);

}

while (true);

}

Wykład 4 – p. 40/44

Domena internetowa - klient (I)

int main(int argc, char ** argv)

{

hostent * host = gethostbyname(argv[1]);

sockaddr_in server_address;

memset(&server_address, 0, sizeof(server_address));

server_address.sin_family = AF_INET;

memcpy(&server_address.sin_addr, host->h_addr, host-> h_length);

server_address.sin_port = htons(PORT);

int orginal_socket = socket(AF_INET, SOCK_STREAM, 0);

if (orginal_socket < 0) {

perror("blad generowania");

exit(3);

}

if (connect(orginal_socket, (sockaddr * )&server_address,

sizeof(server_address)) < 0) {

perror("blad polaczenia");

exit(4);

}Wykład 4 – p. 41/44

Domena internetowa - klient (II)

char buf[255];

std::string line;

do

{

std::cout << "> " << std::flush;

getline(std::cin, line);

write(orginal_socket, line.c_str(), line.size()+1);

read(orginal_socket, buf, 255);

std::cout << buf << std::endl;

}

while (line[0] != ’.’);

close(orginal_socket);

exit(0);

}

Wykład 4 – p. 42/44

Lokalne i odległe adresy gniazd

Do ustalenia adresu odbiorcy, z którym jest połaczone danegniazdo słuzy funkcja:#include <sys/socket.h>

int getpeername(int s, struct sockaddr * name, socklen_t * namelen);

Procedura getsockname dostarcza lokalnego adresuzwiazanego z danym gniazdem:#include <sys/socket.h>

int getsockname(int s, struct sockaddr * name, socklen_t * namelen);

Wykład 4 – p. 43/44

Obsługa wielu klientów

Funkcje accept , send , recv , sendto , recfrom sablokujace.

Aby serwer mógł obsługiwac wielu klientów nalezy:utworzyc dla kazdego klienta oddzielny proces,obsługiwac poszczególnych klientów przy uzyciudodatkowych watków,wykorzystac funkcje select .

Wykład 4 – p. 44/44