• Il protocollo TCP controlla che la trasmissione tra due end points avvenga correttamente. Non stabilisce alcun criterio su chi deve iniziare la comunicazione. • Questo compito è svolto dalle applicazioni che utilizzano TCP per la trasmissione dei dati usando un proprio protocollo, detto protocollo di applicazione. Unix: strumenti di sincronizzazione, memorizzazione, comunicazione Uso di segnali (sincronizzazione) • I protocolli di applicazione si basano sul modello client-server: quindi e’ precisato chi inizia la comunicazione (client) e a chi è diretta (server). Uso di file (memorizzazione) • Ai più diffusi protocolli dello strato applicazione sono stati assegnati numeri di porta specifici. Ad es., un processo server web (che usa il protocollo HTTP) è identificato dal numero di porta 80. IPC • Un server di posta (che usa il protocollo SMTP) è identificato dal numero di porta 25. Inter cas Process o Communication solo tra processi che condividono un file system pipe (solo tra processi con un avo in comune) rem •Un elenco di ben conosciuti numeri di porta per tutti i protocolli standard di Internet è contenuto nella RFC 1700. Quando un programmatore crea una nuova applicazione, ad esso deve essere assegnato un nuovo numero di porta 1 processo invia limitata quantità info (solo un tipo di segnale) e manca il mittente del segnale ot o pipe con nome (per processi su una stessa macchina) shared memory (stessa macchina) Socket (e RPC) 2 Aspetti caratteristici della comunicazione dei processi attraverso socket: SOCKET •Strumenti disponibili nei S.O. della famiglia Unix/Linux per la realizzazione dell’interazione tra processi all’interno di una rete. •Eterogeneità: la comunicazione può avvenire tra oggetti che risiedono in architetture diverse; •UNIX BSD 4.2. Interfaccia di programmazione (API) specifica per lo sviluppo di applicazioni di rete. Libreria di funzioni C basata sul concetto di socket. •Trasparenza: la comunicazione tra processi avviene con le stesse modalità, indipendentemente dalla localizzazione fisica dei processi comunicanti; •Una socket rappresenta il mezzo di comunicazione mediante il quale un processo può scambiare messaggi con altri processi. •Indipendenza dalla rete :l’interfaccia di comunicazione è indipendente dall’architettura della rete; •Compatibilità con i file: le socket sono rappresentate all’interno dei programmi in modo omogeneo ai file 3 4 1 Tipo di socket Proprietà delle socket Tipo: denota lo stile di comunicazione. • Dominio di comunicazione. Ambiente nel quale avviene la comunicazione (rete internet: dominio PF-INET; Stesso S.O. Unix: PF_UNIX) connection-oriented (utilizzo di un canale virtuale) connection-less (senza canale) Socket stream • Caratteristiche semantiche della comunicazione. Affidabilità, comunicazione uno a uno, uno a molti. - Connection oriented (affidabilità) - Comunicazione simmetrica uno-a- uno - Creazione del canale prima dell’inizio della comunicazione (es., funzione connect); chiusura del canale al termine della comunicazione(es.: funzione shutdown). • Denotazione dei processi comunicanti Regole di formato da adottare per esprimere l’indirizzo dei nodi Socket datagram - Connectionless (non affidabile) - Possibilità di comunicazione con più di un processo (comunicazione asimmetrica) 5 Dominio di comunicazione proc A Messaggio 1 Dominio di comunicazione Canale virtuale Proc B proc Messaggio 2 6 Proc A B Proc C Socket stream Socket datagram 7 8 2 Struttura dati associata alla socket Nel caso del dominio PF-INET l’indirizzo di una socket viene espresso attraverso questa struttura: • Nel dominio Internet (PF-INET) ogni socket è individuata da: struct sockaddr-in { sa-family-t sin-family; in-port-t sin-port; struct-in-addr sin-addr; char sin.zero [8] } Indirizzo IP del nodo in cui risiede il processo proprietario della socket. Numero della porta cui è associata la socket • Ogni processo che intende comunicare con altri processi deve: /*dominio*/ /*porta*/ /*ind.nodo*/ /*non usato*/ dove il tipo del campo sin_addr, che rappresenta l’indirizzo del nodo, e` dichiarato nel modo seguente: struct in_addr { uint32_t s_addr}; Creare una socket. Ogni socket viene rappresentata localmente mediante un file descriptor. Renderla individuabile univocamente dai processi del dominio attraverso la specifica del suo indirizzo 9 10 Socket I tipi di dato non primitivi utilizzati nelle precedenti definizioni sono descritti nella tabella A. 2, in cui vengono anche indicati i file header in cui sono contenute le rispettive dichiarazioni. nodo: indirizzo IP nodo: indirizzo IP Processo A Tipo sa_family_t in_port_t uint32_t sockaddr sockaddr_in Descrizione Header file Tipo associatoal dominio <sys/types.h> Tipo associato alla porta <netinet/in.h> (di solito unsigned int a 16 bit) unsigned int a 32 bit <sys/types.h> Tipo generico associato all’indirizzo <sys/socket.h> di una socket Tipo specifico per l’indirizzo di una socket nel dominio internet (IP v.4) <sys/socket.h> socket porta Processo B socket Internet (TCP/IP) porta Il canale di comunicazione tra il processo A e il processo B è definito da: 11 <protocollo; indirizzo IP locale; porta locale; indirizzo IP remoto; porta remota> 12 3 Strutture dati Socket FORMATO INDIRIZZI Una socket è creata all’interno di un dominio di comunicazione Dominio di comunicazione: semantica di comunicazione + standard di denominazione DOMINIO AF_ UNIX : L’indirizzo ha lo stesso formato del nome di un file (pathname). Esempi di domini: UNIX, Internet, etc. struttura dati socket family: PF_INET service: SOCK_STREAM local IP: 137.204.57.33 remote IP: .... local port: 12345 remote port: ..... pgid: .................... _ : indirizzo Internet composto DOMINIO AF_INET da indirizzo IP dell’host (32 bit) e da numero di porta (16 bit) DOMINIO - Protocol Family: Internet (oppure AF_INET, Address Family Internet) TIPO della socket: STREAM o DATAGRAM INDIRIZZO macchina locale (NB. il formato dell’indirizzo dipende dal dominio di comunicazione della socket) gruppo di processi associati alla socket 13 Creazione di una socket 14 Associazione socket - indirizzo locale sd = socket (dominio, tipo, protocollo); int sd, dominio, tipo, protocollo; Crea una SOCKET e ne restituisce il descrittore sd (socket descriptor). error = bind (sd, ind, lun); int error, sd; struct sockaddr * ind; int lun; dominio denota il particolare dominio di comunicazione (es. AF_INET) tipo indica il tipo di comunicazione (es. SOCK_STREAM o SOCK_DGRAM) protocollo specifica uno dei protocolli supportati dal dominio (se si indica zero viene scelto il protocollo di default) Definisce il protocollo usato dalla socket. In una connessione definisce: <protocollo;indirizzo IP locale;porta locale;indirizzo IP remoto;porta remota> 15 Associa alla socket di descrittore sd l’indirizzo codificato nella struttura puntata da ind e di lunghezza lun (la lunghezza è necessaria, poiché la funzione bind può essere impiegata con indirizzi di lunghezza diversa) Collega la socket a un indirizzo locale. In una connessione definisce : <protocollo;indirizzo IP locale;porta locale;indirizzo IP remoto;porta remota> 16 4 Comunicazione connection-oriented Comunicazione connection oriented (lato Server) (socket STREAM o TCP) error = listen (sd , dim); int error , sd , dim; Collegamento (asimmetrico) tra processo Client e processo Server: 1) il server e il client devono creare ciascuno una propria socket e definirne l’indirizzo (primitive socket e bind) Trasforma la socket sd in passiva (listening), pronta per ricevere una richiesta di connessione. 2) deve essere creata la connessione tra le due socket Crea una coda, associata alla socket sd in cui vengono inserite le richieste di connessione dei client. 3) fase di comunicazione La coda può contenere al più dim elementi. 4) chiusura delle socket Le richieste di connessione vengono estratte dalla coda quando il server esegue la accept(). 17 Comunicazione connection oriented (lato Client) 18 Comunicazione connection oriented (lato Server) nuovo_sd = accept (sd , ind, lun); int nuovo_sd , sd; struct sockaddr * ind; int * lun; Indirizzo è parametro in/out error = connect (sd, ind, lun) ; int error, sd; struct sockaddr * ind; int lun; Richiede la connessione fra la socket locale il cui descrittore è sd e la socket remota il cui indirizzo è codificato nella struttura puntata da ind e la cui lunghezza è lun. Estrae una richiesta di connessione dalla coda predisposta dalla listen(). Se non ci sono richieste di connessione in coda, sospende il server finché non arriva una richiesta alla socket sd. La connect() può determinare la sospensione del processo?? Quando la richiesta arriva, crea una nuova socket di lavoro nuovo_sd e restituisce l’indirizzo della socket del client tramite ind e la sua lunghezza tramite lun. Definisce l’indirizzo remoto a cui si collega la socket: <protocollo;indirizzo IP locale;porta locale;indirizzo IP remoto;porta remota> La comunicazione (read/write) si svolge sulla nuova socket nuovo_sd 19 20 5 Protocollo di creazione del canale virtuale Comunicazione connection oriented processo client nodo: indirizzo IP Processo Client socket client porta client asc nodo: indirizzo IP Processo Server socket server (sd) listen() + accept() rete (TCP/IP) csd=socket (…) connect(csd. crea porta server <comunicazione attraverso il canale> asc=socket( ..) bind(asc.) Listen(asc ssd socket server (nuovo_sd) read() e write() crea richiesta di csd connessi one canale virtuale crea ssd=accept(asc . <comunicazione attraverso il canale> 21 22 Processo client Una volta creato il canale virtuale i due processi agli estremi di esso (client e server) possono scambiarsi messaggi in entrambe le direzioni (write, read) int csd; char msg[6]; <creazione socket ed apertura del canale>; read (ssd,msg,6); La spedizione di un messaggio viene richiesta tramite la system call write alla quale si fornisce il socket descriptor associato alla socket locale Le socket sono bloccanti: se un destinatario esegue la read quando non vi è alcuna informazione all’interno del canale, il processo viene sospeso. Il server può spedire un messaggio al client nel modo seguente: int asc,ssd; char msg[6] = 34Ciao!34; TCP non prevede separatori tra un messaggio e il successivo: il contenuto del canale è visto come una sequenza non strutturata di byte Accordo tra i due processi sulle caratteristiche dei messaggi (es. lunghezza costante prefissata) <creazione socket ed apertura del canale> write (ssd,msg,6) 23 24 6 • Al termine di una sessione di comunicazione, la connessione può essere chiusa mediante la primitiva shutdown (int sd,int modo) dove sd rappresenta il socket descripror associato al terminale del canale modo esprime la modalità di chiusura. • E’ possibile chiudere il canale soltanto in una direzione (valore 0 per la ricezione,valore 1 per la trasmissione) oppure in entrambe (valore di modo uguale a 2). • Se la chiusura avviene in entrambe le direzioni la socket sd viene eliminata. Processo client # include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> struct sockaddr_in *D, *server; char msg[2000]; int sd, l; int main() { sd=socket(AF_INET,SOCK_STREAM,0); <inizializzazione indirizzo server> /* richiesta di connessione*/ connect(sd,&server,l); <preparazione messaggio msg>; write(sd, msg,2000); /*invio messaggio*/ read(sd,ris, 2000); /*ricezione risposta */ shutdown (sd,2); /*chiusura connessione*/ 25 Processo server #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> struct sockaddr_in *M, *mio; char msg[BUFFERSIZE], ris[2000]; int asc, l,sd, addrlen ; int main() { asc=socket(AF_INET,SOCK_STREAM,0); <inizializz. mio indirizzo> l=sizeof(struct sockaddr_in); bind (asc,&mio,l); /* pubblicazione indirizzo*/ listen(asc, 100); /*creazione della coda richieste*/ sd=accept(asc, M, &addrlen); /* apertura canale*/ read (sd, msg, 2000); /*ricezione messaggio*. <calcolo risposta ris> write (sd, ris, 2000); /*invio risposta*/ } } 26 Socket datagram Poiché la comunicazione è senza connessione, in questo caso ogni processo, dopo aver creato la socket ed effettuato l’operazione di binding, può già utilizzarla per la comunicazione con altri processi. system call specifiche di spedizione e ricezione dei messaggi sono sendto e recvfrom. int sendto(int s, char *msg, int lun, int flag, struct sockaddr *D, int lunD); sd rappresenta il socket descriptor associato alla socket locale; msg è il puntatore al messaggio da inviare; lun è la lunghezza del messaggio; flag è un intero mediante il quale è possibile specificare opzioni particolari sul trasporto del messaggio; D è il puntatore alla struttura che contiene l’indirizzo della socket; lunD e` la lunghezza della struttura puntata da D; 27 28 7 La primitiva di ricezione prevede una sintassi analoga: int recvfrom(int sd, char *msg, int lun, int flag, struct sockaddr *M, int *lunM); sd rappresenta il socket descriptor associato alla socket locale; msg è il puntatore alla variabile a cui assegnare il messaggio ricevuto; lun è la lunghezza del messaggio; flag è un intero mediante il quale è possibile specificare opzioni particolari sul trasporto del messaggio; M e` il puntatore alla struttura nella quale viene memorizzato l’indirizzo della socket del mittente; lun e` la lunghezza della struttura puntata da M; • La recvfrom può bloccare il processo destinatario, se il messaggio non è ancora disponibile; a differenza della comunicazione mediante stream, in questo caso i confini dei messaggi vengono mantenuti , e il processo quindi viene sospeso fino a che l’intero messaggio non gli è stato recapitato. • A differenza del caso di comunicazione con connessione, le primitive di comunicazione prevedono parametri specifici per gli indirizzi dei partner nella comunicazione: nell’invio è necessario specificare l’indirizzo del destinatario; nella ricezione è previsto che, assieme al messaggio la recvfrom fornisca anche l’indirizzo del mittente. • Per chiudere una socket datagram è possibile usare ancora la system call shutdown, oppure la system call close 29 Comunicazione senza connessione (socket DATAGRAM) Server Process socket() Client Process bind() socket() recvfrom() 1 <attesa richiesta> sendto() 2 recvfrom() <attesa risp> <elaborazione> sendto() close() close() 31 30 Process Client include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> struct sockaddr_in *D, *mio; char msg[2000], ris[BUFFERSIZE]; int sd, l, addrlen; main() { sd=socket(AF_INET,SOCK_DGRAM,0); <inizializz. mio indirizzo> l=sizeof(struct sockaddr_in); bind (sd,&mio,l); /* invio messaggio al server: */ sendto (sd, msg, 2000, 0, D,l); /* ricezione risposta: recvfrom (sd, ris, BUFFERSIZE,0, D, &addrlen); ... close(sd); } 32 8 Processo server #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> struct sockaddr_in *M, *mio; char msg[BUFFERSIZE], ris[2000]; int sd, l, addrlen; main() { sd=socket(AF_INET,SOCK_DGRAM,0); <inizializz. mio indirizzo> l=sizeof(struct sockaddr_in); bind (sd,&mio,l); addrlen =l; /* ricezione messaggio:*/ recvfrom (sd, msg, BUFFERSIZE,0, M, &addrlen); <calcolo risposta ris> /*invio risposta:/ sendto (sd, ris, 2000, 0, M, addrlen); ... close(sd); } Considerazioni conclusive sulle socket UDP : • UDP non è reliable, in caso di perdita del messaggio del Client o della risposta del Server, il Client si blocca in attesa indefinita della risposta (utilizzo di timeout?) • Blocco del Client anche nel caso di invio di una richiesta a un Server non attivo (errori nel collegamento al server notificati solo sulle socket connesse) • UDP non ha flow control, se il Server riceve troppi datagrammi per le sue capacità di elaborazione, questi vengono scartati, senza nessuna notifica ai Client 33 Quale tipo di Socket? Quale livello di trasporto, UDP o TCP? Quale tipo di Socket utilizzare? Utilizzare TCP (con connessione) quando: Fare molta attenzione alle differenze semantiche tra le socket STREAM e quelle DATAGRAM, che in genere guidano nella scelta: servizi che richiedono una connessione connectionless 34 • affidabilità fondamentale • l’ordine dei messaggi è importante • si vuole semantica at-most-once servizi (servizio del server non idempotente, server con stato) Utilizzare UDP (senza connessione) quando: Problema dell’affidabilità (STREAM si basano su TCP e sono quindi affidabili, DATAGRAM si basano su UDP e quindi non sono affidabili) • si vuole fare del broadcast/multicast • troppe connessioni sarebbero richieste • le prestazioni sono fondamentali (le socket DATAGRAM hanno un costo inferiore, non si deve stabilire una connessione, etc.) Prestazioni: STREAM hanno costo più elevato delle DATAGRAM • non ci sono problemi di ordinamento messaggi (es. ogni msg contenuto in un pacchetto UDP) • va bene una semantica may-be 35 36 9 Un esempio: esecuzione remota di comandi •Esecuzione remota di semplici comandi di un client su un server e visualizzazione locale dell’output prodotto dai comandi eseguiti. •Il client deve richiedere la creazione della connessione e successivamente inviare un messaggio contenente il nome di un comando. •Il client si pone in attesa della risposta, rappresentata dall’output del comando eseguito dal server; ogni byte ricevuto attraverso il canale viene copiato dal client sul dispositivo di standard output. Processo client: #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> main(int argc, char **argv) { int sock, retval, i; char mess[10], ris[1000]; struct sockaddr_in rem_ind; /*indirizzo socket remota*/ /* Preparazione indirizzo del server */ rem_ind.sin_family = PF_INET; /*dominio*/ /* ad esempio: se l’indirizzo internet del nodo server e` 137.204.57.115:*/ rem_ind.sin_addr.s_addr=inet_addr("137.204.57.115"); rem_ind.sin_port = 22375; /* numero di porta del server*/ 37 38 Processo server • Ogni processo server ha tipicamente una struttura ciclica: ad ogni iterazione viene servita una particolare richiesta di connessione. /* Preparazione del messaggio*/ strcpy(mess, argv[1]); /* Creazione della socket */ sock=socket(PF_INET, SOCK_STREAM, 0); connect(sock, &rem_ind, sizeof(struct sockaddr_in)); write(sock,mess, 10); /*invio messaggio*/ while (i=read(sock,ris, 1)>0) /*ric. risposta*/ write(1,ris,i); /* stampa su std. output */ shutdown(sock,2); /* chiusura collegamento*/ } • Il processo server può, in generale, servire le richieste in modo sequenziale (viene servita una richiesta per volta) o concorrente (vengono servite più richieste in parallelo). Nell’esempio il server è servito in modo sequenziale. • Prima di entrare nel ciclo di servizio, il server crea la socket di ascolto, ne pubblica l’indirizzo mediante l’operazione di binding; successivamente, con la primitiva listen associa alla socket di ascolto una coda nella quale verranno inserite le eventuali richieste di connessione. 39 • Per ogni richiesta, dopo aver instaurato una nuova connessione dedicata ad essa (mediante accept), verrà creato un nuovo processo che: ricevera` dal canale il nome del comando da eseguire e, successivamente, dopo aver opportunamente ridirezionato la socket di comunicazione sullo standard output, passerà ad eseguire il comando mediante una system call della famiglia exec Al termine dell’esecuzione del comando, il processo server 40 chiudera` la socket e passera` al servizio di nuove richieste. 10 Processo server:*/ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> main() { char comando[20]; int newsock, sock, figlio, status, i; struct sockaddr_in mio_ind; /* Creazione socket di ascolto */ sock=socket(PF_INET, SOCK_STREAM, 0); /* Preparazione indirizzo socket : */ mio_ind.sin_family=PF_INET; mio_ind.sin_addr.s_addr = INADDR_ANY; mio_ind.sin_port=22375; /* Binding:*/ if(bind(sock, &mio_ind, sizeof(struct sockaddr_in))<0) { perror("bind"); exit(1); } /* sock ricevera` le richieste di connessione: */ listen(sock, 5); /*creaz. coda richieste connessione*/ for (;;)/* ciclo di servizio */ { /* estrazione nuova richiesta dalla coda: */ newsock=accept(sock,(struct sockaddr_in *) 0, 0); if ((figlio=fork())==0) { /* figlio */ close(sock); read(newsock, comando, 10); /* ricez. comando*/ /*ridirezione dell’output sulla socket: */ close(1); dup(newsock); 41 /* esecuzione comando: */ if((i=execlp(comando, comando, (char )0))<0) { write(1,"errore", 7); exit(-1); } } /* figlio*/ else /*padre*/ { wait(&status); /* attesa figlio */ shutdown(newsock, 1); /* chiusura socket: */ close(newsock); } } close(sock); } 42 Controllato dal gestore dell’applicazione Controllato dal sistema operativo Processo Processo Socket Socket TCP con buffer, variabili Host o server 43 Internet TCP con buffer, variabili Controllato dal gestore dell’applicazione Controllato dal sistema operativo Host o server 44 11 Processo client Processo server Stretta di mano a tre vie Socket di benvenuto Socket del client byte byte Socket di connessione tempo 45 12