Reţele de calculatoare
Conf.
Dr. Carmen Timofte (Stanciu)
- Exemple
o Comunicaţie client-server pe TCP/IP
o Comunicaţie client-server pe UDP/IP
-
protocoalele
- când o aplicaţie trimite o cerere către nivelul transport pentru a trimite un mesaj, protocolul folosit la acest nivel:
o împarte informaţia în pachete
o adaugă un antet de pachet care include adresa destinaţiei
o trimite informaţia nivelului reţea pentru procesare ulterioară
- transmisa şi recepţia datelor se realizează prin intermediul unor porturi de pe server, care identifică destinaţia specifică a mesajului;
-
nivelul transport este implementat
în reţelele
o UDP (User Datagram Protocol)–protocol datagramă utilizator –
§ Asigură servicii de tip datagramă nivelului aplicaţie;
§ Nu este fiabil (nu asigură certitudinea livrării datagramelor, nici mecanismele de protecţie la pierderea sau duplicarea datagramelor);
§ Viteză mare de transmisie;
§ Este un serviciu fără conexiune (emiţătorul nu cunoaşte starea receptorului în momentul transmisiei);
§ Pt. transferul datelor foloseşte nişte entităţi abstracte, numite porturi de protocol, identificate prin numere întregi pozitive şi care au asociate nişte cozi de mesaje prin care se transmit mesajele;
§ Se utilizează pt. mesaje mici (sub 8KB) cu viteză mare;
§ Antetul datagramei UDP conţine:
· Source Port Number- adresa portului sursă;
· Destination Port Number – adresa portului destinaţie;
· Length – lunginea datagramei în bytes;
· Checksum – suma de control asociată datagramei (foloseşte acelaşi algoritm ca la protocolul IP)
o
§ Este fiabil (asigură integritatea datelor transmise, mecanisme de protecţie la pierderea sau duplicarea pachetelor, păstrarea numărului de secvenţă, mecanisme de control al fluxului de date în reţea);
§ Asigură transmisia blocurilor continue de date între porturile de protocol asociate aplicaţiilor;
§ Dimensiunea mesajelor nu este limitată;
§ Viteza de transfer mai mică;
§ Este un serviciu cu conexiune (emiţătorul
cunoaşte starea receptorului în momentul
transmisiei);
- SO oferă programelor la nivel aplicaţie o interfaţă comună pt. aceste 2 protocoale, şi anume interfaţa socket.
Este o interfaţă între un program de aplicaţie şi serviciul de transport (este un standard de facto), fiind furnizat de o bibliotecă socket sau de sistemul de operare. Se foloseşte conceptul de descriptor, fiecare socket fiind tratat asemănător cu un fişier local. Acest descriptor este transmis aplicaţiei la crearea socket-ului şi apoi este utilizat ca argument în apelurile următoare
Descriptor = socket(protofamily, type, protocol) |
creează un socket |
close(socket) |
închide un socket |
bind(socket,
localaddr, addrlen) |
leagă socket-ul cu un
port |
listen(socket,queuesize) |
pune socket în mod pasiv |
newsock = accept(socket,
caddress, caddresslen) |
acceptă o cerere de conectare |
connect(socket,
saddress, saddresslen) |
stabileşte
legătura cu un server care a făcut accept |
send(socket,
data, length, flags) |
transmite un mesaj |
sendto(socket,
length, flags, destaddress, addresslen) |
transmite un mesaj folosind un socket
neconectat |
sendmsg(socket,
msgstruct, flags) |
|
recv(socket,
buffer, length, flags) |
primeşte un mesaj |
recvfrom(socket,
buffer, length, flags, sndaddr, saddrlen) |
primeşte un mesaj pe
un socket neconectat |
rcvmsg(socket,
msgstruct, flags) |
|
În acest exemplu, serverul păstrează evidenţa numărului de clienţi care au accesat resursa şi raportează acest număr la fiecare apel.
Exemplu de folosire a interfeţei
sockets. |
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
¨ 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 ccepta o cerere de conectare şi a crea un socket nou poentru această conexiune
¨ send pentru a trimite date
¨ close pentru a închide noul socket.
Primitive blocante folosite sunt accept, connect (3 way handshake) şi gethostbyname (conectare cu un server de nume).
– inovaţie a sistemului Berkeley UNIX;
– este un punct de comunicaţie prin care un proces poate emite sau recepţiona informaţie sub forma unui flux de bytes;
– este identificat printr-un descriptor, asemănător cu cel pentru fişier
– realizează următoarele operaţii elementare:
o conectarea la staţia de la distanţă
o emiterea datelor
o recepţionarea datelor
o închiderea unei conexiuni
o ataşarea la un port
o aşteptarea cererilor de conexiune emise de staţiile de la distanţă
o acceptarea cererilor de conexiune la portul local
O aplicaţie de reţea include:
- un program client – care creează un socket pt. a iniţia o conexiune cu o aplicaţie server
- un program server – care aşteaptă preluarea cererilor clienţilor
/* Modul SERVER
#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)
{
unsigned short port; /* portul client */
char buffer[32];
struct sockaddr_in client, server;
/*adresele client, server*/
struct hostent * srvinfo;
int s, 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("A preluat numele serverului.... \n");
printf("Nume server: %s \n", buffer);
/*preia informatiile despre configurarea hostului*/
if (!(srvinfo=gethostbyname(buffer)))
perror("Eroare la
preluarea informatiilor despre server");
printf("A preluat informatiile despre
configurarea hostului.... \n");
port=(unsigned
short) atoi(argv[1]);
/*Creeaza
un socket*/
if ((s=socket(AF_
{
perror("Eroare la creare socket");
exit(3);
}
printf("A creat socketul.... \n");
/*Asociaza
socketului o adresa de server */
memset(&server, 0, sizeof(server));
server.sin_family = AF_
server.sin_port = htons(port);
server.sin_addr.s_addr = inet_addr("193.226.62.247");
/* adresa Internet locala */
printf("A asociat socketului o adresa
de serv.... \n");
if ( bind ( s, &server, sizeof(server)) <0)
{
perror("Eroare la obtinerea adresei");
exit(4);
}
printf("A facut bind....
\n");
/*Creeaza
coada pentru cererile de conexiune; va prelua maxim 5 cereri de conexiune de la
clienti, restul fiind refuzate */
if (listen(s, 5) != 0)
{
perror("Eroare la obtinerea cozii de cereri");
exit(5);
}
printf("A facut listen....
\n");
/* Creeaza
un descriptor de socket pt. comunicatia
server-client */
namelen = sizeof(client);
if ((ns = accept( s, &client, &namelen))
== -1)
{
perror("Eroare la acceptarea
conexiunii");
exit(6);
}
printf("A facut accept.... \n");
/* Receptioneaza
mesajul de la client */
if(recv(ns, buffer, 32, 0) == -1)
{
perror ("Eroare la receptie");
exit(7);
}
/* Afiseaza
mesajul primit de la client */
printf("Mesaj receptionat de la client,
pe TCP-gr...., Nume Prenume: %s \n", buffer);
/*Trasmite
confirmarea clientului */
if (send(ns, buffer, strlen(buffer),
0) <0)
{
perror("Eroare la
transmisie");
exit(8);
}
printf("A facut send....
\n");
endhostent(); /* inchide sesiunea
close(ns);
close(s);
printf("A inchis socket
2 si1 ... \n");
exit(0);
}
/* Modul CLIENT
/* Modul SERVER UDP
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
main()
{
char buffer[32];
struct sockaddr_in client, server;
/*adresele client, server*/
int s, namelen;
/*Creeaza
un socket*/
if ((s=socket(AF_
{
perror("Eroare la creare socket");
exit(1);
}
printf("A creat socket-ul....\n");
/*Asociaza
socketului o adresa de server */
memset(&server, 0, sizeof(server));
server.sin_family = AF_
server.sin_port = 0; /* orice port */
server.sin_addr.s_addr = INADDR_ANY;
if ( bind( s, &server, sizeof(server)) <0)
{
perror("Eroare la obtinerea adresei");
exit(2);
}
printf("A facut bind .....\n");
/* Determina portul
asignat*/
namelen = sizeof(server);
if (getsockname(s, (struct
sockaddr *) &server, &namelen))
{
perror("Eroare la
determinarea portului");
exit(3);
}
printf("\n Portul asignat este: %d\n", ntohs(server.sin_port));
namelen = sizeof(client);
/* Receptioneaza
mesajul de la client */
/*
if (recvfrom (s, buffer, 32, 0, &client, sizeof(client))
< 0)
*/
if (read(s,buffer,32)<0)
{
perror ("Eroare la receptie");
exit(4);
}
printf("A receptionat mesajul de la
client pe UDP, Grupa...., Nume Prenume.... \n");
/* Afiseaza
mesajul primit de la client */
printf("\n Mesajul receptionat de la
client este: %s \n", buffer);
/*printf("Parametrii
client: \n Nume domeniu: %s \n \Port: %d \n Adresa \Internet: %d \n", (client.sin_family == AF_
printf("Parametrii server: \n Nume domeniu: %s \n \Port: %d \n
Adresa \Internet: %d \n", (server.sin_family ==
AF_
close(s);
exit(0);
}
/* 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)
{
unsigned short port; /* portul client, acelasi
ca cel specificat in modulul server */
char
buffer[32];
struct sockaddr_in server; /*adresa server*/
int s;
if(argc!= 2)
{
printf("Apel:
%s port \n", argv[0]);
exit(1);
}
port=(unsigned short) atoi(argv[1]);
strcpy(buffer,
"Mesaj socket, UDP- user...");
/*preia
informatiile despre server*/
server.sin_family
= AF_
server.sin_port
= htons(port);
server.sin_addr.s_addr = inet_addr("193.226.62.247");
/* aceeasi ca la server */
if ((s=socket(AF_
{
perror("Eroare
la creare socket");
exit(2);
}
printf("A
creat socketul.... \n");
/*
Transmite mesajul serverului */
if(sendto(s, buffer, strlen(buffer)+1,
0, &server, sizeof(server)) < 0)
{
perror ("Eroare la transmisie");
exit(3);
}
printf("A
transmis mesajul serverului.... \n");
close(s);
printf("A
inchis socketul....
\n");
exit(0);
}