Sunteți pe pagina 1din 22

6 Comunicaie client-server la nivel de socket

6.1 Introducere Vom prezenta o serie de aspecte generale: Protocoalele TPC/IP de nivel transport ofer servicii ce permit programelor nivelului aplicaie s comunice ntre ele prin intermediul mesajelor. Cnd o aplicaie trimite o cerere ctre nivelul transport pentru a trimite un mesaj, protocolul folosit la acest nivel: mparte informaia n pachete; adaug un antet de pachet care include adresa destinaiei; trimite informaia nivelului reea pentru procesare ulterioar. Transmisia i recepia datelor se realizeaz prin intermediul unor porturi de pe server, care identific destinaia specific a mesajului. Nivelul transport este implementat n reelele TCP/IP prin intermediul a dou protocoale: UDP (User Datagram Protocol) protocol datagram utilizator; TCP (Transmission Control Protocol) protocol de control al transmisiei. Caracteristici UDP: Asigur servicii de tip datagram nivelului aplicaie; Nu este fiabil (nu asigur certitudinea livrrii datagramelor, nici mecanismele de protecie la pierderea sau duplicarea datagramelor); Vitez mare de transmisie; Este un serviciu fr conexiune (emitorul nu cunoate starea receptorului n momentul transmisiei); Pentru transferul datelor folosete nite entiti abstracte, numite porturi de protocol, identificate prin numere ntregi pozitive i care au asociate nite cozi de mesaje prin care se transmit mesajele; Se utilizeaz pentru mesaje mici (sub 8KB) cu vitez mare;

Comunicaie client-server la nivel de socket

Antetul datagramei UDP conine: Source Port Number adresa portului surs; Destination Port Number adresa portului destinaie; Length lungimea datagramei n bytes; Checksum suma de control asociat datagramei (folosete acelai algoritm ca la protocolul IP). Caracteristici TCP (Transmission Control Protocol): Este fiabil (asigur integritatea datelor transmise, mecanisme de protecie la pierderea sau duplicarea pachetelor, pstrarea numrului de secven, mecanisme de control al fluxului de date n reea). Asigur transmisia blocurilor continue de date ntre porturile de protocol asociate aplicaiilor. Dimensiunea mesajelor nu este limitat. Viteza de transfer mai mic. SO ofer programelor la nivel aplicaie o interfa comun pentru aceste dou protocoale, i anume interfaa socket.

6.2 Interfaa Socket Este o interfa ntre un program de aplicaie i serviciul de transport (este un standard de facto), fiind furnizat de o bibliotec socket sau de sistemul de operare. Se folosete conceptul de descriptor, fiecare socket fiind tratat asemntor cu un fiier local. Acest descriptor este transmis aplicaiei la crearea socket-ului i apoi este utilizat ca argument n apelurile urmtoare. Primitive de serviciu Socket API Tabel 6.1
Primitive socket(protofamily, type, protocol) close(socket) bind(socket, localaddr, addrlen) listen(socket,queuesize) newsock = accept(socket, caddress, caddresslen) connect(socket, saddress, saddresslen) Descriere creeaz un socket nchide un socket leag socket-ul cu un port pune socket n mod pasiv accept o cerere de conectare stabilete legtura cu un server care a fcut accept

Reele de calculatoare Primitive send(socket, data, length, flags) sendto(socket, length, flags, destaddress, addresslen) sendmsg(socket, msgstruct, flags) recv(socket, buffer, length, flags) recvfrom(socket, buffer, length, flags, sndaddr, saddrlen) rcvmsg(socket, msgstruct, flags) Descriere transmite un mesaj transmite un mesaj folosind un socket neconectat primete un mesaj primete un mesaj pe un socket neconectat

Proprieti ale socketurilor n Unix: inovaie a sistemului Berkeley UNIX; este un punct de comunicaie prin care un proces poate emite sau recepiona informaie sub forma unui flux de bytes; este identificat printr-un descriptor, asemntor cu cel pentru fiier realizeaz urmtoarele operaii elementare: conectarea la staia de la distan emiterea datelor recepionarea datelor nchiderea unei conexiuni ataarea la un port ateptarea cererilor de conexiune emise de staiile de la distan acceptarea cererilor de conexiune la portul local O aplicaie de reea include: un program client care creeaz un socket pentru a iniia o conexiune cu o aplicaie server un program server care ateapt preluarea cererilor clienilor Structura general folosit pentru lucrul cu socketuri este: struct sockaddr { unsigned short sa_family; char sa_data[14]; //14 bytes pentru adrese }

Comunicaie client-server la nivel de socket

Membrii structurii sunt: sa_family identific familia de adrese; sa_data identific adresa de socket compus din numrul portului i adresa IP. Pentru a lucra mai uor cu structura de mai sus se folosete o nou structur ajuttoare sockaddr_in. Structura sockaddr este una generic (o putem privi ca o clas abstract) menit a stoca informaii de adres pentru oricare tip de socketuri. Structura ajut la referirea facil a elementelor adresei de socket: struct sockaddr_in { short int sin_family; unsigned short int sin_port; struct sin_addr; unsigned char sin_zero[8]; // }; Membrii: sin_family corespunde cmpului sa_family din structura sockaddr; sin_port identific portul; sin_addr identific adresa IP; sin_zero[8] se iniializeaz cu 0. Valorile articolelor sin_port i sin_addr trebuie s fie n forma big endian. Pentru acest lucru va trebui s se fac conversia ntre formatul little endian (host order) i cel big endian (network order). Pentru aceste conversii se vor utiliza funciile: htons() host to network short htonl() host to network long ntohs() network to host short ntohl() network to host long O alt funcie util de conversie este inet_addr(), care convertete adrese IP din forma zecimal grupat n cea de tipul unsigned long n formatul big endian. O alt funcie ce poate fi folosit n locul celei de mai sus este inet_aton() cu prototipul: int inet_addr(const char *cp, struct in_addr *inp)

Reele de calculatoare

n cazul n care avem o structur in_addr i dorim s afim adresa IP n format little-endian, atunci putem folosi funcia inet_ntoa(), astfel: printf ("%s", inet_ntoa(ina.sin_addr)); Vom prezenta un exemplu de iniializare a structurii sockaddr_in: struct sockaddr_in my_addr; my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); inet_aton( " 2 1 . 3 3 . 2 1 0 . 5 4 " , &(my_addr.sin_addr)); memset(&(my_addr.sin_zero), ' \ 0 ' , 8 ) ; Funcia socket() creaz un socket i returneaz descriptorul de socket (valoare ntreag prin care se identific un socket) sau 1, n caz de eroare. #include <sys/types.h> #include <sys/socket.h> int socket (int domeniu, int tip, int protocol); Parametrii funciei: Domeniul de comunicaie poate fi setat cu valori de tipul AF_ceva, cum ar fi: AF_UNIX stabilete domeniul de comunicare local UNIX sau AF_INET utilizat pentru comunicaii ntre procese aflate pe aceeai main sau pe maini diferite, folosind stiva de protocoale TCP/IP (domeniul Internet). Pentru exemplele curente vom utiliza cea de-a doua variant. n acest caz, fiecare socket va avea asociat o adres format din adresa IP a mainii gazd i un numr de 16 bii, local gazdei respective, denumit port. Tipul de socket utilizat: SOCK_STREAM (comunicarea se va realiza full-duplex, sigur, orientat-conexiune prin flux de date) sau SOCK_DGRAM (fr conexiune prin datagrame). Se mai poate folosi i constanta SOCK_RAW care ofer un acces la protocolul reea (protocolul IP), de nivel inferior. Protocol specific protocolul particular care va fi utilizat pentru transmisia datelor. Acesta poate fi setat pe 0 pentru ca funcia s-i poat alege protocolul corect automat. De exemplu, pentru domeniul AF_INET i tipul SOCK_STREAM se va considera protocolul de transport TCP, iar pentru cazul n

Comunicaie client-server la nivel de socket

care domain este AF_INET i tipul SOCK_DGRAM se va considera implicit protocolul de transport UDP. 6.2.1 Comunicaie client-server TCP/IP n figura 6.1 este prezentat modul de comunicaie client-server TCP/IP.
getprotobyname ()

socket()

bind()

ge thostbyname()

listen()

ge tprotobyname()

acce pt()

socke t()

stabilire conexiune

conne ct()

read() ce rere write() rspuns close()

write ()

read()

close ()

Figura 6.1 Cient-server TCP/IP Clientul apeleaz: gethostbyname() pentru a converti numele unui calculator n adresa IP; getprotobyname() pentru a converti numele unui protocol n forma binar folosit de sockets; socket() pentru a crea un socket; connect() pentru a conecta socket-ul la un server;

Reele de calculatoare

recv() (n mod repetat) pentru transferul tuturor datelor de la server (clientul nu are de unde ti dac serverul transmite datele ntr-un singur mesaj sau n mai multe); close() pentru a nchide socket-ul. Serverul apeleaz: getprotobyname() pentru a converti numele unui protocol n forma binar folosit de sockets; socket() pentru a crea un socket; bind() pentru a specifica portul local pentru socket; listen() pentru a plasa socket-ul n modul pasiv, apoi n bucl; accept() pentru a accepta o cerere de conectare i a crea un socket nou pentru aceast conexiune; send() pentru a trimite date; close() pentru a nchide noul socket. Primitivele blocante folosite sunt accept, connect (3 way handshake) i gethostbyname (conectare cu un server de nume). Primitiva bind() asigneaz socketul la portul mainii la care, de exemplu, serverul va asculta cereri de conexiune din partea clienilor. Prototipul funciei este urmtorul: #include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen); Parametri: sockfd este descriptorul de socket my_addr este un pointer la structura ce conine informaii referitoare la adres addrlen poate fi setat la valoarea sizeof(struct sockaddr) Vom prezenta un model de folosire a funciei bind(): #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define MYPORT 3490 main()

Comunicaie client-server la nivel de socket

{ int sockfd; struct sockaddr_in my_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; // little endian my_addr.sin_port = htons(MYPORT); // big endian my_addr.sin_addr.s_addr = inet_addr("10.12.110.57"); memset(&(my_addr.sin_zero), '\0', 8); // iniializare cu 0 a structurii bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)) ; ................. } Dup ataarea portului, serverul va trebui s atepte viitoarele conexiuni de la diveri clieni i s le rezolve cererile. Pentru aceasta se utilizeaz primitiva listen() urmat apoi de accept(). Primitiva listen() are urmtoarea form: int listen(int sockfd, int backlog); Parametri: sockfd este descriptorul de socket; backlog reprezint numrul maxim de conecii permise n coada de ateptare. Primitiva accept() permite acceptarea propriu-zis a conexiunilor: int accept(int sockd, struct sockaddr *addr, socklen_t *addrlen); Apelul va returna un descriptor de socket corespunztor clientului a crui conexiune a fost acceptat, stabilindu-se astfel un canal de comunicaie duplex ntre server i client. Acest nou descriptor va putea fi folosit pentru a trimite i recepiona date via reea prin mijlocitori precum send() sau write() i recv() sau read(). Parametri: sockfd este descriptorul de socket addr va conine informaii despre adresa IP i portul folosite de clientul conectat la server, addrlen stocheaz lungimea acestei structuri.

Reele de calculatoare

Primitiva send() ntoarce numrul de octei transmii, care uneori difer de numrul de octei ce dorim s-i transmitem. Valoarea returnat este numrul de octei trimii n caz de succes. Dac eueaz, este returnat -l, iar errno descrie eroarea. int send(int sockfd, const void *msg, int len, int flags) Parametri: sockfd este descriptorul de socket msg reprezint o zon de memorie n care se afl datele ce trebuie trimise len reprezint lungimea datelor n octei flags este de obicei setat pe 0 Primitiva recv() ntoarce numrul de octei recepionai. Valoarea returnat este numrul de octei primii n caz de succes. Dac eueaz, este returnat -l, iar errno descrie eroarea. int recv (int sockfd, void *buf, int len, unsigned int flags); Parametri: sockfd este descriptorul de socket; msg reprezint o zon de memorie n care se vor copia datele recepionate; len reprezint mrimea acestor date n octei; flags este de obicei 0 sau setat la valoarea MSG_PEEK, dac datele recepionate trebuie reinute i dup ce sunt recepionate; Primitivele close() i shutdown() Primitiva close() va nchide conecia aferent descriptorului de socket. Astfel se va bloca orice read() or write() ulterior, cel ce va ncerca acest lucru va primi mesaj de eroare. Primitiva shutdown() permite un control superior al procesului de nchidere a socketurilor. Funcia are forma: int shutdown(int sockfd, int opt); Parametri: sockfd este descriptorul pentru socketul ce trebuie nchis; opt poate lua valorile: 0 (interzice orice recepie ulterioar), 1 (interzice orice trimitere ulterioar), 2 (interzice att recepia, ct i trimiterea, similar cu close())

Comunicaie client-server la nivel de socket

Funcia ntoarce valoarea 0 n caz de success i valoarea -1 n caz de eroare. 6.2.2 Comunicaie client-server UDP/IP n figura 6.2 este prezentat modul de comunicaie client-server UDP/IP.

socket()

socket()

bind()

bind()

cerere recvfrom() sendto()

rspuns sendto() recvfrom()

close()

close()

Figura 6.2 Client-server UDP/IP Mecanismul de lucru este urmtorul: Se creaz un socket care va trata conexiunile cu clienii. Sunt pregtite structurile de date (sockaddr_in) pentru a ataa socketul la portul folosit de aplicaie. Se ataeaz socketul la port (bind()). Sunt procesate cererile clientului prin schimbul de mesaje ntre server i client (sendto() i recvfrom()). Pot fi utilizate i primitivele generale send() i recv(). Se nchide socketul client (close()). Primitiva sento() este folosit pentru trimiterea datagramelor, ntoarce numrul de octei trimii i are urmtorul prototip: int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

Reele de calculatoare

Parametrii funciei: sockfd este descriptorul de socket; msg reprezint o zon de memorie n care se afl datele ce trebuie trimise; flags va fi iniializat cu 0 len reprezint lungimea datelor ce vor fi trimise; to reprezint un pointer la o structur de tip sockaddr i conine adresa de IP i portul destinaiei; tolen va fi iniializat cu valoarea sizeof(struct sockaddr). Primitiva recfrom() este folosit pentru recepionarea datagramelor, ntoarce numrul de octei recepionai i are urmtorul prototip: int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); Parametrii funciei: sockfd este descriptorul de socket; msg reprezint o zon de memorie n care se afl datele ce sunt primite; flags va fi iniializat cu 0; len reprezint lungimea datelor primite; from reprezint un pointer la o structur de tip sockaddr i conine adresa de IP i portul sursei; fromlen va fi iniializat cu valoarea sizeof(struct sockaddr) 6.3 Exemplificri 1. S se construiasc un server i un client TCP/IP. n exemplu, serverul va pstra evidena numrului de clieni care au accesat resursa i va raporta acest numr la fiecare apel. /* SERVER TCP */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <netdb.h>

Comunicaie client-server la nivel de socket

main(int argc, char ** argv) { unsigned short port; /* portul client */ char buffer[32]; struct sockaddr_in client, server; /*adresele client, server*/ struct hostent * srvinfo; int s, rc, namelen, ns; if(argc!= 2) { printf("Apel: %s port \n", argv[0]); exit(1); } /*preia numele calculatorului local */ if(gethostname(buffer, 32)) perror("Eroare la preluarea numelui serverului"); printf("Nume server: %s \n", buffer); /*preia informatiile despre configurarea hostului*/ if (!(srvinfo=gethostbyname(buffer))) perror("Eroare la preluarea informatiilor despre server"); port=(unsigned short) atoi(argv[1]); /*Creeaza un socket*/ if ((s=socket(AF_INET, SOCK_STREAM, 0)) <0) { perror("Eroare la creare socket"); exit(3); } /*Asociaz socketului o adres de server */ memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* adresa Internet locala */ if ( bind ( s, &server, sizeof(server)) <0) { perror("Eroare la obinerea adresei"); exit(4); }

Reele de calculatoare

/*Creeaz coad pentru cererile de conexiune; va prelua maxim 5 cereri de conexiune de la clieni, restul fiind refuzate */ if (listen(s, 5) != 0) { perror("Eroare la obinerea cozii de cereri"); exit(5); } /* Creeaz un descriptor de socket pentru. comunicaia serverclient */ namelen = sizeof(client); if ((ns = accept( s, &client, &namelen)) == -1) { perror("Eroare la acceptarea conexiunii"); exit(6); } /* Recepioneaz mesajul de la client */ if(recv(ns, buffer, 32, 0) == -1) { perror ("Eroare la recepie"); exit(7); } /* Afieaz mesajul primit de la client */ printf("Mesaj recepionat de la client, pe TCP: %s\n", buffer); /*Trasmite confirmarea clientului */ if (send(ns, buffer, strlen(buffer), 0) <0) { perror("Eroare la transmisie"); exit(8); } endhostent(); /* nchide sesiunea TCP/IP */ close(ns); close(s); exit(0); }

Comunicaie client-server la nivel de socket

/* CLIENT TCP */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <netdb.h> main (int argc, char ** argv) { unsigned short port; /* portul client, acelai ca cel specificat n modulul server */ char buffer[32]; struct sockaddr_in server; /*adres server*/ struct hostent * hostnm; /*informaii server */ int s, rc; if (argc != 3) { printf("Apel: %s hostname port \n", argv[0]); exit(1); } /*preia numele calculatorului local */ if (!(hostnm=(struct hostent *) gethostbyname(argv[1]))) { perror("Eroare la preluarea numelui serverului"); exit(3); } printf("A preluat numele de server.... \n"); port = (unsigned short)atoi(argv[2]); strcpy(buffer, "Mesaj transferat prin socket, pe TCP"); /*preia informaiile despre server*/ server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* aceeai ca la server */

Reele de calculatoare

printf("A preluat inf. despre server....\n"); if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("Eroare la creare socket"); exit(4); } printf("A creat socket-ul....\n"); if (connect(s, &server, sizeof(server)) < 0) { perror("Eroare la obinerea conexiunii"); exit(5); } printf("A realizat conexiunea.....\n"); /* Transmite mesajul serverului */ if (send(s, buffer, strlen(buffer), 0) < 0) { perror("Eroare la transmisie"); exit(6); } printf("A transmis mesajul.....\n"); /* Confirmare de la server */ if (recv(s, buffer, 32, 0) < 0) { perror("Eroare la recepie"); exit(7); } printf("Confirmarea de la server a fost fcut.... \n"); close(s); exit(0); }

Comunicaie client-server la nivel de socket

2. S se construiasc o aplicaie server i una client care s comunice prin datagrame. /* Modul SERVER UDP */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <errno.h> #include <netdb.h> main() { char buffer[32]; struct sockaddr_in client, server; /*adresele client, server*/ int s, rc, namelen; /*Creeaz un socket*/ if ((s=socket(AF_INET, SOCK_DGRAM, 0)) <0) { perror("Eroare la creare socket"); exit(1); } printf("A creat socket-ul....\n"); /*Asociaz socketului o adres de server */ memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = 0; /* orice port */ server.sin_addr.s_addr = INADDR_ANY; if ( bind( s, &server, sizeof(server)) <0) { perror("Eroare la obinerea adresei"); exit(2); } printf("S-a alocat o adres .....\n"); /* Determin portul asignat*/ namelen = sizeof(server); if (getsockname(s, (struct sockaddr *) &server, &namelen))

Reele de calculatoare

{ perror("Eroare la determinarea portului"); exit(3); } printf("\n Portul asignat este: %d\n", ntohs(server.sin_port)); namelen = sizeof(client); /* Recepioneaza mesajul de la client */ if (recvfrom ( s, buffer, 32, 0, &client, sizeof(client)) < 0) { perror ("Eroare la recepie"); exit(4); } printf("A recepionat mesajul de la client.... \n"); /* Afieaz mesajul primit de la client */ printf("\n Mesajul recepionat de la client este: %s\n", buffer); printf("Parametrii: \n Nume domeniu: %s \n \Port: %d \n Adresa \Internet: %s \n", (client.sin_family == AF_INET? "AF_INET":"AF_UNIX"), ntohs(client.sin_port), inet_ntoa(client.sin_addr)); endhostent (); /* nchide sesiunea UDP/IP */ close(s); exit(0); } /* Modul CLIENT UDP */ /* Modul CLIENT UDP */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <errno.h> #include <netdb.h> main(int argc, char ** argv) {

Comunicaie client-server la nivel de socket

unsigned short port; /* portul client, acelai ca cel specificat n modulul server */ char buffer[32]; struct sockaddr_in server; /*adres server*/ int s, rc; if(argc!= 2) { printf("Apel: %s port \n", argv[0]); exit(1); } port=(unsigned short) atoi(argv[1]); strcpy(buffer, "Mesaj transferat prin socket, pe UDP"); /*preia informaiile despre server*/ server.sin_family = AF_INET; /*AF_UNIX, AF_INET*/ server.sin_port = htons(port); server.sin_addr.s_addr = inet_addr("193.226.34.61"); /* aceeasi ca la server */ if ((s=socket(AF_INET, SOCK_DGRAM, 0)) <0) { perror("Eroare la creare socket"); exit(2); } /* Transmite mesajul serverului */ if(sendto(s, buffer, strlen(buffer)+1, 0, &server, sizeof(server)) < 0) { perror ("Eroare la transmisie"); exit(3); } close(s); exit(0); }

Reele de calculatoare

3. S se construiasc o aplicaie de tip server stream (TCP) concurent, care ateapt un numr N de la un client i returneaz lista numerelor prime mai mici dect N. Rezolvarea servirii concurente a mai multor clieni se va face folosind apelul fork(). Se creaz astfel un proces copil care va servi un anumit client. #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <error.h> #include <string.h> #include <stdlib.h> #include <signal.h> /* portul folosit */ const int PORT_SERVER = 9001; /* numarul maxim de clieni acceptai */ const int CLIENTI_MAXIM = 10; extern int errno; /* eroarea returnat */ int ds; /* descriptor pentru server */ int dc; /* descriptor pentru client */ int nr = 0; /* numrul de clieni */ void semnal (int nr_semnal) /* funcia de tratare a semnalelor */ { if (nr_semnal == SIGCHLD) { wait (NULL); nr--; /* am pierdut un client */ return; } } /* ntoarce 0 dac nu e prim, i altfel */ int e_prim (int i) { int k;

Comunicaie client-server la nivel de socket

for (k = 2; k * k <= i; k++) if ((i%k) == 0) return 0; return 1; } void client () /* funcia de tratare a clientului */ { char buffer[100]; char aux[100]; int i,t; int numar, k; sprintf (aux,"Eti clientul numrul: %d\n",nr); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); /* eroare, am ieit */ exit (errno); } sprintf (aux, "Dai numrul:"); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); exit (errno); } bzero (buffer, 100); /* citete numarul sub forma de ir de caractere */ if (read (dc, buffer, 100) == 0) { shutdown (dc, 2); exit (errno); } /* din ir de caractere n ntreg */ numr = atoi (buffer); for (k = 2; k < numr; k++) if (e_prim (k)) { sprintf (aux, "Numr prim: %d\n", k); if (write (dc, aux, strlen (aux))!=strlen (aux)) { shutdown (dc, 2); exit (errno); }

Reele de calculatoare

} shutdown (dc, 2); exit (errno); } /* programul principal */ int main () { struct sockaddr_in server; /* tratm semnalele */ if (signal (SIGCHLD, semnal) == SIG_ERR) { perror ("signal()") ; exit (errno); } if (signal (SIGPIPE, SIG_IGN) == SIG_ERR) { perror ("signal()"); exit (errno); } /* crem socket-ul */ if ((ds = socket (AF_INET, SOCK_STREAM, 0)) == -1) { perror ("socket() ") ; return errno; } /* pregtim structurile de date */ bzero (&server, sizeof (server)); server.sin_family = AF_INET; server.sin_port = htons (PORT_SERVER); server.sin.addr.s_addr = htonl (INADDR_ANY); /* atam la port */ if (bind (ds, &server, sizeof (server)) == -1) { perror ("bind()"); return errno; } if (listen (ds, 5) == -1) { perror ("listen() ") ; return errno; }

Comunicaie client-server la nivel de socket

printf ("Ateptm clieni la portul %d...\n", PORT_SERVER) ; while (1) { /* acceptm un client */ dc = accept (ds, NULL, NULL); /* am ajuns la numrul maxim de clieni? */ if (nr == CLIENTI_MAXIM) { shutdown (dc, 2) ; continue; } /* lansm un proces care trateaz cererile clientului */ switch (fork ()) { case 0: client (); case -1: perror ("fork()"); break; default: break; } nr++; /* a mai venit un client */ } }

S-ar putea să vă placă și