Applicazione distribuita

Похожие документы
Reti (già Reti di Calcolatori )

Socket. Nei sistemi operativi moderni i servizi disponibili in rete si basano principalmente sul modello client/server.

Socket. Nei sistemi operativi moderni i servizi disponibili in rete si basano principalmente sul modello client/server.

Esercitazione [7] Client/Server con Socket

L uso di Socket UDP. Usiamo le API Winsock incluse in <Winsock.h> A.A. 2005/06. Dott.ssa Valeria Carofiglio

L interfaccia socket

Esercitazione [6] Client/Server con Socket

COMUNICAZIONE TRA PROCESSI REMOTI IN UNIX

IPC Inter Process Communication

L uso di Socket UDP. TCP vs. UDP UDP

unsigned long inet_addr(cp) char *cp;

TECN.PROG.SIST.INF. I Socket Roberta Gerboni

Interazione (TCP) Client-Server con le socket

DATAGRAM SOCKET. Angelastro Sergio Diomede Antonio Viterbo Tommaso

Interazione (TCP) Client-Server con le socket

I Socket. Laboratorio Software M. Grotto R. Farina

Esempio 1: stampa locale di file remoto

Lo strato di applicazione in Internet

Cenni di programmazione distribuita in C++ Mauro Piccolo

Paradigma client-server

Creare una applicazione Winsock di base

Socket TCP. seconda parte

Introduzione alla programmazione C di socket

API Socket di Berkeley

Acknowledgment: Prof Vincenzo Auletta, Università di Salerno. Approfondimento alla programmazione distribuita

Una semplice applicazione client/server 1

Guida all' uso dei sockets nella programmazione in C

Il modello Client/Server. La comunicazione

request reply richiesta client processo di servizio processo server principale From - Valeria Cardellini, Corso Sist. Distr. A.A.

Esercitazione di Lab. di Sistemi Operativi 1 a.a. 2011/ Comunicazione Tra Processi (IPC) Parte -

Elementi di programmazione con interfaccia Socket

Socket TCP. prima parte

Introduzione alle applicazioni di rete

Транскрипт:

La programmazione di applicazioni distribuite in C Il concetto di applicazione distribuita L architettura di una applicazione distribuita Il paradigma a scambio di messaggi Il paradigma client-server Il paradigma peer-to-peer Lo sviluppo di applicazioni distribuite in C I socket TCP/ IP in C Un esempio di uso dei socket TCP/ IP in C Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 1 Applicazione distribuita Definizione: Applicazione costituita da due o più processi che eseguono in parallelo su macchine distinte connesse da una rete di comunicazione I processi che costituiscono una applicazione distribuita cooperano sfruttando i servizi forniti dalla rete di comunicazione Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 2 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 1

Architettura di una applicazione distribuita Una applicazione distribuita è caratterizzata dalla propria architettura run-time Definizione: Con il termine architettura run-time si indica l organizzazione dei componenti (processi) che costituiscono l applicazione a run-time Elementi caratteristici di una architettura Tipologia e ruolo dei componenti Tipologia delle connessioni Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 3 Le architetture basate su scambio messaggi Lo scambio messaggi è il paradigma di comunicazione più semplice per lo sviluppo di applicazioni distribuite Identifica una categoria di architetture distinte Caratteristiche: Ogni componente dell applicazione possiede uno o più indirizzi Un componente A comunica con un componente B spedendo un messaggio ad uno degli indirizzi associati a B Principali architetture basate su scambio messaggi: Architetture client-server Architetture peer-to-peer Architetture a tre livelli (three-tiered architecture) Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 4 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 2

L architettura client-server Caratteristiche: Componenti distinti in due tipi: client e server I server erogano un servizio I client sfruttano tale servizio Comunicazioni basate su scambio messaggi Browser Esempio: il web Client: il browser Server: il demone http che fornisce i documenti ai client Invio documento Richiesta documento Demone http Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 5 L architettura peer-to to-peer Caratteristiche Componenti indifferenziati: agiscono tanto da richiedenti di un servizio quanto da fornitori di servizio Comunicazioni basate su scambio messaggi Esempio: talk Blah blah blah Blah blah blah Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 6 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 3

L architettura a tre livelli Caratteristiche: Tre tipologie di componenti: Client Server applicativo Data base Comunicazioni basate su scambio messaggi Esempio: applicazioni di commercio elettronico Client (browser + ActiveX o Applet) Server applicativo (demone http+cgi o servlet) DB Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 7 Socket TCP e UDP Con il termine socket si indica un astrazione del sistema operativo per modellare la comunicazione tramite TCP o UDP Nati in ambiente Unix BSD (1982) Disponibili su tutte le piattaforme Le librerie per la gestione dei socket sono fornite con tutti i principali linguaggi di programmazione Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 8 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 4

Tipi di socket Socket UNIX: permettono la comunicazione tra due processi in esecuzione sullo stesso host (tipo AF_UNIX) Meccanismo di indirizzamento basato su pathname unix Socket Internet o TCP/ IP: permettono la comunicazione tra processi in esecuzione su macchine diverse (tipo AF_INET) Meccanismo di indirizzamento basato su coppie: <indirizzo IP, porta> Socket connection-oriented: modellano le connessioni con protocolli connection-oriented Esempio: socket Stream Socket connectionless: modellano le connessioni connectionless -Esempio: socket Datagram Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 9 Stream Socket (TCP): meccanismo di funzionamento Server P1 P2 Client P1 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 10 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 5

Datagram Socket (UDP): meccanismo di funzionamento Server P1 P2 Client Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 11 Socket connection-oriented oriented socket() bind() listen() accept() si sospende socket() connect() read() write() write() read() close() close() Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 12 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 6

Socket connectionless socket() bind() socket() rcvfrom() sendto() si sospende bind() sendto() recvfrom() close() close() Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 13 Indirizzi di socket Un socket ha un indirizzo specificato dalla struttura struct sockaddr { u_short sa_family; /* tipo del socket */ char sa_data[14]; /* indirizzo vero e proprio */ Per i socket Internet la struttura diventa: struct sockaddr_in { u_short sin_family; /* tipo del socket = AF_INET */ u_short sin_port; /* numero di porta */ struct in_addr sin_addr; /* struttura di 4 byte che contiene l indirizzo IP dello host */ char sin_zero[8]; /* byte non usati (padding) */ sin_port e sin_addr devono essere in network byte order Per i socket Unix la struttura diventa: struct sockaddr_un { u_short sun_family; /* tipo del socket = AF_UNIX */ char *sun_path; /* pathname usato come indirizzo del socket */ Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 14 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 7

API socket - socket Essendo chiamate alla parte di gestione della rete del sistema operativo sono solitamente implementate come system call #include <sys/types.h> int socket(int family, int type, int protocol) family specifica il tipo di socket (AF_UNIX, AF_INET) type specifica il tipo di canale: SOCK_STREAM per un canale connection-oriented, SOCK_DGRAM per un canale connectionless protocol specifica il tipo di protocollo usato: IPPROTO_UDP per indicare UDP (tipo DGRAM) o IPPROTO_TCP per TCP (tipo STREAM) La primitiva ritorna un intero che rappresenta un descrittore di file socket Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 15 API socket - bind e listen #include <sys/types.h> int bind(int sockfd, struct sockaddr *myaddr, int addrlen) myaddr è un puntatore ad un indirizzo di socket addrlen specifica la lunghezza della struttura myaddr La primitiva associa al descrittore di socket sockfd un indirizzo bind ritorna un valore che indica se l operazione è andata a buon fine #include <sys/types.h> int listen(int sockfd, int maxconn) maxconn specifica la lunghezza della coda delle richieste di connessione pendenti La primitiva specifica, per socket connection-oriented che il processo desidera ricevere richieste di connessione e quante richieste di connessione devono essere accodate prima di ritornare un errore (0 per infinite) listen ritorna un valore che indica se l operazione è andata a buon fine Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 16 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 8

API socket - accept #include <sys/types.h> int accept(int sockfd, struct sockaddr *partner, int *len) partner è un puntatore ad un indirizzo di socket vuoto che viene riempito con l indirizzo del partner della comunicazione len deve essere pari alla lunghezza della struttura partner La primitiva estrae la prima richiesta di connessione dalla coda e ritorna un descrittore di socket associato a questa particolare connessione Se non esistono richieste di connessione pendenti il processo si sospende fino a quando un processo client non esegua la corrispondente operazione connect Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 17 API socket - connect #include <sys/types.h> int connect(int sockfd, struct sockaddr *server, int len) server è un puntatore ad un indirizzo di socket al quale ci si vuole connettere len deve essere pari alla lunghezza della struttura server connect ritorna un valore che indica se l operazione è andata a buon fine Se il canale è di tipo connection-oriented, tramite la primitiva connect viene inoltrata una richiesta di creazione di un nuovo canale. Se la richiesta viene accettata tramite la accept, la comunicazione potrà procedere usando il descrittore di file sockfd Se il canale è di tipo connectionless, tramite la primitiva connect si stabilisce l indirizzo del partner della comunicazione. I messaggi spediti verranno consegnati all indirizzo specificato da server e solo da tale indirizzo verranno accettati messaggi in arrivo. In questo caso l uso della primitiva è facoltativo. Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 18 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 9

API socket - send e sendto int send(int sockfd, char *buf, int len, int flags) buf è un puntatore ad un buffer di dati che verrà trasmesso al partner della comunicazione così come è stato determinato dalla connect len specifica la lunghezza del buffer flags specifica alcune caratteristiche della comunicazione (solitamente è 0) La primitiva ritorna il numero di byte trasmessi int sendto(int sockfd, char *buf, int len, int flags, struct sockaddr *to, int tolen) sockfd, buf, len, flags come sopra to è un puntatore ad un indirizzo di socket al quale si vuole trasmettere il datagramma buf tolen deve essere pari alla lunghezza della struttura to La primitiva ritorna il numero di byte trasmessi Non è necessario aver prima eseguito una connect Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 19 API socket - recv e recvfrom int recv(int sockfd, char *buf, int len, int flags) buf è un puntatore ad un buffer di dati dove verrà memorizzato il datagramma ricevuto dal partner così come è stato determinato dalla connect len specifica la lunghezza del buffer flags specifica alcune caratteristiche della comunicazione (solitamente è 0) La primitiva ritorna il numero di byte ricevuti int recvfrom(int sockfd, char *buf, int len, int flags, struct sockaddr *from, int *fromlen) sockfd, buf, len, flags come sopra from è un puntatore ad un indirizzo di socket nel quale viene ritornato l indirizzo del mittente del datagramma buf fromlen deve essere pari alla lunghezza della struttura from La primitiva ritorna il numero di byte ricevuti Non è necessario aver prima eseguito una connect Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 20 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 10

API socket - read, write e close int read(int sockfd, char *buf, int numbyte) buf è un puntatore ad un buffer di dati dove verranno memorizzati i byte letti dal socket numbyte specifica il numero di byte da leggere La primitiva ritorna il numero di byte effettivamente letti int write(int sockfd, char *buf, int numbyte) buf è un puntatore ad buffer di dati dove sono memorizzati i byte da trasmettere numbyte specifica il numero di byte da scrivere La primitiva ritorna il numero di byte effettivamente scritti int close(int sockfd) La primitiva chiude il socket Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 21 API socket - gethostbyname e gethostname Routine per la determinazione dell indirizzo IP di un host noto il suo nome #include <netdb.h> struct hostent *gethostbyname(const char *name) Routine per la determinazione del nome dell host locale #include <unistd.h> int gethostname(char *hostname, size_t size) La struttura hostent struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; ; #define h_addr h_addr_list[0] Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 22 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 11

API socket - Routine ausiliarie Routine di conversione di byte order tra quello usato da TCP/ IP e quello locale u_long htonl(u_long hostlong) u_short htons(u_short hostshort) u_long ntohl(u_long netlong) u_short ntohs(u_short netshort) Routine di trasformazione degli indirizzi dal formato stringa 131.112.45.67 a quello in 4 byte consecutivi e viceversa u_long inet_addr(char* str) char *inet_ntoa(struct in_addr addr) Routine per l impostazione delle proprietà di un file #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, long arg) invocata come fcntl(fd, F_SETFL, O_NONBLOCK) imposta il file di descrittore fd in maniera non bloccante. Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 23 La comunicazione attraverso socket UDP Lo User Datagram Protocol è orientato ad implementare applicazioni che utilizzano il paradigma a scambio messaggi Processo sender: genera il messaggio Processo receiver: riceve il messaggio Socket SOCK_DGRAM Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 24 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 12

Client UDP #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <netdb.h> #define MAXHOSTNAME 128 #define BUFLEN 1024 int main(int argc, char *argv[]) { int sock, port; char *host, *message; struct sockaddr_in sa; struct hostent *hp; /* Parse command line arguments */ if(argc<3) { printf("usage: client <host> <port> [<message>]\n"); exit(-1); host = argv[1]; port = atof(argv[2]); if(argc == 3) message = "Let me try..."; else message = argv[3]; /* set the address the new socket have to be bound to */ memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear address */ hp = gethostbyname(host); /* get address info */ if(hp == NULL) { perror("accessing host by name"); exit(-1); sa.sin_family = AF_INET; sa.sin_port = htons(port); /* set port */ memcpy(&sa.sin_addr, hp->h_addr, hp->h_length); /* set host address */ /* now create the socket */ sock = socket (PF_INET, SOCK_DGRAM, 0); if(sock < 0) { perror("opening the socket"); exit(-1); /* now send data */ if (sendto(sock, message, strlen(message), 0, (struct sockaddr *) &sa, sizeof(sa)) < 0) { perror("writing on stream socket"); exit(-1); /* close */ close(sock); return 0; Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 25 Server UDP #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define MAXHOSTNAME 128 #define BUFLEN 1024 int main(int argc, char *argv[]) { int sock, portnumber; struct sockaddr_in sa; char buf[buflen]; /* Parse command line arguments */ if(argc<2) {printf("usage: server <port_number>\n");exit(-1); portnumber = atof(argv[1]); /* set the address the new socket have to be bound to */ memset(&sa, 0, sizeof(struct sockaddr_in));/* clear our address */ sa.sin_family = AF_INET; sa.sin_port = htons(portnumber); sa.sin_addr.s_addr=htonl(inaddr_any); /* accept conn. from any host */ /* now create the socket */ sock = socket (PF_INET, SOCK_DGRAM, 0); if(sock < 0) {perror("opening the socket"); exit(-1); /* now bind the socket to the specified address (i.e., sa) */ if (bind(sock, (struct sockaddr *) &sa, sizeof (sa)) < 0) { perror("binding the socket"); exit(-1); /* wait for incoming requests and print them (main loop) */ while(1) { memset(buf,0,buflen); /* receive incoming data */ recv(sock, buf, BUFLEN-1, 0); /* print data */ printf("received message: %s\n", buf); close(sock); return 0; Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 26 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 13

La comunicazione attraverso socket TCP I socket TCP permettono l implementazione di applicazioni client/ server basate su comunicazioni con connessione In siffatte applicazioni è possibile strutturare il server in due modi Server iterativo Il server si pone in attesa di una richiesta A fronte di una richiesta esegue il servizio e ritorna i risultati Si rimette in attesa Server a gestore Il server si pone in attesa di una richiesta A fronte di una richiesta crea un processo che si occupa di fornire il servizio richiesto e si rimette subito in attesa Il processo appena creato fornisce il servizio e poi termina Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 27 Client TCP #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <netdb.h> #define MAXHOSTNAME 128 #define BUFLEN 1024 int main(int argc, char *argv[]) { int sock, port; char *host, *message; struct sockaddr_in sa; struct hostent *hp; /* Parse command line arguments */ if(argc<3) {printf("usage: client <host> <port> [<message>]\n"); exit(-1); host = argv[1]; port = atof(argv[2]); if(argc == 3) message = "Let me try..."; else message = argv[3]; /* set the address the new socket have to be bound to */ memset(&sa, 0, sizeof(struct sockaddr_in)); hp = gethostbyname(host); /* get address */ if(hp == NULL) { perror("accessing host by name"); exit(-1); sa.sin_family = AF_INET; sa.sin_port = htons(port); /* set port */ memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);/* set host address */ /* now create the socket */ sock = socket (PF_INET, SOCK_STREAM, 0); if(sock < 0) {perror("opening the socket"); exit(-1); /* now connect the socket to the specified address (i.e., sa) */ if (connect(sock, (struct sockaddr *) &sa, sizeof (sa)) < 0) { perror("binding the socket"); exit(-1); /* now send data */ if (write(sock, message, strlen(message)) < 0) { perror("writing on stream socket"); exit(-1); /* close */ close(sock); return 0; Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 28 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 14

Server TCP: schema iterativo #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <netdb.h> #define MAXHOSTNAME 128 #define BUFLEN 1024 int main(int argc, char *argv[]) { int sock, s, n, portnumber; struct sockaddr_in sa; char buf[buflen]; /* Parse command line arguments */ if(argc<2) {printf("usage: server <port_number>\n"); exit(-1); portnumber = atof(argv[1]); /* set the address the new socket have to be bound to */ memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */ sa.sin_family = AF_INET; sa.sin_port = htons(portnumber); sa.sin_addr.s_addr = htonl(inaddr_any); /* now create the socket */ sock = socket (PF_INET, SOCK_STREAM, 0); if(sock < 0) {perror("opening the socket"); exit(-1); /* now bind the socket to the specified addr. */ if (bind(sock, (struct sockaddr *) &sa, sizeof (sa)) < 0) { perror("binding the socket"); exit(-1); /* listen to the connection and accept incoming requests (main loop) */ if(listen(sock, 0) < 0) { perror("listening"); exit(-1); while(1) { /* accept a new connection */ s = accept(sock,null,null); if(s < 0) { perror("accepting"); exit(-1); /* read data */ while(1) { memset(buf, 0, sizeof(buf)); /* clear buf */ if ((n = read(s, buf, BUFLEN-1)) < 0) perror("reading stream message"); else if (n == 0) break; else { printf("%s\n",buf); /* stop if EOT char is sent */ if(buf[n-1]==4) break; close(s); close(s); close(sock); return 0; Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 29 Gianpaolo Cugola - Impianti di Elaborazione dell'informazione 15