Sunteți pe pagina 1din 30

Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Introducere in programarea aplicatiilor de retea

 Ce ste un socket?
 Tipuri de socket
 Adrese socket
 Model de comunicatie client – server
 Functii
 Completarea structurii sockaddr_in
 Exemple
 Cerinte pt laborator
 Bibiliografie

1
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Ce este socket?

Un socket este un „capat de comunicatie" sau „punct final de comunicatie" care poate fi numit si adresat intr-o retea, fiind locul
unde programul de aplicatie se intalneste cu furnizorul mediului de transport.

Un soket este:
- d.p.d.v. al unui program de aplicatie: o resursa alocata de sistemul de operare;
- d.p.d.v. al sistemului de operare: o structura de date intretinuta de catre nucleul sistemului de operare; aceasta structura este
referita in aplicatii printr-un intreg numit descriptor de socket.

Relativ la un socket se pot face una dintre urmatoarele doua analogii:


 socket-cutie postala:
- proprietarul (aplicatia) depune mesajele de trimis si isi ridica corespondenta primita;
- facorul postal (furnizorul mediului de transport) deschide cutia de cateva ori pe zi, ridica corespondanta de expediat si
depune corespondenta sosita la adresa respectiva;

 socket-aparat telephonic
- proprietarul formeaza un numar si dupa stabilirea legaturii incepe sa discute cu persoana de la celalalt capat al firului;
- aparatul si intreaga retea telefonica asigura stabilitatea legaturii pana la incheierea convorbirii .

OBS. doua aplicatii pot comunica intre ele prin socket doar dupa ce fiecareia dintre ele sistemul de operare i-a alocat un socket
(exista un numar de descriptori de socket rezervati pentru aplicatiile de sistem, restul descriptorilor fiind disponibili pentru
utilizatori).

2
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Tipuri de socket
Se disting doua tipuri de socket: socket stream si socket datagram. Comunicarea este posibila, doar daca la ambele capete este
utilizat acelasi tip de socket.

Socket stream
Interfata socket stream defineste un serviciu orientat conexiune, datele fiind transmise fara erori si fara duplicari, Datele sunt
receptionate in aceeasi ordine in care au fost transmise, avandu-se grija insa ca fluxul de date sa nu depaseasca o valoare maxima de
octeti la un moment dat. Asupra datelor ce sunt transmise nu se impune nici un fel de limitare, ele fiind considerate simple siruri de
octeti. Transportul este realizat folosind protocolul TCP. Fiind un serviciu orientat conexiune, este potrivita analogia facuta anterior
cu aparatul telefonic. Ca exemplu de utilizare pentru socket stream poate fi dat unul dintre serviciile nivelului aplicatie, si anume FTP
(File Transfer Protocol).

Deci, socket stream asigura o conexiune sigura, lucru care presupune insa reducerea performantei datorita efortului de calcul
necesar mentinerii conexiunii si verificarilor de corectitudine. La nivel utilizator aceasta reducere a performantei nu este insa
sesizata .

Se recomanda utilizarea socket-ului stream in cazurile in care cantitatile de date ce sunt transmise sunt mari, iar comunicatia are loc
in retele WAN.

3
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Socket datagram
Interfata socket datagram defineste un serviciu fara conexiune in care datagramele sunt transmise ca si pachete separate. Serviciul
nu asigura garantii cu privire la receptionarea datelor, acestea putand fi pierdute ori duplicate, ordinea de sosire la destinatie putand
fi de asemenea diferita de cea de transmitere. Marimea unei datagrame este limitata la numarul de octeti care pot fi transmit intr-o
singura tranzactie. Transportul este realizat folosind protocolul UDP, iar analogia potrivita este cea cu cutia postala.

Comunicarea prin socket-ul datagram este nesigura deoarece pachetele pot fi ignorate, alterate sau duplicate in timpul transmisiei,
utilizarea lui fiind recomandata in cazurile in care aplicatia implementeaza un mecanism propriu de corectitudine sau daca aplicatia
nu este sensibila la transmisii eronate. Se castiga insa viteza la prelucrare raportat la socket-ul stream.

Se recomanda folosirea acestui tip de socket pentru transmiterea unei cantitati mici de date in cadrul retelelor LAN.

4
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Adrese socket
Pentru a fi independent de platforma, socket permite utilizarea mai multor familii de adrese, o astfel de familie definind un stil
de adresare. Toate host-urile din aceeasi familie de adrese inteleg si folosesc aceeasi schema pentru adresarea capetelor socket-ului.
Familiile de adrese sunt identificate printr-un numar intreg, numele acestora incepand cu AF (Adress Family):

 AF-INET: defineste adresarea in domeniul Internet, fiind si cea mai importanta familie;

 AF-UNIX: reprezinta sistemul local (protocoale interne UNIX);

 AF-NS: pentru protocoale Xerox NS;

Generic, stuctura unei adrese este urmatoarea:


struct sockaddr {
u_short sa_family; //valoare AF_xxx
char sa_data[14]; //dependent de familie
}
unde,
sa_family: indica familia de adrese folosita;
sa_data: interpretat in functie de familie.
OBS. fiecare familie de adrese are definita structura proprie de adresa care se suprapune peste cea generica in momentul
transmiterii ei catre nucleu.

5
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Adresele din familia AF_INET sunt de tip struct sockaddr_in si sunt definite in <arpa/inet.h> astfel:

struct in_addr {
union {
struct{
unsigned char s_b1,
s_b2,
s_b3,
s_b4;
} S_un_b;
struct {
unsigned short s_w1,
s_w2;
} S_un_w;
unsigned long s_addr;
} S_un;
};

struct sockaddr_in{
short sin_family; //valoare AF_INET
unsigned short sin_port; //numarul de port
struct in_addr sin_addr; //adresa IP
char sin_zero[8]; //nefolosit
};

6
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Model de comunicatie client/server


Aplicatiile care folosesc socket respecta o serie de scenarii bine stabilite: este vorba despre ordinea de apelare a functiilor sistem
in functie de tipul de socket si de rolul pe care il joaca aplicatia (client sau server)

4.1. Scenariul aplicatiei client in cazul socket stream

Succesiunea apelurilor pentru client este dupa cum urmeaza:


SERVER CLIENT

Apelurile sistem pentru aplicatia client


Asa cum se poate observa si din figura, apelurile sistem se pot grupa in trei sectiuni: sectiunea de initializare, sectiunea de
transfer de date si sectiunea de inchidere a conexiunii.

Secventa de initializare:

7
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

• socket: cere nucleului sistemului sa creeze un socket prin care sa poata fi contactat; se fixeaza familia de adrese folosita si tipul
de socket (in acest caz stream) ;
• connect: initiaza conexiunea intre aplicatia client si aplicatia server. La finalul acestui apel, fie exista o conexiune stabila intre
client si server, fie se returneaza un cod de eroare.
Apelurile sistem socket si connect trebuie efectuate in mod obligatoriu in aceasta ordine si o singura data. Daca se apeleaza
connect pentru un socket deja conectat se va reurna o eroare.

Sectiunea de transfer de date:


• send: trimite catre server un sir de octeti. Pentru a putea trimite date este necesara existenta unei conexiuni. Fara aceasta
metoda send va intoarce un cod de eroare si nu va trimite nimic;
• recv: primeste un sir de octeti de la server. Pentru a putea primi date este necesara existenta unei conexiuni. Fara aceasta
metoda recv va intoarce un cod de eroare si nu va primi nimic;

Apelurile sistem send si recv NU trebuie efectuate in mod obligatoriu in aceasta ordine. Ordinea prezentata in figura corespunde
comunicatiei de tip cerere-raspuns. De asemenea aceste metode se pot apela de mai multe ori. Ordinea apelurilor depinde de modul
in care sunt implementate aplicatiile server si client.

Sectiunea de inchidere a conexiunii:


• close: cere nucleului sistemului sa inchida conexiunea existenta si sa elibereze orice resurse folosite;
Apelul sistem close este optional, dar recomandat. Sistemul de operare se ocupa oricum de eliberarea tuturor resurselor atunci
cand aplicatia este finalizata. In urma acestui apel conexiunea este incheiata iar orice apel de tip send sau receive va returna o
eroare.

8
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Functia socket
Aceste apeluri sistem trebuie precedate de specificarea fisierului header:

#include <sys/socket.h>

Apelurile soket si connect (apeluri socket de conexiune)


Prototipurile apelurilor sunt:

int socket (int familie, int tip, int protocol);

unde:
familie: indica familia de adresa socket utilizata (AF_INET, AF_UNIX, etc);
tip: indica tipul de socket folosit (SOCK_STREAM, SOCK_DGRAM);
protocol: argument care are valoare 0 cu specificatia „lasam sistemului alegerea protocolului"

Apelul creaza un socket care va asigura conectivitatea programului local, fie el client sau server. Apelul intoarce un SOCKET (
intreg), notat in cele ce urmeaza cu sd si care reprezinta descriptorul de socket (folosit de apelurile care urmeaza ca si parametru).
sd se mai numeste si socket(descriptor) de intalnire.

9
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Functia connect
int connect( int sd, struct sockaddr *saddr, int sz);
//returneaza 0 la succes si -1 la eroare
Un proces client care foloseste socket stream solicita nucleului sa conecteze prin sd, serverul avand adresa socket saddr
reprezentata pe sz octeti.
Structura sockaddr este o strucura generica prin intermediul careia se pot seta informatiile de identificare ale unui socket. Pentru
socketul din familia AF_INET informatiile necesare pentru identificare sunt adresa IP si portul. Se poate observa ca structura
sockadrr_in contine aceste campuri. Problema care apare in acest moment este cum se poate transforma o structura de tip sockaddr
intr-o structura de tip sockaddr_in. O solutie ar fi fost folosirea mostenirii. Mai exact, structura sockaddr?in sa mosteneasca stuctura
sockaddr, dar acest lucru nu este posibil datorita faptului ca aceste structuri, ca si metodele despre care am discutat pana acum,
sunt definite intr-un limbaj procedural (limbajul C) in care nu exista notiunea de mostenire. Ne ajuta totusi o alta particularitate a
limbajului C, si anume un pointer se poat converti intr-un alt pointer folisnd un simplu „cast". Astfel, putem crea o structura de tip
sockaddr_in in care sa scriem datele de care avem nevoie, sa obtinem un pointer la aceasta structura si sa convertim acest pointer la
un pointer de tip sockaddr pe care sa il oferim ca parametru metodei connect. Ex.:

SOCKET sd;
struct sockaddr_in saddr;
int sz = sizeof(saddr);

//apelam connect
int result = connect(sd, (struct sockaddr*) &pointer_sockaddr, sz);
In acest fel metoda connect poate fi folosita si pentru alte familii de socket. Este suficient sa definim o noua structura
asemanatoare cu sockaddr care sa contina detaliile de identificare pentru socketul din familia noastra.

10
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Completarea campurilor structurii sockaddr_in


O atentie deosebita trebuie acordata si structurii sockaddr_in. Asa cum am spus, in aceasta structura vom scrie adresa IP si portul
folosite pentru identificarea socketului.

Concret, membrul sin_port va primi valoarea portului iar membrul sin_addr adresa IP.
Portul este un numar pe 2 octeti si trebuie specificat in formatul retea (Big Endian).

Pe o masina Big Endian atribuirea se poate face direct deoarece datele au aceiasi reprezentare in memorie. In cazul in care
matina foloseste Little Endian nu se poate face o atribuire directa ci trebuie facuta mai intai o conversie din Little Endian in Big
Endian.

Motivul pentru aceasta conversie este ca daca masina este Little Endian atunci octetul cel mai putin semnificativ este la adresa
cea mai mica iar atunci cand se citeste valoarea in formatul retea acest octet devine cel mai semnificativ

Ex1.: pentru portul 43962 (0xABBA in hexazecimal), Big Endian.

11
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Exemplul de mai sus corspunde situatiei in care masina foloseste o reprezentare Big Endian si s-a facut o atribuire directa intre
valoarea portului si membrul sin_port al structurii sockaddr_in:

saddr.sin_port = 43962; // OxABBA in hexazecimal


Sa presupunem ca structura saddr este pastrata in memorie incepand cu adresa 0x0028. Rezulta ca membrul sin_port se va afla in
memorie incepand cu adresa 0x002A. Deoarece reprezentarea este Big Endian atunci octetul cel mai semnificativ se va afla la adresa
cea mai mica. Atunci cand valoarea portului se va copia in sirul de octeti ce va fi trimis in retea octetii se copiaza in aceiasi ordine.
Rezulta ca octetul cel mai semnificativ al portului se va afla inaintea octetului mai putin semnificativ (in cazul nistru MSB este octetul
12 iar LSB este octetul 13).
Atunci cand se va interpreta valoarea in formatul retea se va citi mai intai MSB-ul si din octetul urmator LSB-ul. Rezulta valoarea
0xABBA (in hexazecimal), adica exact valoarea dorita.

Ex2.: pentru portul 43962 (0xABBA in hexazecimal), Little Endian

Transformare Little Endian - format retea

12
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Exemplul de mai sus corspunde situatiei in care masina foloseste o reprezentare Little Endian si s-a facut o atribuire directa intre
valoarea portului si membrul sin_port al structurii sockaddr_in:
saddr.sin_port = 43962; // OxABBA in hexazecimal
Sa presupunem ca structura saddr este pastrata in memorie incepand cu adresa 0x0028. Rezulta ca membrul sin_port se va afla
in memorie incepand cu adresa 0x002A. Deoarece reprezentarea este Little Endian atunci octetul cel mai putin semnificativ se va
afla la adresa cea mai mica. Atunci cand valoarea portului se va copia in sirul de octeti ce va fi trimis in retea octetii se copiaza in
aceiasi ordine. Rezulta ca octetul cel mai putin semnificativ al portului se va afla inaintea octetului mai semnificativ (in cazul nostra
LSB este octetul 12 iar MSB este octetul 13).
Atunci cand se va interpreta valoarea in formatul retea se va citi mai intai MSB-ul si din octetul urmator LSB-ul. Rezulta valoarea
OxBAAB (in hexazecimal), o valoare diferita de cea dorita. Pentru a se obtine valoarea dorita este necesara inversare a celor doi
octeti. Astfel, in loc sa facem o atribuire directa a valorii, vom folosii metoda htons. Aceasta metoda face o transformare a unui short
din formatul masinii (in cazul nostru Little Endian) in formatul retea (identic cu Big Endian).

saddr.sin_port = htons(43962);

Transformare Little Endian - htons - format retea

13
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

In urma apelului htons numarul OxABBA este convertit la numarul OxBAAB si salvat in memorie in formatul Little Endian. Astfel
octetul mai putin semnificativ (OxAB) va fi salvat la adresa mai mica iart octetul cel mai semnificativ (OxBA) la adresa mai mare.
Atunci cand se copiaza valoarea in sirul de octeti transmis in retea se va pastra ordinea din memorie. Insa atunci cand valoarea este
interpretata, se va incepe citirea cu primul octet si aacesta va fi interpretat ca MSB. Rezulta valoarea OxABBA, adica exact valoarea
dorita.

Aceiasi situatie apare si in cazul adresei IP. Adresa IP este un numar de 32 de biti (4 octeti). In cadrul structurii sockaddr_in adresa ip
(membrul sin_addr) este reprezentata ca un union. Un union este asemanatopr cu o structura, diferenta fiind aceea ca in cazul unei
structuri fiecare membru ocupa propria zona de memorie, in timp ce in cazul unui union toti membrii impart aceiasi zona de
memorie (memoria alocata este dimensiunea celui mai mare membra). In cazul nostra acest union contine o structura cu 4 char-uri
(dimensiune 4*1=4), o structura cu 2 short-uri (dimensiune 2*2=4) si un unsigned long (dimensiune 1*4=4). Dimensiunea union-ului
este deci 4. Practic, acest union permite scrierea adresei IP in 3 feluri in aceiasi zona de memorie. La final, in memorie, trebuie sa
apara la adresa cea mai mica cel mai semnificativ octet al adresei IP.

Ex. Daca avem adresa IP 127.0.0.1 se pot folosi urmatoarele variante pentru a seta adresa IP:

A:
saddr.sin_addr.s_un_b.s_b1 = 127;
saddr.sin_addr.s_un_b.s_b2 = 0;
saddr.sin_addr.s_un_b.s_b3 = 0;
saddr.sin_addr.s_un_b.s_b4 = 1;

B:
saddr.sin_addr.s_un_w.s_w1 = htons(16128);
saddr.sin_addr.s_un_w.s_w2 = htons(1);

C:
saddr.sin_addr.s_addr = inet_addr(„127.0.0.1");

Din cele 3 variante ultima este cea mai simpla practic adresa IP se scrie sub forma unui sir de caractere iar metoda inet_addr se
ocupa de conversia ei intr-un numar scris direct in formatul retea.

14
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Functia Bind
int bind ( SOCKET sd, struct sockaddr * saddr, int sz);
//returneaza 0 la succes si -1 la eroare
Server-ul isi inregistreaza adresa socket proprie saddr, pentru socket-ul sd; lungimea adresei local este sz. In
saddr se trece numarul de port la care poate fi contactat, tot in local in campul sin_addr.s_addr se trece adresa IP
a serverului sau constanta INADDR_ANY. Structura sockaddr va fi inlocuita cu o structura sockaddr_in (vezi
metoda connect pentru detalii). Pentru port se foloseste aceiasi valoare ca si pentru connect (trebuie sa fie
acelasi port pentru a se putea stabili conexiunea)

15
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Funtia Listen
int listen (SOCKET sd, int lungcoada);
//returneaza 0 la succes si -1 la eroare
unde:
lungcoada: indica numarul maxim de conexiuni care sunt acceptate pe socket-ul sd in asteptare daca server-ul este ocupat (cele
ce depasesc lungcoada vor fi refuzate); majoritatea sistemelor de operare nu admit mai mult de 5 clienti simultan.

16
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Functia Accept
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sd, struct sockaddr *addr, socklen_t *addrlen);

Apelul pune server-ul sa astepte o conexiune socket stream sd pana cand un client reuseste un connect la el. La realizarea
conexiunii, in argumentele addr si addrlen sunt intoarse adresa socket a clientului si lungimea pe care este reprezentata aceasta.
Apelul intoarce trei valori:
1. un SOCKET pe care il notam fd. Acesta reprezinta un descriptor pe care server-ul il foloseste pe post de descriptor de fisier
pentru schimbul de mesaje cu clientul; fd se mai numeste si socket (descriptor) de schimb.
2. adresa socket a procesului client in departe. Structura oferita ca parametru va fi umpluta automat cu datele clientului
3. lungimea acestei adrese in addrlen.

17
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Functiile send, recv (operatii de I/O prin socket)


Aceste apeluri sunt cele mai simple apeluri sistem prin intermediul carora se pot face schimburi de date intre client si server prin
socket. Utilizarea lor presupune citarea fisierului header: <sys/socket.h> Sintaxele apelurilor sunt:
int send (SOCKET sd, char *T, int n, int f);
int recv (SOCKET sd, char *T, int n, int f);

unde:
 sd: descriptorul de socket prin care se realizeaza comunicatia cu partenerul departat; acest intreg provine dintr-un apel
socket, cu exceptia send si recv dintr-un server socket stream, cand acesta provine din apelul accept;
 f: flag care are de regula valoarea 0 lasand in seama sistemului fixarea unor flaguri

Apelul send expediaza prin sd, un numar de maxim n octeti pe care ii ia din memorie incepand cu adresa T.

Responsabilitatea depunerii octetilor la aceasta adresa T revine programatorului.

OBS.
• in cazul send (cazul socket stream) adresa IP si portul destinatarului se stabilesc la conexiune;
• intregul returnat de apel reprezinta numarul de octeti care s-a putut transmite , in caz contrar, se intoarce o valoare negativa.

Apelul recv receptioneaza prin sd un numar de maxim n octeti pe care ii depune in memorie incepand cu adresa T.
Programatorul trebuie sa se asigure ca zona tampon are rezervati la adresa T cel putin n octeti.

OBS.
• in cazul recv (cazul socket stream) adresa IP si portul destinatarului se stabilesc la conexiune;
• intregul returnat de capel reprezinta numarul de octeti care au fost receptionati; faptul ca s-a inchis conexiunea este semnalat
prin intoarcerea valorii 0; in caz de eroare se intoarce o valoare negativa.

OBS. tratarea situatiilor in care nu s-au transmis sau receptionat exact cei n octeti solicitati cade exclusiv in sarcina programatorului.
Daca prin socket se poate transmite fie si numai 1 octet, acesta se va transmite si operatia este considerata incheiata.

18
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Precizarea adresei IP internet


Pentru conversia acestora este necesar headerul
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

Rutinele inet_addr, inet_ntoa

Prototipurile rutinelor sunt:

unsigned long inet_addr (char *S);


char *inet_ntoa (struct in_addr I);

in_addr_t inet_addr(const char *S);


char *inet_ntoa(struct in_addr I);
int inet_aton(const char *cp, struct in_addr *inp);

Rutina inet_addr transforma sirul de caractere S scris in conventie C si care contine o adresa IP (scrisa in notatia punctuala), intr-
o adresa de 32 biti a carei valoare o intoarce.
Rutina inet_ntoa face operatia inversa, adica transformas intregul lung I intr-un sir de caractere care contine adresa IP in notatia
punctuala.

19
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Internet v6
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
int inet_pton(int af, const char *src, void *dst);

Return Value
inet_ntop() returns the dst parameter on success, or NULL on failure (and errno is set).
inet_pton() returns 1 on success. It returns -1 if there was an error (errno is set), or 0 if the input isn't a valid IP address

20
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Exemple
Exemplu Server
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* portul folosit */
#define PORT 8000

/* codul de eroare returnat de anumite apeluri */


extern int errno;

int main ()
{
struct sockaddr_in server; /* structurile folosite de server si client */
struct sockaddr_in from;
char buffer[100]; /* mesajul trimis de client */
int sd; /* descriptorul de socket */

/* cream un socket */
if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
perror ("Eroare la socket().\n");

21
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

return errno;
}

/* pregatim structurile de date */


bzero (&server, sizeof (server));
bzero (&from, sizeof (from));

/* initializam structura folosita de server */


server.sin_family = AF_INET; /* stabilirea familiei de socket-uri */
server.sin_addr.s_addr = htonl (INADDR_ANY); /* acceptam orice adresa */
server.sin_port = htons (PORT); /* utilizam un port utilizator */

/* atasam socketul */
if (bind (sd, (struct sockaddr *) &server, sizeof (struct sockaddr) ) == -1)
{
perror ("Eroare la bind().\n");
return errno;
}

/* punem serverul sa asculte daca vin clienti sa se conecteze */


if (listen (sd, 5) == -1)
{
perror ("Eroare la listen().\n");
return errno;
}

/* servim clientii unul cate unul */


while (1)
{
int client;
int length = sizeof (from);

printf ("Asteptam la portul %d...\n", PORT);


fflush (stdout);

/* acceptam un client (ne vom bloca pina la realizarea conexiunii) */

22
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

client = accept (sd, (struct sockaddr *) &from, &length);

/* eroare la acceptarea conexiunii de la un client */


if (client < 0)
{
perror ("Eroare la accept().\n");
continue;
}

/* am realizat conexiunea, asteptam mesajul... */


bzero (buffer, 100);
printf ("Asteptam mesajul...\n");
fflush (stdout);

/* citirea mesajului */
if ((nr = recv (client, buffer, 100, 0)) <= 0)
{
perror ("Eroare la read() de la client.\n");
close (client); /* inchidem conexiunea cu clientul */
continue;
}

printf ("Mesajul a fost receptionat...\nTrimitem mesajul inapoi...");

/* returnam mesajul clientului */


if (send (client, buffer, nr, 0) <= 0)
{
perror ("Eroare la write() catre client.\n");
continue;
}

/* am terminat cu acest client, inchidem conexiunea */


close (client);
}

23
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

24
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Exemplu Client
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern int errno;

/* portul de conectare la server*/


int port = 8000;
char * adresa = "127.0.0.1";

int main (int argc, char *argv[])


{
int sd, nr; /* descriptorul de socket */
struct sockaddr_in server; /* structura folosita pentru conectare */
char buffer[100]; /* mesajul trimis */

if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)


{
perror ("Eroare la socket().\n");
return errno;
}

/* initializam structura folosita pentru realizarea conexiunii cu serverul */


server.sin_family = AF_INET; /* familia socket-ului */

25
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

server.sin_addr.s_addr = inet_addr(adresa); /* adresa IP a serverului */


server.sin_port = htons (port); /* portul de conectare */

/* ne conectam la server */
if (connect (sd, (struct sockaddr *) &server, sizeof (struct sockaddr)) == -1)
{
perror ("Eroare la connect().\n");
return errno;
}

/* citirea mesajului si trimiterea catre server */


bzero (buffer, 100);
printf ("Introduceti mesajul: ");
fflush (stdout);

gets(buffer);
nr = strlen(buffer);
if (send (sd, buffer, nr, 0) <= 0)
{
perror ("Eroare la write() spre server.\n");
return errno;
}
/* citirea raspunsului dat de server (asteptam pana cind raspunde serverul)*/
if ( (nr = recv (sd, buffer, 100, 0)) < 0)
{
perror ("Eroare la read() de la server.\n");
return errno;
}
buffer[n] = 0;
printf ("Mesajul primit este: %s\n", buffer);

/* inchidem conexiunea*/
close (sd);
}

26
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Cerinte laborator
Exercitiul 1.
Folosind functiile socket, connect, send, recv si close, scrieti o aplicatie client care trebuie sa indeplineasca urmatoarele cerinte:
• se conecteaza la aplicatia server pe portul 12346 si adresa IP 127.0.0.1
• ii trimite serverului un text (maxim 256 de caractere)
• asteapta de la server un mesaj de maxim 256 de caractere
• inchide conexiunea cu serverul.

Exercitiul 2.
Folosind functiile socket, connect, send, recv si close, scrieti o aplicatie server care trebuie sa indeplineasca urmatoarele cerinte:
• se ataseaza la portul 8080
• primeste mesaje de tip GET in format HTTP/1.1
• raspunde in format HTTP cu un header raspuns
• livreaza fisierul cerut
• mentine conexiunea cu clientul.

Exercitiul 3.
Folosind functiile socket, connect, send, recv si close, scrieti o aplicatie client care trebuie sa indeplineasca urmatoarele cerinte:
• se conecteaza la aplicatia server pe portul 8080 si adresa IP 127.0.0.1
• ii trimite serverului un mesajul GET in format HTTP/1.1
• asteapta de la server un raspuns in format HTTP/1.1
• parseaza si intelege raspunsul, asteapta si receptioneaza daca este cazul un fisier transmis de server
• afiseaza continutul fisrului pe ecran
• inchide conexiunea cu serverul.

27
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Bibliografie suplimentara
 A. Tanenbaum, Reţele de calculatoare (ediţia a patra), Byblos, Tg.Mureş, 2003
 D. Comer, Internetworking With TCP/IP, vol.I: Principles, Protocols, and Architecture (2nd edition), Prentice Hall, New Jersey, 1991
 D. Comer, D. Stevens, Internetworking with TCP/IP: vol.III: Client-Server Programming and Applications, Prentice Hall, New Jersey,
1993
 K. Ross, D. Rubenstein, P2P Systems, Tutorial, 2004
 S. Raab et al., Mobile IP Technology and Applications, Cisco Press, 2005
 J. Doyle, CCIE Professional Development: Routing TCP/IP, Volume I, Macmillan Technical Publishing, 1998
 K. Robbins, S. Robbins, UNIX Systems Programming: Communication, Concurrency, and Threads, Prentice Hall PTR, 2003
 R. Stevens, TCP/IP Illustrated, Volume 1: The Protocols, Addison-Wesley Longman, 1994 –
 R. Stevens, TCP/IP Illustrated, Volume 2: The Implementation, Addison-Wesley Longman, 1995
 R. Stevens, TCP/IP Illustrated, Volume 3: TCP for Transaction, HTTP, NNTP, and the UNIX Domain Protocols, Addison-Wesley
Longman, 1996
 R. Stevens, B. Fenner, A. Rudoff, UNIX Network Programming Volume 1, Third Edition: The Sockets Networking API, Addison Wesley,
2003
 J. Martin, J. Leben, TCP/IP Networking, Prentice Hall, New Jersey, 1994
 A. Abbas, Grid Computing: A Practical Guide to Technology and Applications, Charles River Media, 2004
 M. Ben-Ari, Principles of Concurrent Programming, Prentice Hall International, 1982
 S. Dixit, R. Prasad (eds.), Wireless IP and Building the Mobile Internet, Artech House, 2003
 A. Grama et al., Introduction to Parallel Computing (2nd edition), Addison Wesley, 2003

28
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

 E. Hall, Internet Core Protocols: The Definitive Guide, O'Reilly, 2000


 G. Held, Ethernet Networks (4th edition), John Wiley & Sons, 2003
 A. Jones, J. Ohlund, Network Programming for Microsoft Windows, Microsoft Press, 1999
 A. Kshemkalyani, M. Singhal, Distributed Computing. Principles, Algorithms, and Systems, Cambridge University Press, 2008
 C. McNab, Network Security Assessment, O'Reilly, 2004
 D. Naik, Internet. Standards and Protocols, Microsoft Press, 1998
 K. Robbins, S. Robbins, Unix Systems Programming: Communication, Concurrency, and Threads, Prentice Hall PTR, New Jersey, 2003
 M. Rochkind, Advanced UNIX Programming, Prentice Hall, New Jersey, 1985
 N. Shi (ed.), Mobile Commerce Applications, Idea Group Publishing, 2004
 R. Stevens, Advanced UNIX Programming in the UNIX Environments, Addison-Wesley, Reading MA, 1992
 A. Wells, Grid Application Systems Design, CRC Press, 2008

29
Retele de calculatoare - Introducere in programarea aplicatiilor de retea

Rezumat

 Ce ste un socket?
 Tipuri de socket
 Adrese socket
 Model de comunicatie client – server
 Functii
 Completarea structurii sockaddr_in
 Exemple
 Cerinte pt laborator
 Bibiliografie

Intrebari ?

30

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