Le socket possono essere implementate con svariati linguaggi di programmazione, come c, c# e java. Analizziamo per esempio l’ implementazione in C di un client.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
Dopo aver incluso le opportune librerie indicate sopra viene lanciata la funzione socket:
int socket(int pf, int type, int protocol)
Come possiamo facilmente osservare la chiamata alla funzione socket restituisce un' intero che individua la socket stessa. Chiameremo tale intero socket descriptor. La chiamata di sistema socket richiede 3 argomenti:
L'argomento pf che specifica la famiglia di protocolli da usare con il socket.: l'inter-rete TCP/IP (PF_INET); l'inter-rete PUP della Xerox (PF_PUP); la rete AppleTalk della Apple (PF_APPLETALK); il file system UNIX (PF_UNIX).
L'argomento type specifica il tipo di comunicazione desiderata:
SOCK_STREAM: fornisce una connessione affidabile, sequenziata, a due vie.(TCP)
SOCK_DGRAM: Socket di datagramma (connessione non affidabile) (UDP).
SOCK_RAW: Socket grezzo, per protocolli di rete interna (IP).
SOCK_SEQUPACKET: Socket di pacchetto in sequenza
SOCK_RDM: socket di messaggio consegnato in maniera affidabile (non ancora implementato).
Argomento protocol che forza il sistema ad utilizzare un determinato protocollo. In genere viene utilizzato il valore 0 in modo tale che sia il sistema a scegliere il protocollo più adatto.
Detto questo risulta evidente che per creare una socket è sufficiente scrivere qualcosa del genere:
int sd;
sd = socket(PF_INET, SOCK_STREAM, 0);
Quando un processo smette di usare un socket chiama close, che ha la seguente forma:
close(socket); // per chiudere il socket inizializzato sopra sarà close(sd)
Una volta creata una socket, va in qualche modo specificato a quale indirizzo o a quale porta dobbiamo collegarci per istaurare una comunicazione. A tale proposito viene utilizzata la sockaddr, una particolare struttura utilizzata per passare un indirizzo TCP/IP all'interfaccia dei socket .
La struttura inizia con un campo SOCKET ADDRESS FAMILY a 16 bit che identifica la famiglia di protocolli a cui appartiene l'indirizzo. È seguita da un indirizzo di 14 ottetti al massimo. Il valore nel campo ADDRESS FAMILY determina il formato degli ottetti dell'indirizzo rimanente. Ad esempio, il valore 25 nel campo ADDRESS FAMILY significa che gli ottetti degli indirizzi rimanenti contengono un indirizzo TCP/IP. Ogni famiglia di protocolli definisce come userà gli ottetti nel campo degli indirizzi. Per gli indirizzi TCP/IP l'indirizzo dei socket è noto come sockaddr_in e comprende sia l'indirizzo IP sia il numero di porta. Inizialmente un socket è creato in stato non connesso, che significa che non è associato ad alcuna destinazione esterna. La funzione connect collega permanentemente una destinazione a un socket, ponendolo nello stato connesso. Un programma applicativo deve chiamare connect per stabilire una connessione prima di poter trasferire i dati attraverso un socket con la tecnica del trasferimento di flusso affidabile (TCP). I socket usati per i servizi di datagram senza connessione (UDP) non devono essere collegati per essere utilizzati; l'esecuzione della connect, però, rende possibile trasferire i dati senza specificare ogni volta la destinazione. La funzione connect ha la seguente forma:
int connect(int socket, struct sockaddr * destaddr, int addrlen)
L’ argomento socket specifica il Socket descriptor generato da una chiamata socket precedente. L’ argomento destaddr è un puntatore alla struttura di tipo sockaddr contenente l'indirizzo del server al quale il client deve connettersi. L’ argomento addrlen rappresenta la lunghezza effettiva della struttura che contiene l'indirizzo del server. Una volta che un programma applicativo ha stabilito un socket, può usarlo per trasmettere i dati. Vi sono cinque funzioni tra cui scegliere: send, sendto, sendmsg, write e writev. Queste funzioni sono utilizzate sia dal client che dal server per inviare i dati: il primo invia i dati da elaborare ed il secondo restituisce i risultati dell'elaborazione. Send, write, writev funzionano solo con socket connessi perché non consentono al chiamante di specificare un indirizzo di destinazione. Le differenze tra le tre sono minime. Vediamo per esempio la funzione write():
void write(int socket, void * buffer, int lenght)
Socket contiene un descrittore di socket intero, buffer contiene l'indirizzo dei dati che devono essere inviati e lenght specifica il numero di byte da inoltrare. La chiamata a write è bloccante, cioè blocca l'esecuzione fin che i dati possono essere trasferiti (ad esempio, se i buffer di sistema allocati per il socket sono pieni). Allo stesso modo ci sono cinque funzioni che un processo può usare per ricevere i dati attraverso un socket: read, readv, recv, recvfrom e recvmsg. Anche’ esse vengono utilizzate per ricevere i dati sia dal client che dal server. L'operazione d'input convenzionale, read, può essere utilizzata solo quando il socket è connesso e ha la forma seguente:
void read(int socket, void* buffer, int lenght)
L'argomento socket dà il descrittore intero di un socket o di un file da cui leggere i dati, buffer specifica l'indirizzo in memoria a cui memorizzare i dati e length stabilisce il numero massimo di byte da leggere. Per saperne di più consulta i seguenti approfondimenti:
Tutto quanto riportato in questa pagina è a puro scopo informativo personale. Se non ti trovi in accordo con quanto riportato nella pagina, vuoi fare delle precisazioni, vuoi fare delle aggiunte o hai delle proposte e dei consigli da dare, puoi farlo mandando un email. Ogni indicazione è fondamentale per la continua crescita del sito.