Vous êtes sur la page 1sur 82

- Comunicazione Tra Processi (IPC) -

Esercitazione di
Lab. di Sistemi Operativi 1
a.a. 2012/2013
- Comunicazione Tra Processi (IPC) -
- 1 Parte -
1
Laboratorio di sistemi operativi a.a. 2012/2013
Sommario
Comunicazione tra processi sulla stessa macchina:
fifo (qualunque insieme di processi)
Socket locali
Comunicazione tra processi su macchine diverse in rete
Socket TCP (prossima lezione)
Esercizi: Esercizi:
fifo
Socket locali
SOCK_STREAM
SOCK_DATAGRAM
2
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione tra processi sulla stessa
macchina: FIFO - macchina: FIFO -
3
Laboratorio di sistemi operativi a.a. 2012/2013
Le fifo sono pipe con nome che si usano per realizzare una
comunicazione tra processi qualunque, cio non appartenenti alla
stessa gerarchia (padre figlio)
Per creare una fifo si usa:
- Creazione di una fifo: mkfifo -
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
Dove:
pathname: il nome della fifo
mode: esprime i permessi sulla fifo (identico a open)
Restituisce:
0 in caso di successo
-1 altrimenti
4
Laboratorio di sistemi operativi a.a. 2012/2013
int mkfifo(const char *pathname, mode_t mode);
Esempio duso:
mkfifo("nomeFIFO", S_IRUSR | S_IWUSR | S_IXUSR);
Una volta creata, una FIFO deve essere aperta prima di poterla
utilizzare: si utilizza la funzione open
Quindi la FIFO un tipo di file che ha le caratteristiche di una
pipe:
I dati scritti vengono letti in ordine first-in-first-out.
Non possibile rileggere i dati gi letti n posizionarsi allinterno con
- Apertura/chiusura/eliminazione: fifo -
#include <sys/types.h>
#include <sys/stat.h>
fd=open("nomefifo",O_RDONLY | O_WRONLY);
I dati scritti vengono letti in ordine first-in-first-out.
Non possibile rileggere i dati gi letti n posizionarsi allinterno con
lseek. (come pipe)
La costante PIPE_BUF stabilisce il massimo numero di byte che
possono essere scritti in una FIFO in maniera atomica (come pipe)
Per chiudere e per eliminare una FIFO si utilizzano le
funzioni: close e unlink (non c bisogno nelle pipe)
5
Laboratorio di sistemi operativi a.a. 2012/2013
close(fd); unlink("nomefifo");
Una volta aperta, si pu accedere alla FIFO come ad un
normale file mediante le funzioni read/write
Leggere in una FIFO funzione: read
- Utilizzo: fifo -
int fd;
char msg[10];
mkfifo("myfifo", S_IRUSR)
fd=open("myfifo", O_RDONLY);
read(fd,msg,10);//legge dalla fifo
Scrivere in una FIFO funzione: write
6
Laboratorio di sistemi operativi a.a. 2012/2013
read(fd,msg,10);//legge dalla fifo
int fd;
char msg[10];
mkfifo("myfifo", S_IWUSR)
fd=open("myfifo", O_WRONLY);
write(fd,msg,10);//scrive nella fifo
- pipe vs fifo -
PIPE FIFO
utilizzabile solo da processi gerarchici
hanno un nome nel file system e possono
essere usate da processi non gerarchici
create con pipe() create con mkfifo() e aperte con open()
chiuse con close() si elimina al termine
del processo
chiuse da close() e distrutte da unlink()
7
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione client/server half-duplex con
FIFO - FIFO -
8
Laboratorio di sistemi operativi a.a. 2012/2013
Esercizio n 1 FIFO half-duplex
Scrivere due programma C, server.c e client.c i quali comunicano
attraverso una FIFO. Il programma server, crea la fifo serverFIFO, la
apre in sola lettura e si mette in attesa di ricevere una richiesta da parte
del programma client.Alla ricezione della richiesta, crea un processo figlio,
il quale esegue il servizio di stampa a video del pid del processo client che ha
inviato la richiesta e si rimette in attesa sulla serverFIFO. Il programma
client, riempie una struttura dati scrivendovi il proprio pid, dopodich
invia tale struttura al server tramite una scrittura nella serverFIFO, quindi
termina (lanciare i programmi in due shell separate sulla stessa macchina)
Esecuzione in due shell diverse sulla stessa macchina
shell1 $ ./server.out
shell2 $ ./client.out
9
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione client/server half-duplex con FIFO -
client server
read pid
write pid
Stampa a video il pid del client
FIFO half-duplex
10
Per interrompere lattivit del server usare la funzione signal:
signal(SIGINT, foo); \\CTRL-C
imposta la funzione foo come handler del segnale SIGINT
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 1 FIFO server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <signal.h>
typedef struct {
pid_t clientPID;
} richiesta; } richiesta;
void disconnetti_fifo();
int main () {
int fifo;
pid_t figlio;
richiesta buffer;
signal(SIGINT, disconnetti_fifo);//CTRL-C
if (mkfifo("serverFIFO", S_IRUSR | S_IWUSR ) < 0)
if (errno != EEXIST) {
perror ("Impossibile creare la serverFIFO.\n");
exit (-1);
}
11
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 1 FIFO server.c
if ((fifo = open ("serverFIFO", O_RDONLY)) == -1) {
perror ("Errore nella open.\n");
exit (-1);
}
while (1) {//loop infinito
if( read (fifo, &buffer, sizeof (richiesta)) > 0 ) {
if ((figlio = fork()) < 0) {
perror ("Impossibile creare il figlio.\n");
exit (-1);
}
if (figlio == 0) {
printf("Richiesta di esecuzione di Stampa pid\n");
sleep(1);
printf("Pid del Client: %d\n", buffer.clientPID);
}
}
}//end loop
} //end server.c
void disconnetti_fifo()
{printf("Server fermato. Rimozione FIFO dal sistema....");
unlink("serverFIFO");
exit(0);}
12
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 1 FIFO client.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct {
pid_t clientPID;
} richiesta;
int main () {
int fifo;
richiesta buffer;
Struttura contenente il pid
richiesta buffer;
if ((fifo = open ("serverFIFO", O_WRONLY)) == -1) {
perror ("Errore nella open.\n");
exit (-1); }
buffer.clientPID = getpid (); /*Pid del processo*/
write (fifo, &buffer, sizeof (buffer));//scrive in fifo
close (fifo); //chiude la fifo
return 0;
}
13
Laboratorio di sistemi operativi a.a. 2012/2013
- I Socket - - I Socket -
14
Laboratorio di sistemi operativi a.a. 2012/2013
I Socket sono Application Programming Interface (API) usate
per interProcess Comunication (IPC)
Il loro utilizzo giustificato dall avere un interfaccia
estremamente potente e flessibile:
consentono la comunicazione tra processi eseguiti sulla stessa
macchina o tra processi su macchine distribuite in rete
possono essere utilizzate insieme a molte famiglie di protocolli
tra le quali ricordiamo quella dei protocolli di Internet
- Socket: Generalit -
tra le quali ricordiamo quella dei protocolli di Internet
(TCP/IP).
Sono referenziabili tramite descrittori cosi come avviene
per i file ottenibili dopo la chiamata alla funzione socket()
15
Laboratorio di sistemi operativi a.a. 2012/2013
Forniscono un canale di comunicazione bidirezionale.
Utilizzate per la comunicazione client/server
Caratterizzate da descrittori che consentono di utilizzare:
read, write e close ecc.
Due tipi di socket:
Socket locali (per processi che risiedono sullo stesso host)
Socket TCP (per processi che risiedono su host diversi in rete)
- Socket: Generalit -
Socket locali (per processi che risiedono sullo stesso host)
Socket TCP (per processi che risiedono su host diversi in rete)
16
client server
socket
read/write
write/read
Laboratorio di sistemi operativi a.a. 2012/2013
La logica su cui si basa la programmazione dei socket semplice,
infatti il tipo di comunicazione adottato passa attraverso la definizione di
due parametri: dominio e stile
Il dominio di un una socket equivale alla scelta di una famiglia di
protocolli, ed indica lo spazio in cui risiedono il client e server.
Ad ogni dominio sono associate una o pi costanti simboliche del tipo
PF_nomefamiglia, definite nell header <sys/socket.h>
- Socket: Domini e stili -
PF_nomefamiglia, definite nell header <sys/socket.h>
Tra i domini pi importanti ricordiamo:
PF_LOCAL o PF_UNIX per le comunicazioni in locale tramite file
system (socket locali)
PF_INET, la famiglia TCP/IP con Ipv4 (socket TCP)
PF_INET6, la famiglia TCP/IP con Ipv6 (socket TCP)
17
Laboratorio di sistemi operativi a.a. 2012/2013
A ciascun dominio, possono corrispondere:
uno o pi tipi di indirizzi;
quindi per i socket prevista la nozione di famiglia di indirizzi
ciascuna identificata con una costante simbolica del tipo
AF_nomefamiglia definita sempre nell header <sys/socket.h>;
I domini finora introdotti dispongono di un unico schema di indirizzi,
per cui le attuali implementazioni prevedono lequivalenza tra nomi di
dominio e nomi di indirizzi.
- Socket: Indirizzi -
dominio e nomi di indirizzi.
18
Laboratorio di sistemi operativi a.a. 2012/2013
Indirizzamento:
consente di individuare le parti coinvolte nella trasmissione
stessa. (client e server)
Gli indirizzi vengono forniti alle socket mediante puntatori ad
opportune strutture dati i cui nomi incominciano con
sockaddr_suffisso. (Il suffisso specifica il nome del relativo
dominio.)
- Socket: Indirizzamento -
La struttura degli indirizzi definita nell header <sys/socket.h>
come segue:
struct sockaddr_suffisso {
sa_family sa_family, /* Tipo di dominio. AF_xxx */
char sa_data[14]; /* Tipo di indirizzo nel dominio */
}
19
Laboratorio di sistemi operativi a.a. 2012/2013
- Indirizzamento -
Dominio ITERET
Domino Locale
20
Laboratorio di sistemi operativi a.a. 2012/2013
- Indirizzi per dominio Internet-
21
Laboratorio di sistemi operativi a.a. 2012/2013
Lo stile di comunicazione definisce: le caratteristiche della
trasmissione tra client e server
Ad esempio, le trasmissioni possono avvenire a flusso o a pacchetti,
essere affidabili o no, richiedere o meno una connessione.
Lo stile di comunicazione individuato da costanti simboliche
del tipo SOCK_nomestile definite sempre nell header
<sys/socket.h>
Gli stili principali sono:
SOCK_STREAM, corrispondente ad un canale di trasmissione
bidirezionale a flusso, con connessione sequenziale ed affidabile
- Socket: stili -
SOCK_STREAM, corrispondente ad un canale di trasmissione
bidirezionale a flusso, con connessione sequenziale ed affidabile
(paradigma connection oriented).
SOCK_DGRAM, che consiste in una trasmissione a pacchetti (datagram)
di lunghezza max. prefissata, senza connessione e non affidabile
(connectionless).
Fissato un dominio, la scelta dello stile di comunicazione
corrisponde in pratica ad individuare uno specifico protocollo tra
quelli consentiti dal dominio stesso.
22
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione client/server con Socket - - Comunicazione client/server con Socket -
23
Laboratorio di sistemi operativi a.a. 2012/2013
Lato server:
crea un socket tramite la funzione socket il cui nome noto
anche ai processi client
Gli assegna un indirizzo con la funzione bind affinch sia
condivisibili da altri processi client
Tramite la funzione listen, attende la connessione al socket da
parte dei vari client. La funzione listen crea una coda di lunghezza
- client/server con socket -
parte dei vari client. La funzione listen crea una coda di lunghezza
opportuna per consentire la gestione di connessioni simultanee da
parte dei client.
Accetta le connessioni da parte dei client tramite la funzione
accept, il cui ruolo quello di creare un socket per ogni nuova
connessione con un client. Tale socket rappresenta il vero canale
di comunicazione tra il client ed il server.
24
Laboratorio di sistemi operativi a.a. 2012/2013
Lato server interattivo (un processo client per volta):
Un client posto in attesa di essere servito sulla coda generata dalla
funzione listen aspettando che il server abbia terminato di servire il
client precedente.
Lato server concorrente (pi processi client):
Per ogni client viene generato un processo ad hoc per offrire il servizio
richiesto, in modo che pi client possano essere serviti in modalit
- client/server con socket -
richiesto, in modo che pi client possano essere serviti in modalit
concorrente. In tal caso lattesa sulla coda limitata al tempo necessario
alla gestione della richiesta del client da parte del server.
Una volta creata la connessione con il client, di solito il server, crea un
processo figlio che si occupa della gestione della connessione, mentre il
processo originario continua ad accettare altre connessione da altri
client
25
Laboratorio di sistemi operativi a.a. 2012/2013
Lato client:
crea un socket anonimo mediate la funzione socket e quindi
chiede di essere connesso al socket del server
non presente la funzione bind in quanto il socket creato non
deve essere indirizzabile.
richiama la funzione connect per stabilire una connessione con il
server, utilizzando il nome del socket predisposto dal server come
- client/server con socket -
server, utilizzando il nome del socket predisposto dal server come
indirizzo.
Una connessione che ha successo restituisce un descrittore di
file al client ed uno al server, che consentono di leggere e
scrivere sul socket (funzioni read e write)
26
Laboratorio di sistemi operativi a.a. 2012/2013
- socket lato server -
Crea il socket Fuzione socket
Gli assegna un indirizzo Funzione bind
Si mette in ascolto Funzione listen
Accetta nuove connessioni Funzione accept
Chiude il socket Funzione close
Cancella il file se socket locale Funzione unlink
- socket lato client -
27
- socket lato client -
Crea il socket Fuzione socket
Stabilire una connessione Funzione connect
Chiude il socket Funzione close
Laboratorio di sistemi operativi a.a. 2012/2013
- Funzioni Socket lato server - - Funzioni Socket lato server -
28
Laboratorio di sistemi operativi a.a. 2012/2013
Un programma che usa socket deve includere:
<sys/types.h>
<sys/socket.h>
Inoltre deve anche includere:
<sys/un.h> se usa socket del dominio:
AF_LOCAL o AF_UNIX, socket locali
<netinet/in.h> <arpa/inet.h> e <arpa/netdb.h> se usa socket
del dominio:
- Socket: include -
del dominio:
AF_INET, socket distribuite
29
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione socket: creazione
30
Laboratorio di sistemi operativi a.a. 2012/2013
(STILE)
Funzione socket:
- Esempio: creare un socket locale-
#include <sys/socket.h>
int socket(int famiglia, int tipo, int protocollo);
socket locale:
famiglia = PF_LOCAL oppure PF_UNIX (dominio della socket)
tipo = SOCK_STREAM stile (paradigma connection oriented)
protocollo = 0 (protocollo di default)
int socket( PF_LOCAL, SOCK_STREAM, 0 );
famiglia: specifica il dominio in cui utilizzare il socket Useremo:
AF_UNIX oppure AF_LOCAL per socket locali
AF_INET per socket distribuite
tipo specifica il tipo di comunicazione (SOCK_STREAM)
protocol specifica il protocollo da utilizzare per la trasmissione
dei dati. Se vale 0, indica il protocollo di default per la copia
dominio/tipo utlizzato
31
int socket( PF_LOCAL, SOCK_STREAM, 0 );
Laboratorio di sistemi operativi a.a. 2012/2013
- Valori per creazione socket -
32
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione bind: Assegnare un indirizzo
33
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione bind:
Assegna lindirizzo al socket sockfd, il tipo di indirizzo pu
essere locale (AF_UNIX) o di rete (AF_INET) a seconda del
dominio del socket ed memorizzato nella struttura puntata da
myaddr
Ad esempio, per socket locali (AF_LOCAL), lindirizzo il path+il
- Assegnare un indirizzo ad una socket -
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *myaddr,
socklen_t addrlen);
Ad esempio, per socket locali (AF_LOCAL), lindirizzo il path+il
nome del file e la funzione bind fallisce se il file esiste gi (quindi
conviene fare prima unlink)
Mentre per AF_INET lindirizzo rappresentato dal numero di
porta e dallindirizzo IP.
Il terzo argomento addrlen rappresenta la dimensione
dellindirizzo (sizeof)
Restituisce
0 se ok
-1 altrimenti
34
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione bind:
Consideriamo la struttura sockaddr_ definita nellinclude
<sys/un.h>
- Assegnare un indirizzo ad una socket locale -
#include <sys/un.h>
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; //AF_LOCAL
char sun_path[UNIX_PATH_MAX]; //pathname del socket
};
Costruzione dell indirizzo per socket locale:
35
struct sockaddr_un mio_indirizzo;
//Valorizzare i campi della struttura
mio_indirizzo.sun_family = AF_LOCAL;
strcpy(mio_indirizzo.sun_path, "/tmp/mio_socket");
bind(fd,(struct sockaddr *)&mio_indirizzo, sizeof(mio_indirizzo));
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione listen: mettersi in ascolto
36
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione accept: accettare nuove connessioni
37
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione accept:
Crea un nuovo socket con gli stessi attributi di quello originario,
dedicato a questa nuova connessione
- Accettare una nuova connessione -
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *indirizzo_client,
socklen_t *dimensione_indirizzo);
dedicato a questa nuova connessione
Lo connette al socket del client e restituisce un descrittore di file
corrispondente che permette di comunicare con il client
il vecchio socket resta in ascolto per accettare altre connessioni
il secondo e terzo argomento servono ad identificare il client.
Possono anche essere poste a NULL nel caso che il chiamante
(client) non necessiti di indirizzo (ad esempio socket locali)
Restituisce
Un nuovo descrittore se ok
-1 altrimenti
38
Laboratorio di sistemi operativi a.a. 2012/2013
- Struttura di un server con socket locale -
int fd1, fd2;
struct sockaddr_un mio_indirizzo;
mio_indirizzo.sun_family = AF_LOCAL;
strcpy(mio_indirizzo.sun_path, "/tmp/mio_socket");
fd1 = socket(PF_LOCAL, SOCK_STREAM, 0);//crea socket locale
bind(fd1,(struct sockaddr*)mio_indirizzo,
39
Laboratorio di sistemi operativi a.a. 2012/2013
bind(fd1,(struct sockaddr*)mio_indirizzo,
sizeof(mio_indirizzo)); //assegna indirizzo al socket
listen(fd1, 5);//5 la dim della coda di attesa
//attende richieste di connessione da client
fd2 = accept(fd1, NULL, NULL);//per socket locali
...
close(fd2);
close(fd1);
unlink("/tmp/mio_socket"); //distrugge il socket
- Funzioni socket lato server -
Crea il socket fd socket(famiglia, tipo, protocollo)
Gli assegna un indirizzo bind(fd, indirizzo, dimensione_indirizzo)
Si mette in ascolto listen(fd, lunghezza_coda)
Accetta nuove connessioni
fd accept(fd, indirizzo_client, dimensione_ind)
Chiude il socket close(fd)
Cancella il file se socket locale unlink(nomeFileSocket)
40
Laboratorio di sistemi operativi a.a. 2012/2013
- Funzioni Socket lato client - - Funzioni Socket lato client -
41
Laboratorio di sistemi operativi a.a. 2012/2013
- Funzioni socket lato client -
Crea il socket Funzione socket (uguale a quella server)
Si connette ad un server Funzione connect
Chiude il socket Funzione close
42
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione connect:
Connette il socket sockfd creato da un client ad un socket il cui
indirizzo presente nella struttura puntata da serv_addr
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *serv_addr,
socklen_t addrlen);
Funzione connect: connettersi ad un server
indirizzo presente nella struttura puntata da serv_addr
il client deve conoscere lindirizzo del server
il terzo argomento la dimensione della struttura dati contenente
lindirizzo
Restituisce
0 ok
-1 altrimenti
43
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione close: chiudere il socket
44
Laboratorio di sistemi operativi a.a. 2012/2013
- Struttura di un client con socket locale -
int fd;
struct sockaddr_un indirizzo;
indirizzo.sun_family = AF_LOCAL;
strcpy(indirizzo.sun_path, "/tmp/mio_socket");
fd = socket(PF_LOCAL, SOCK_STREAM, 0);//crea socket locale
connect(fd,(struct sockaddr*)indirizzo, sizeof(indirizzo));
45
connect(fd,(struct sockaddr*)indirizzo, sizeof(indirizzo));
...
close(fd);
Laboratorio di sistemi operativi a.a. 2012/2013
Leggere da un socket
46
Laboratorio di sistemi operativi a.a. 2012/2013
Scrivere in un socket
47
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server con socket connection oriented -
48
Laboratorio di sistemi operativi a.a. 2012/2013
- Esercizi: client/server con Socket locale -
(STREAM SOCKET) (STREAM SOCKET)
49
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server: con server concorrente multi
processo per la gestione di pi client- processo per la gestione di pi client-
50
Laboratorio di sistemi operativi a.a. 2012/2013
Esercizio n 4 Socket locali
Scrivere due programmi C, server.c e client.c. che comunicano
tramite socket. Il server.c crea una socket locale, ed ogni volta che
instaura una connessione con un client, mediate fork crea un nuovo
processo (server concorrente). Tale processo, dovr leggere sul
socket il messaggio scritto dal client e scrivere il messaggio che il
server manda al client. Il client.c dovr connettersi al socket locale
su cui scriver il messaggio da mandare al server.
(lanciare l esecuzione dei due programmi su due shell distinti
della stessa macchina) della stessa macchina)
Esecuzione
$ (shell1) ./server.out MESSAGGIO DA CLIENT: <messaggio>
$ (shell2) ./client.out <messaggio>
Suggerimento:
Si utilizzi fgets per ricevere il messaggio da riga di comando
51
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione client/server con socket locale -
client server
fork()
socket
legge il messaggio del scrive il messaggio del
Schema Server concorrente
multi-processo per gestire pi
client
52
Laboratorio di sistemi operativi 1 a.a. 2011/2012
fork()
processo
figlio
gestisci
legge il messaggio del
client dalla socket
scrive il messaggio del
server sulla socket
Il processo figlio gestisce la
connessione con il client
Funzione chiamata dal processo
figlio per gestire la comunicazione
con i client
- Parametri per creare un socket locale connection oriented -
#include <sys/socket.h>
int socket(int famiglia, int tipo, int protocollo);
famiglia = PF_LOCAL oppure PF_UNIX
tipo = SOCK_STREAM ( paradigma connection oriented )
protocollo = 0 ( protocollo di default )
int socket( PF_LOCAL, SOCK_STREAM, 0 );
Indirizzamento:
53
#include <sys/un.h>
struct sockaddr_un serverAddress;
serverAddress.sun_family = AF_LOCAL;
strcpy(serverAddress.sun_path, "/tmp/mio_socket");
bind(fd,(struct sockaddr *)serverAddress,
sizeof(serverAddress));
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 4 server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>
#include <unistd.h>
int gestisci(int connection_fd)
{
int nbytes;
char buffer[256];
//legge da socket il mess. del client
Funzione chiamata dal processo
figlio per comunicare con il client
tramite socket
sockfd
//legge da socket il mess. del client
nbytes = read(connection_fd, buffer, 256);
buffer[nbytes] = 0;
printf("MESSAGGIO DA CLIENT: %s\n", buffer);
nbytes = sprintf(buffer, "Saluti dal server");
//Scrive su socket il mess. del server
write(connection_fd, buffer, nbytes);
close(connection_fd);
return 0;
}
54
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 4 server.c
int main(void) //server
{//struttura degli indirizzi di tipo locale
struct sockaddr_un serverAddress;
//Puntatore alla struttura degli indirizzi
struct sockaddr* serverSockAddrPtr;
int socket_fd, conn_fd, serverAddressLen;
pid_t child;
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);//crea socket
if(socket_fd < 0)
Orientato alla connessione
if(socket_fd < 0)
{printf("socket() failed\n");
return 1;}
unlink("demo_socket"); /*Rimuove la socket se gi esiste */
//valorizzo i campi della struttura sockaddr_un
serverAddress.sun_family = AF_LOCAL; //setta il tipo di dominio
sprintf(serverAddress.sun_path, "demo_socket");
//Parametri da passare all funzione bind
serverSockAddrPtr = (struct sockaddr*) &serverAddress;
serverAddressLen = sizeof (serverAddress);
55
Laboratorio di sistemi operativi 1 a.a. 2011/2012
Sol. Eser. n 4 server.c
if(bind(socket_fd, serverSockAddrPtr, serverAddressLen) != 0)
{printf("bind() failed\n");
return 1;}
if(listen(socket_fd, 5) != 0)//si mette in ascolto sulla coda
{printf("listen() failed\n");
return 1;}
//crea la connessione con i client
while((conn_fd = accept(socket_fd,NULL,NULL)) > -1)
{{
printf("server: new connection from %d \n",conn_fd);
child = fork();//server concorrente crea il figlio
if(child == 0){
return (gestisci(conn_fd)); //comunica con client
}
close(conn_fd);
}//end while
close(socket_fd);
unlink("demo_socket"); /*Rimuove la socket*/
return 0;
}//end server
56
Laboratorio di sistemi operativi 1 a.a. 2011/2012
Sol. Eser. n 4 client.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
int main(void) //client
{struct sockaddr_un serverAddress;
//Puntatore alla struttura degli indirizzi
struct sockaddr* serverSockAddrPtr;
int socket_fd, nbytes, serverAddressLen;
char buffer[256];
Orientato alla connessione
char buffer[256];
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);//crea socket
if(socket_fd < 0)
{printf("socket() failed\n");
return 1;}
//valorizza i campi della struttura indirizzi
serverAddress.sun_family = AF_LOCAL;
sprintf(serverAddress.sun_path, "demo_socket");
//Parametri da passare all funzione connect
serverSockAddrPtr = (struct sockaddr*) &serverAddress;
serverAddressLen = sizeof (serverAddress);
57
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 4 client.c
//si propone di connettersi al socket del server
if(connect(socket_fd, serverSockAddrPtr, serverAddressLen) != 0)
{
printf("connect() failed\n");
return 1;
}
printf("(CLIENT) Scrivere un messaggio: ");
fgets(buffer,255,stdin); //immesso da tastiera
//scrive su socket il mess. da mandare al server
write(socket_fd, buffer, strlen(buffer)); write(socket_fd, buffer, strlen(buffer));
//legge da socket il mess. del server
nbytes = read(socket_fd, buffer, 256);
buffer[nbytes] = '\0';
printf("MESSAGGIO DA SERVER: %s\n", buffer);
close(socket_fd);
return 0;
}//end client
58
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server: con server concorrente multi
thread per la gestione di pi client - thread per la gestione di pi client -
59
Laboratorio di sistemi operativi a.a. 2012/2013
- Struttura di un server concorrente multiThread-
socket(...);
bind(...);
listen(...);
while (1) {//loop principale
connect_sd = accept(listen_sd, NULL,NULL)
printf("server: new connection from %d \n",connect_sd);
pthread_create(&tid,NULL,gestisci,(void *)connect_sd);
60
}
void *gestisci(void *arg) {
/* *** fa quello che deve fare *** */
/* il thread termina se stesso */
pthread_exit(0);
}
Laboratorio di sistemi operativi a.a. 2012/2013
Esercizio n 5 Socket locali
Scrivere due programmi C, serverMultiThread.c e client.c. Il
programma serverMultiThread.c, crea una socket locale e rimane in
attesa di ricevere una connessione. Quando riceve una connessione,
crea un thread con chiamata ad una funzione che gestisce la connessione,
mentre il programma server rimane in ascolto per eventuali altre richieste di
connessione. Il programma client, si connette alla socket locale ed invia il
messaggio passato a riga di comando (usare fgets) al server. Il server
tramite il thread legge il messaggio e lo stampa a video
(Lanciare i due programmi in due shell distinte, e compilare il server
con -lpthread) con -lpthread)
Esecuzione server:
shell1 $ ./serverMultiThread.out
Esecuzione client:
shell2 $ ./client.out Messaggio
61
Laboratorio di sistemi operativi a.a. 2012/2013
- Comunicazione client/server con socket locale -
client server
pthread_create()
socket
legge il messaggio del
Schema Server concorrente
multi-thread per gestire pi
client
62
pthread_create()
processo
thread
gestisci
legge il messaggio del
client dalla socket
stampa il messaggio del
client a video
Il processo thread gestisce la
connessione con il client
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 5 serverMultiThread.c
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pthread.h>
#define SOCKNAME "mysocket
#define N 256
void *gestisci(void *arg) {
Funzione chiamata dal thread per
comunicare con il client tramite
socket
void *gestisci(void *arg) {
printf("gestisci(): creato il thread\n");
char buf[N];
//Legge da socket il messaggio scritto dal client
while (read((int *) arg, buf, N) != 0)
{
printf("Server %d : %s\n", getpid(), buf);
}
close((int *) arg);
pthread_exit (0);
}
63
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 5 serverMultiThread.c
int main(void)
{unlink(SOCKNAME);
int s_fd, c_fd;
pthread_t tid;
struct sockaddr_un sa;
sprintf(sa.sun_path, SOCKNAME);
sa.sun_family = AF_LOCAL;
s_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
bind(s_fd, (struct sockaddr *) &sa, sizeof(sa)); bind(s_fd, (struct sockaddr *) &sa, sizeof(sa));
listen(s_fd, 5);
while (1) { //loop infinito
c_fd = accept(s_fd, NULL, NULL);
printf("server: new connection from %d \n",c_fd);
pthread_create(&tid, NULL, gestisci, (void *) c_fd)
pthread_detach(tid);
}
return 0;
}//end server
64
Passaggio dell id socket alla funzione gestisci
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 5 client.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCKNAME "mysocket
#define N 256 #define N 256
int main(void)
{int c_fd;
struct sockaddr_un sa;
char buffer[N];
sprintf(sa.sun_path, SOCKNAME);
sa.sun_family = AF_UNIX;
c_fd = socket(AF_UNIX, SOCK_STREAM, 0);
65
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 5 client.c
if(connect(c_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)
{
printf("connect() failed\n");
return 1;
}
printf("(CLIENT) Scrivere un messaggio: ");
fgets(buffer,N,stdin); //Inserimento del messaggio
write(c_fd, buffer, strlen(buffer)); //scrittura su socket
printf("Client %d ha inviato il messaggio\n", getpid());
close(c_fd);
return 0;
}//end client
66
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server: con server interattivo - - client/server: con server interattivo -
67
Laboratorio di sistemi operativi a.a. 2012/2013
Esercizio n 6 Socket locali
Scrivere due programmi C, socket-server.c e socket-client.c. Il
programma socket-server.c, crea una socket locale e rimane in attesa
di ricevere una connessione. Quando riceve una connessione, legge il
messaggio proveniente da essa, lo stampa e chiude la connessione. Se
il messaggio ricevuto quit, il programma server, rimuove la socket e
termina lesecuzione. Il server prende il path della socket da linea di
comando. Il programma client, si connette alla socket locale ed invia il
messaggio. Il nome del path della socket e del messaggio da inviare sono
specificati a linea
di comando. (Lanciare i due programmi in due shell distinte) di comando. (Lanciare i due programmi in due shell distinte)
Esecuzione server:
$ ./socket-server demo_socket
Esecuzione client:
shell1 $ ./socket-client demo_socket Messaggio
shell2 $ ./socket-client demo_socket quit
68
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 6 socket-server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
int server (int client_socket)
{ while (1)
{ int length;
char* text;
if (read (client_socket, &length, sizeof (length)) == 0)
Legge la lunghezza del messaggio
dalla socket e la mette in length
chiamata dal server per leggere il
mess. del client nel socket
if (read (client_socket, &length, sizeof (length)) == 0)
return 0;
text = (char*) malloc (length); /*Alloca memoria per il buffer*/
read (client_socket, text, length);/*legge il messaggio e lo mette in text*/
printf ("%s\n", text);
free (text); /*Pulisce il buffer */
if (!strcmp (text, "quit")) /*Se text quit termina*/
return 1;
}
}
69
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 6 socket-server.c
int main (int argc, char* const argv[])
{
const char* const socket_name = argv[1]; //nome socket
struct sockaddr_un serverUNIXAddress; /*Server address*/
struct sockaddr* serverSockAddrPtr; /*Ptr to server address*/
int socket_fd, serverLen, clientLen;
int client_sent_quit_message;
socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);//creazione socket
//Valorizzo la struttura degli indirizzi //Valorizzo la struttura degli indirizzi
serverUNIXAddress.sun_family = AF_LOCAL;
strcpy (serverUNIXAddress.sun_path, socket_name);
//Parametri da passare all funzione bind
serverSockAddrPtr = (struct sockaddr*) &serverUNIXAddress;
serverLen = sizeof (serverUNIXAddress);
unlink (socket_name);
bind (socket_fd, serverSockAddrPtr, serverLen);
listen (socket_fd, 5); /* coda di attesa */
70
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 6 socket-server.c
do {
int client_socket_fd;
client_socket_fd = accept (socket_fd, NULL, NULL);
client_sent_quit_message = server(client_socket_fd);
close (client_socket_fd);
} while (!client_sent_quit_message);//cicla se non quit } while (!client_sent_quit_message);//cicla se non quit
close (socket_fd);
unlink (socket_name); /*Rimuove la socket*/
return 0;
} //END SERVER
71
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 6 socket-client.c
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
void write_text (int socket_fd, const char* text)
{
int length = strlen (text) + 1;
chiamata dal client per scrivere il
mess. nel socket
int length = strlen (text) + 1;
/*Write the number of bytes in the string,
including NUL-termination.*/
write (socket_fd, &length, sizeof (length));
write (socket_fd, text, length);
}
72
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 6 socket-client.c
int main (int argc, char* const argv[])
{
const char* const socket_name = argv[1];//nome socket
const char* const message = argv[2]; //messaggio
int serverLen, socket_fd;
struct sockaddr_un serverUNIXAddress;
struct sockaddr* serverSockAddrPtr;
serverSockAddrPtr = (struct sockaddr*) &serverUNIXAddress;
serverLen = sizeof (serverUNIXAddress);
socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0); //crea socket
serverUNIXAddress.sun_family = AF_LOCAL;
strcpy (serverUNIXAddress.sun_path, socket_name);
connect (socket_fd, serverSockAddrPtr, serverLen);
write_text (socket_fd, message);//scrittura mess. su socket
close (socket_fd);
return 0;
} //end client
73
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server con Socket locale -
connectionless (DATAGRAM SOCKET) connectionless (DATAGRAM SOCKET)
74
Laboratorio di sistemi operativi a.a. 2012/2013
- client/server con DATAGRAM SOCKET -
read()
75
Laboratorio di sistemi operativi a.a. 2012/2013
Funzione sendto():
Manda un messaggio su datagram socket (senza connessione)
sockfd: il descrittore della socket su cui mandare il messaggio
buf: il puntatore al messaggio da mandare
#include <sys/types.h>
#include <sys/socket.h>
int sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen);
Funzione: sendto
buf: il puntatore al messaggio da mandare
len: la dimensione del messaggio
flags: consente di specificare altre info sul messaggio da mandare;
per messaggi normali viene posto a zero
to: puntatore alla struttura contenete lindirizzo del destinatario
del messaggio
tolen: dimensione struttura
Ritorna
il numero di byte mandati se ok
-1 altrimenti
76
Laboratorio di sistemi operativi a.a. 2012/2013
- Esercizi: client/server con Socket locale -
(DATAGRAM SOCKET) (DATAGRAM SOCKET)
77
Laboratorio di sistemi operativi a.a. 2012/2013
Esercizio n 7 Socket locali
Scrivere due programmi C, server.c e client.c. che comunicano
tramite DATAGRAM socket. Il server.c crea una socket locale, e si
mette in attesa di leggere un messaggio sulla socket. Il client.c
scrivere un messaggio su socket.
Il nome della socket viene passato al client da riga di comando
(lanciare l esecuzione dei due programmi su due shell distinti
della stessa macchina)
Esecuzione Esecuzione
$ ./server.out (shell1) MESSAGGIO DA CLIENT: Saluti da client
$ ./client.out socket (shell2)
78
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 7 server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#define NAME "socket" //nome della socket
main()
{
int sock, length;
struct sockaddr_un name; struct sockaddr_un name;
char buf[1024]; /* Create socket from which to read. */
sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
if (sock < 0) {
perror("opening datagram socket");
exit(1); }
/* Create name. */
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, NAME);
79
Laboratorio di sistemi operativi a.a. 2012/2013
Sol. Eser. n 7 server.c
/* Bind the UNIX domain address to the created socket */
if (bind(sock, (struct sockaddr *) &name,
sizeof(struct sockaddr_un)))
{
perror("binding name to datagram socket");
exit(1); }
printf("socket -->%s\n", NAME);
/* Read from the socket */ /* Read from the socket */
if (read(sock, buf, 1024) < 0)
perror("receiving datagram packet");
printf("-->%s\n", buf);//STAMPA DEL MESSAGGIO LETTO
close(sock);
unlink(NAME);
}//END SERVER
80
Laboratorio di sistemi operativi a.a. 2012/2013
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#define DATA "socket locale connectionless
main(argc, argv)
int argc;
char *argv[];
{ int sock;
struct sockaddr_un name;
sock = socket(PF_LOCAL, SOCK_DGRAM, 0); //Crea socket dove scrivere
if (sock < 0) {
Soluzione Esercizio N 7 client.c 1/1
if (sock < 0) {
perror("opening datagram socket");
exit(1); }
/* Costruzione indirizzo */
name.sun_family = AF_LOCAL;
strcpy(name.sun_path, argv[1]);
/* manda message. */
if (sendto(sock, &DATA, sizeof(DATA), 0, (struct sockaddr *)&name,
sizeof(name)) < 0)
{ perror("sending datagram message");}
close(sock);
}//END CLIENT
81
Laboratorio di sistemi operativi a.a. 2012/2013
- Fine Esercitazione - - Fine Esercitazione -
82
Laboratorio di sistemi operativi a.a. 2012/2013

Vous aimerez peut-être aussi