Application Programming Interfaces (API)

Interfetele de programare a aplicatiilor permit programatorilor sa scrie aplicatii care pot face uz de serviciile TCP/IP. Interfata socket este una dintre dinte cele cateva API-uri catre protocoalale de comunicatie.

API Socket Berkeley

In anii '80 Agentia pentru Proiecte de cercetare Avansata (Advanced Research Projects Agency - ARPA) a guvernului SUA a oferit Universitatii Berkeley din statul California fonduri pentru implementarea suitei TCP/IP sub sistemul de operare Unix. Proiectat pentru a fi o interfata generica de programare a comunicatiei, interfata socket a fost pentru prima data introdusa pe sistemul UNIX  BSD 4.2. Cu toate ca nu a fost standardizata, aceasta intefata a devenit un standard industrial de facto. Interfata socket este deosebita de serviciile care sunt furnizate aplicatiilor: socketurile pentru streamuri (stream sockets) (orientate pe conexiune), socketurile pentru datagrame (datagram sockets) (fara conexiune), si socketurile raw (raw sockets) (pentru accesul direct la protocoalele din straturile inferioare).

O varianta a interfetei socket a BSD este asigurata de catre  interfata Winsock dezvoltata de catre Microsoft si alte companii pentru a suporta aplicatii TCP/IP pe sistemele de operare Windows. Winsock 2.0, ultima versiune, asigura o interfata si mai generalizata permitand aplicatiilor sa comunice cu orice protocol din stratul de transport disponibil si cu serviciile de retea aferente, incluzand dar ne limitandu-se la, TCP/IP. Mai multe detalii vor fi date in sectiunea Winsock V2.0.

Principalele functii ale interfetei socket

O trecerea in revista a acestor functii este data in continuare.

FORMAT:

SOCKET sockfd = socket(int af, int type, int protocol)

unde:

af se refera la familia de adrese (sau familii de protocolale). Acest parametru poate lua valori precum AF_UNIX (pentru Unix), AF_INET (pentru Internat), AF_NS (pentru XNS - Xerox Network Services, inclusiv IPX), AF_IPX (pentru IPX si SPX) si AF_NETBIOS (pentru NeTBIOS) si altele. Scopul sau este de a specifica metoda de adresare utilizata de catre socket. Dupa cum se cunoaste formatul adreselor de retea variaza de la o retea la alta. Pe fiecare tip de retea sunt implementate diferite suite de protocoale (familii de protocoale). Diferenta intre familiile de protocoale si de adrese rezida in aceea ca permite programatorilor sa utilizeze protocoale de retea care contin mai multe reprezentari ale adreselor in cadrul aceleiasi suite de protocoale. Pentru familiile de protocoale, in bibliotecile interfetei socket, sunt definite o serie de constante care incep cu prefixul PF_. Astfel pentru internet se foloseste PF_INET. Constantele PF_INET si AF_INET au aceeasi valoare si de aceea multi le folosesc pe una sau pe cealalta.

type se refera la tipul interfetei socket care va fi folosit. Acest parametru poate lua valori precum SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, si SOCK_SEQPACKET.
protocol specifica protocolul. Protocolul este specificat prin constante al caror nume incep cu prefixul IPPROT_. Spre exemplu, pentru protocoalele UDP, TCP, IP si ICMP se folosesc valorile IPPROTO_UDP, IPPROTO_TCP, IPPROTO_IP si IPPROTO_ICMP.
sockfd este un intreg fara semn redefinit ca SOCKET (analog unui descriptor de fisier) returnat de catre apelul functiei socket. In caz de eroare valoarea intoarsa este SOCKET_ERROR avand valoarea -1.

FORMAT:

int bind(SOCKET sockfd, const struct sockaddr FAR *localaddr, int addrlen)

Unde:

sockfd este intregul returnat de catre functia socket.
localaddr este adresa locala returnata de apelul functiei bind.

De retinut ca dupa apelarea functiei bind se obtin valori pentru primii trei parametrii ai cvintetului (asociatiei):

{protocol, local-address, local-process, foreign-address, foreign-process}

FORMAT:

int listen(SOCKET sockfd, int queue_size)

Unde:

sockfd este acelasi intreg returnat de functia socket.
queue_size indica numarul de cereri de conectare care pot fi puse in lista de asteptare de catre sistem in timp ce procesul local nu a emis apelul accept.

FORMAT:

int accept(SOCKET sockfd, struct sockaddr FAR *foreign_address, int addrlen)

unde:

sockfd este  acelasi intreg returnat de functia socket.
foreign_address este adresa procesului (client) strain returnat de catre apelul accept.

De notat ca acest apel al functiei accept este emis de catre procesul server si nu de catre procesul client. Daca exista o cerere de conectare in coada asteptare la acest socket, accept preia prima cerere din lista de asteptare si creaza un alt socket cu aceleasi proprietati ca sockfd; in caz contrar, accept va bloca procesul pana cand apare o cerere de conectare.

FORMAT:

int connect(SOCKET sockfd, struct sockaddr *foreign_address, int addrlen)

Unde:
sockfd este intregul returnat de catre functia socket.
foreign_address este adresa procesului (server) strain returnat de apelul  connect.

Nota: Acest apel este emis de catre procesul client si nu de catre procesul server.

Apelurile read(), readv(sockfd, char *buffer int addrlen), recv(), readfrom(), send(sockfd, msg, len, flags) si write() pot fi folosite pentru a citi sau scrie date de la/la o conexiune stabilita (asociatie socket).

Nota: Aceste apeluri sunt similare apelurilor standard de citire si scriere a fisierelor.

FORMAT:

int close(SOCKET sockfd)

Unde:

sockfd este intregul returnat de catre functia socket.

Utilizarea socketurilor cu un protocol orientat pe conexiune

Figura urmatoare prezinta apelurile tipice pentru socketuri pe care o aplicatie le poate folosi cu un protocol orientat pe conexiune.

Partea din stanga a diagramei reprezinta apelurile de functii facute de server, partea din dreapta reprezinta apelurile de functii ale clientului. Sagetile verticale reprezinta ordinea apelurilor, iar sagetile orizontale fluxul comunicatiei intre cele doua procese.

Apelurile serverului

Pentru implementarea unui server orientat pe conexiune sunt necesare, in ordine, urmatoarele apeluri de functii API.

  1. socket. Serverul creeaza un socket cu functia socket.
  2. bind. Serverul inregistreaza (leaga) socketul la un port local.
  3. listen. Functia listen cere socketului sa astepte cereri de conectare si sa confirme primirea acestora. Functia listen trece socketul intr-o stare de asteptare pasiva.Un socket care sta in ascultare va trimite fiecarui solicitant un mesaj de confirmare ca serverul a receptionat cererea de conectare. Un socket in ascultare nu accepta de fapt cererea de conectare.
  4.  accept. Programul server va trebui sa foloseasca pentru aceasta functia accept.

Apelurile clientului

Pentru implementarea unui client orientat pe conexiune sunt necesare, in ordine, urmatoarele apeluri de functii API.

  1. socket. Clientul creeaza de asemenea un socket cu functia socket.
  2. connect. Clientul nu este interesat de adresa locala de protocol si de acea nu foloseste functia bind. In schimb, clientul orientat pe conexiune initiaza conversatia in retea apeland functia connect.

Dupa ce serverul si clientul stabilesc conexiunea, comunicatia care urmeaza are loc prin intermediul functiilor read si write de ambele parti. Totusi, clientul si serverul mai pot utiliza functiile send si recv sau orice alte functii care lucreaza cu socketuri conectate (precum sendto si recvfrom). 

Utilizarea socketului cu un protocol fara conexiune

Figura urmatoare ilustreaza secventa tipica de apelurile pentru socketuri utilizate la protocoale fara conexiune.

Apelurile serverului

Programul server fara conexiune din figura de mai sus utilizeaza apelurile socket si bind in acelasi mod in care o face si un server orientat pe conexiune. Pentru preluarea datelor de la socket programul server fara conexiune apeleaza functia recvform. Functia recvform nu asteapta realizarea unei conexiuni. In schimb, raspunde oricaror solicitari care sosesc la portul la care s-a inregistrat cu functia bind. Cand functia recvform receptioneaza o datagrama de la socket, ea memoreaza adresa de retea a procesului care a trimis datagrama, precum si datagrama insasi.

De notat ca in cazul protocoalelor fara conexiune si clientul se inregistreaza (leaga) la un port cu functia bind.

Apelurile clientului

In esenta apelurile sunt aceleasi. Deosebirea intre client si server apare si aici din faptul ca dialogul este initiat tot de client prin cererea de serviciu pentru care foloseste functia sendto.

Functiile de transmitere a datelor ale interfetei socket

Aceste functii sunt: send, write, writev, sendto, sendmsg.

Primele trei sunt destinate transmiterii datelor prin socketuri conectate, iar celelalte doua prin socketuri neconectate.

Nota. Pentru datele transmise prin socketuri neconectate se mai foloseste termenul de mesaj. Despre doua aplicatii ce comunica printr-un protocol fara conexiune se spune ca-si transmit mesaje.

Tabelul urmator descrie succind aceste cinci functii.

send Trimite date printr-un socket conectat. Poate utiliza flaguri pentru a controla comportamentul socketului.
write Transmite date printr-un socket conectat folosind un buffer simplu.
writev Transmite date printr-un socket conectat, folosind zone de memorie neadiacente ca buffer de date.
sendto Transmite date printr-un socket neconectat, folosind un buffer simplu de mesaje.
sendmsg Transmite date printr-un socket neconectat, folosind o structura de date flexibila ca buffer de mesaje.

Functiile de receptie a datelor ale interfetei socket

Aceste functii sunt: recv, read, readv, recvfrom, recvmsg.

Primele trei sunt destinatereceptiei datelor prin socketuri conectate, iar celelalte doua prin socketuri neconectate.

Tabelul urmator descrie succind aceste cinci functii.

recv Receptioneaza date printr-un socket conectat. Poate utiliza flaguri pentru a controla comportamentul socketului.
read Receptioneaza date printr-un socket conectat folosind un buffer simplu.
readv Receptioneaza date printr-un socket conectat, folosind zone de memorie neadiacente ca buffer de date.
recvfrom Receptioneaza date printr-un socket neconectat, folosind un buffer simplu de mesaje.
recvmsg Receptioneaza date printr-un socket neconectat, folosind o structura de date flexibila ca buffer de mesaje.

Cu cateva exceptii (functiile read, write si close ), detalii asupra acestor functii se gasesc in sectiunea Interfata Socket Berkeley implementata de Microsoft pe sistemele Windows.

Cornel Mironel Niculae, 2004-2005
22-Nov-2005