pdf slides

I Socket di Berkeley
Diego Reforgiato Recupero
[email protected]
Dipartimento di Ingegneria Informatica e delle
Telecomunicazioni
Università degli studi di Catania
Original slides by Ing. F. Licandro
1
Outline




Socket di Berkeley
Programmazione dei Socket
Problemi della concorrenza (Semafori, lock, mutex)
Thread
INFO
Lezione 1 di intro ed esempi generali
Da lezione 2 fate voi (portate il pc)
Gruppi da 2 per progetto che iniziano la prox volta
PROSSIME LEZIONI : 22/12, 7/1 (Prof. Sergio Palazzo),
12/1, 19/1
Programmazione su rete

Le applicazioni di rete consistono di diverse
componenti, in esecuzione su macchine differenti (in
generale), che operano in modo indipendente e che
possono scambiare informazioni.


Forniscono i servizi di alto livello utilizzati dagli utenti
Le applicazioni sono processi comunicanti e distribuiti.

La comunicazione avviene utilizzando i servizi offerti dal
sottosistema di comunicazione


Comunicazione a scambio di messaggi.
La cooperazione può essere implementata secondo vari
modelli


Client-server
P2P
3
Modello Client-Server

Client:

E’ l’applicazione che richiede il servizio


Server:

E’ l’applicazione che fornisce il servizio richiesto.


Inizia il contatto con il server
Attende di essere contattato dal client
Come fa un’applicazione ad identificare in rete l’altra
applicazione con la quale vuole comunicare?


Indirizzo IP dell’host su cui è in esecuzione l’altra applicazione
Numero di porta (16 bit - tra 0 e 65535)

L’host ricevente può così determinare a quale applicazione locale
deve essere consegnato il messaggio.
4
Il paradigma Client-Server
(C/S)

Il chiamato è il server:




deve aver divulgato il proprio indirizzo
resta in attesa di chiamate
in genere viene contattato per fornire un servizio
Il chiamante è il client:



conosce l’indirizzo del partner
prende l’iniziativa di comunicare
usufruisce dei servizi messi a disposizione dal
server
5
Il concetto di indirizzo

Una comunicazione può quindi essere identificata
attraverso la quintupla:
{protocol, local-addr, local-port, foreign-addr, foreign-port}


Una coppia {addr, process} identifica univocamente
un terminale di comunicazione (end-point).
Nel mondo IP, ad esempio:


local-addr e foreign-addr rappresentano indirizzi IP
local-port e foreign-port rappresentano numeri di porta
E' possibile suddivere i tipi di porte in tre categorie:
Well Known Ports: il cui valore va da 0 a 1023 sono assegnate a specifici protocolli dalla Internet Assigned Number
Authority (IANA);
Registered Ports: il cui valore va da 1024 a 49151, sono registrate a nome delle società che hanno sviluppato
specifiche applicazioni;
Dynamic and/or Private Ports: il cui valore va da 49152 a 65535, non sono gestite da nessun organo di controllo, e
vengono assegnate dinamicamente, dal sistema operativo, quando un client si connette ad un host remoto;
6
Server concorrenti ed iterativi

Server iterativo


Gestisce una richiesta client per volta (adatti
quando ci sono pochi client da servire, e ci vuole
poco tempo per servire un client)
Server ricorsivo

Gestisce più richieste client contemporaneamente

Creato processo/thread di servizio in grado di gestire
la richiesta client.
7
Interazione livello applicativotrasporto




Le applicazioni client e server utilizzano TCP o UDP
come protocollo di trasporto
Il software di gestione del protocollo di trasporto si
trova all’interno del sistema operativo
Il software dell’applicazione si trova all’esterno del
sistema operativo
Per poter comunicare 2 applicazioni devono interagire
con i rispettivi sistemi operativi.

Ogni applicazione deve chiedere al suo SO di inviare o
ricevere dati tramite la rete.
Come???
8
Comunicazione locale
Esempio di comunicazione locale
Due applicazioni,
localizzate sulla stessa
macchina, scambiano
dati tra di loro
utilizzando l’interfaccia
delle socket.
Le socket utilizzate a
questo scopo vengono
comunemente definite
Unix-domain socket.
$ netstat --unix -p -a
9
Comunicazione remota
Esempio di comunicazione remota.
Anche due
applicazioni situate su
macchine distinte
possono scambiare
informazioni secondo
gli stessi meccanismi.
Così funzionano
telnet, ftp, ICQ,
Napster.
$ netstat --inet -p -a -n
10
Application Programming
Interface (API)

Si utilizza un meccanismo che svolge il ruolo di
interfaccia fra il Sistema Operativo e l’applicazione
di rete:

Application Programming Interface (API)
 Insieme delle funzioni che possono essere invocate per
effettuare chiamate di sistema


Le interfacce delle funzioni sono indipendenti dalla piattaforma
La più diffusa è la Berkeley Sockets (introdotti nel 1983 in
BSD [Berkeley Software Distribution] e poi presi da tutti gli
altri SO).
11
Application Programming
Interface

Nei sistemi Unix definiscono la divisione fra
kernel space e user space.
12
Socket di Berkeley

E’ una interfaccia locale all’host, controllata dal
sistema operativo, creata/posseduta dall’applicazione
tramite la quale il processo applicativo può
inviare/ricevere messaggi a/da un altro processo
applicativo (locale o remoto).



Creato dinamicamente dal SO su richiesta del processo
applicativo utente
Persiste solo durante l’esecuzione dell’applicazione
Il suo ciclo di vita è simile a quello di un file:




Apertura
Collegamento ad un endpoint
Lettura/scrittura
Chiusura
13
Le origini

Inizialmente nasce in ambiente UNIX




Negli anni ‘80 la Advanced Research Project Agency finanziò
l’università di Berkeley per implementare la suite TCP/IP nel
sistema operativo Unix.
I ricercatori di Berkeley svilupparono il set originario di
funzioni che fu chiamato interfaccia socket.
Rappresentano una estensione delle API di UNIX per
la gestione dell’I/O su periferica standard (files su
disco, stampanti, etc).
Rappresentano lo standard di riferimento per tutta la
programmazione su reti.
14
Interazione tra Applicazione e
SO


L’applicazione chiede al sistema operativo di
utilizzare i servizi di rete
Il sistema operativo crea un socket e lo
restituisce all’applicazione


L’applicazione utilizza il socket


restituito un socket descriptor
Open, Read, Write, Close.
L’applicazione chiude il socket e lo restituisce
al sistema operativo
15
Tipi di Socket

SOCK_STREAM




Una socket STREAM stabilisce una connessione.
La comunicazione è affidabile, bidirezionale e i byte sono
consegnati in sequenza.
(presenza di meccanismi out-of-band). Out-of-band
communication is the exchange of call control information
in a separate band from the data or voice stream, or on an
entirely separate, dedicated channel
SOCK_DGRAM




Una socket DATAGRAM non stabilisce alcuna
connessione (connectionless).
Ogni messaggio è indirizzato individualmente a un
destinatario.
NON c’è garanzia di consegna del messaggio.
Non è garantito l’ordine di consegna dei messaggi.
16
Comunicazione
“Connection-Oriented”

In una comunicazione dati ConnectionOriented, i due endpoints dispongono di un
canale di comunicazione che:




trasporta flussi
è affidabile
è dedicato
preserva l’ordine delle informazioni
17
Progettazione di un Server
TCP

Creazione di un endpoint


Richiesta al sistema operativo
Collegamento dell’endpoint ad una porta

Ascolto sulla porta




Processo sospeso in attesa
Accettazione della richiesta di un client
Letture e scritture sulla connessione
Chiusura della connessione
18
Progettazione di un Client TCP

Creazione di un endpoint


Creazione della connessione


Implementa open di TCP (3-way handshake)
Lettura e scrittura sulla connessione


Richiesta al sistema operativo
Analogo a operazioni su file in Unix
Chiusura della connessione

Implementa close di TCP (4-way handshake)
19
Comunicazione
“Connection-Oriented”
3 way handshake:
Host A sends a TCP SYNchronize packet to Host B
Host B receives A's SYN
Host B sends a SYNchronize-ACKnowledgement
Host A receives B's SYN-ACK
Host A sends ACKnowledge
Host B receives ACK.
TCP connection is ESTABLISHED
20
Comunicazione
“Connectionless o Datagram”

In una comunicazione dati Datagram il
canale:




trasporta messaggi
non è affidabile
è condiviso
non preserva l’ordine delle informazioni
21
Progettazione di un Server
UDP

Creazione di un endpoint


Collegamento dell’endpoint ad una porta



Richiesta al sistema operativo
open passiva in attesa di ricevere datagram
Ricezione ed invio di datagram
Chiusura dell’endpoint
22
Progettazione di un Client UDP

Creazione di un endpoint

Richiesta al sistema operativo

Invio e ricezione di datagram

Chiusura dell’endpoint
23
Struttura di un’applicazione
UDP
24
La programmazione
dei Socket
25
Le strutture dati per le socket: il
trattamento degli indirizzi
<sys/socket.h>
struct sockaddr {
u_short
sa_family;
/* address family: AF_xxx value */
char
sa_data[14]; /* up to 14 bytes of protocol-specific address */
};
<netinet/in.h>
struct in_addr {
u_long
s_addr;
};
struct sockaddr_in {
short
sin_family;
u_short
sin_port;
struct in_addr sin_addr;
char
sin_zero[8];
};
Int = 2 bytes
Long = 4 bytes
Char = 1 byte
Short = 2 byes
/* 32-bit netid/hostid network byte ordered */
/* AF_INET */
/* 16-bit port number network byte ordered */
/* unused */
26
Indirizzo di socket

Definizioni del C e definizioni dei tipi dati (typedef)
utilizzati in tutto il sistema sono
Tipo di dati in C
unsigned char
unsigned short
unsigned int
usigned long
4.3BSD
u_char
u_short
u_int
u_long
27
Funzione socket()



Prima funzione eseguita dal client e dal
server
Crea un endpoint
Restituisce


-1 se la creazione non è riuscita
il descrittore del socket se la creazione è riuscita
#include <sys/socket.h>
int socket(int family, int type, int protocol);
28
Parametri della funzione
socket()

int family specifica la famiglia di protocolli da usare:





AF_INET IPv4
AF_INET6 IPv6
AF_LOCAL prot. locale (client e server sullo stesso host)
Altri
int type identifica il tipo di socket



SOCK_STREAM per uno stream di dati (TCP)
SOCK_DGRAM per datagrammi (UDP)
SOCK_RAW per applicazioni dirette su IP
29
Parametri della funzione
socket()

int protocol



0 per specificare il protocollo di default indotto
dalla coppia family e type (tranne che per
SOCK_RAW)
AF_INET + SOCK_STREAM determinano una
trasmissione TCP (IPPROTO_TCP)
AF_INET + SOCK_DGRAM determinano una
trasmissione UDP (IPPROTO_UDP)
30
Funzione socket()

Esempio di invocazione della funzione socket():
if ((sd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
perror("socket");
exit(1);
}

Della quintupla, dopo la chiamata socket(), resta
specificato solo il primo campo:
{protocollo, indirizzo locale, porta locale, indirizzo
remoto, porta remota}
31
Funzione connect()
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sd, const SA *servaddr,
socklen_t addrlen);

Permette ad un client di aprire una connessione con il server



Il SO sceglie una porta effimera ed effettua una open attiva
la funzione termina solo dopo che la connessione è stata creata
Restituisce


-1 in caso di errore
0 se la connessione è stata creata
32
Parametri della funzione
connect()


sd è il socket descriptor
servaddr è un puntatore all’indirizzo dell’endpoint a
cui ci si vuole collegare




indirizzo IP + numero di porta
puntatore di tipo sockaddr (SA)
addrlen è la lunghezza in byte di servaddr
In caso di errore restituisce



ETIMEDOUT è scaduto il time out del SYN
ECONNREFUSED il server ha rifiutato il SYN
EHOSTUNREACH errore di indirizzamento
33
Funzione connect()

Esempio di invocazione della funzione connect():
if (connect(sd, (struct sockaddr *)&servaddr,
sizeof(servaddr)) < 0) {
perror("connect");
exit(1);
}

Della quintupla, dopo la chiamata connect(), restano
specificati tutti i campi relativi agli indirizzi:

{protocollo, indirizzo locale, porta locale,
indirizzo remoto, porta remota}
34
Funzione bind()


Serve a far sapere al kernel a quale processo
vanno inviati i dati ricevuti dalla rete
Permette di assegnare uno specifico indirizzo
al socket


se non si esegue la bind il S.O. assegnerà al
socket una porta effimera ed uno degli indirizzi IP
dell’host dipende dall’interfaccia utilizzata
in genere eseguito solo dal server per usare una
porta prefissata
35
Parametri della funzione bind()
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sd, const SA*myaddr, socklen_t addrlen);

L’oggetto puntato da myaddr può specificare



l’indirizzo IP
il numero di porta (indirizzo locale)
Un campo non specificato è messo a 0


Se la porta è 0 ne viene scelta una effimera
Se l’indirizzo IP è INADDR_ANY (0) il server accetterà richieste
su ogni interfaccia


quando riceve un segmento SYN utilizza come indirizzo IP quello
specificato nel campo destinazione del segmento
La funzione restituisce un errore se l’indirizzo non è utilizzabile

EADDRINUSE
36
Funzione bind()

Esempio di invocazione della funzione bind():
name.sin_family = AF_INET
name.sin_port = htons(0);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sd, (struct sockaddr *)&name, sizeof(name)) < 0) {
perror("bind");
exit(1);}
Della quintupla, dopo la chiamata bind(), restano
specificati il secondo ed il terzo campo, cioè gli
estremi locali della comunicazione:
{protocollo, indirizzo locale, porta locale, indirizzo
remoto, porta remota}

37
Funzione listen()

Utilizzata per rendere un socket passivo
#include <sys/socket.h>
int listen(int sd, int backlog);

Specifica quante connessioni possono
essere accettate e messe in attesa di essere
servite

le connessioni sono accettate o rifiutate dal S.O.
senza interrogare il server
38
Backlog


Nel backlog ci sono sia le richieste di
connessione in corso di accettazione che quelle
accettate ma non ancora passate al server
La somma degli elementi in entrambe le code
non può superare il backlog
39
Funzione accept()
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sd, SA*cliaddr, socklen_t* addrlen);

Permette ad un server di prendere la prima connessione
completata dal backlog


Se il backlog è vuoto il server rimane bloccato sulla chiamata a
funzione fino a quando non viene accettata una connessione
Restituisce


-1 in caso di errore
un nuovo descrittore di socket assegnato automaticamente dal
S.O. e l’indirizzo del client

la porta del nuovo descrittore è effimera
40
Socket di Ascolto e Socket
Connesso

Il server quindi utilizza due socket diversi per ogni
connessione con un client



il socket di ascolto (listening socket) è quello creato dalla
funzione socket()
 utilizzato per tutta la vita del processo
 in genere usato solo per accettare richieste di connessione
il socket connesso (connected socket) è quello creato dalla
funzione accept()
 usato solo per la connessione con un certo client
 usato per lo scambio dei dati con il client
I due socket identificano due connessioni distinte
41
Funzione close()
#include <unistd.h>
int close(int sd);


Marca il descrittore come chiuso
il processo non può più utilizzare il descrittore ma la connessione
non viene chiusa subito


Restituisce


TCP continua ad utilizzare il socket trasmettendo i dati che sono
eventualmente nel buffer
-1 in caso di errore 0 se OK
Più processi possono condividere un descrittore


un contatore mantiene il numero di processi associati al descrittore
la procedura di close della connessione viene avviata solo quando il
contatore arriva a 0
42
Ricevere ed inviare i dati




Una volta utilizzate le precedenti chiamate, la
“connessione” è stata predisposta.
La quintupla risulta completamente
impostata.
A questo punto chiunque può inviare o
ricevere dati.
Per questo, è necessario aver concordato un
protocollo comune.
43
Le system-call send() e sendto()

send() e sendto() si utilizzano per inviare dati verso l’altro terminale di
comunicazione.
int send(int sockfd, char *buff, int nbytes, int flags);
int sendto(int sockfd, char *buff, int nbytes, int flags,
struct sockaddr *to, int addrlen);






sockfd è il descrittore restituito dalla chiamata socket().
buff punta all’inizio dell’area di memoria contenente i dati da inviare.
nbytes indica la lunghezza in bytes del buffer, e quindi, il numero di bytes
che devono essere inviati.
to e addrlen indicano l’indirizzo del destinatario, con la sua lunghezza.
flags abilita particolari opzioni. In generale è pari a 0.
entrambe restituiscono il numero di bytes effettivamente inviati.
44
Le system-call recv() e
recvfrom()


recv()e recvfrom() si utilizzano per ricevere dati dall’altro terminale di
comunicazione.
int recv(int sockfd, char *buff, int nbytes, int flags);
int recvfrom(int sockfd, char *buff, int nbytes, int flags,
struct sockaddr *from, int *addrlen);







sockfd è il descrittore restituito dalla chiamata socket().
buff punta all’inizio dell’area di memoria in cui devono essere ricopiati i dati
ricevuti.
nbytes è un parametro di ingresso che indica la lunghezza del buffer.
from e addrlen contengono, dopo la chiamata, l’indirizzo del mittente con la sua
lunghezza.
flags abilita particolari opzioni. In generale è pari a 0.
entrambe restituiscono il numero di bytes ricevuti (minore o uguale a nbytes).
in assenza di dati da leggere, la chiamata è bloccante.
45
Il marshalling dei parametri



Una serie di funzioni è stata prevista, nell’ambito della
comunicazione su Internet, proprio a questo scopo.
Vanno sotto il nome di Byte Ordering Routines.
Sui sistemi che adottano la stessa convenzione fissata per Internet,
queste routines sono implementate come “null-macros” (funzioni
‘vuote’).
u_long htonl(u_long hostlong); /* host to net long */
u_short htons(u_short hostshort);/* host to net short */
u_long ntohl(u_long netlong);
/* net to host long */
u_short ntohs(u_short netshort); /* net to host short */
46
Operazioni sui buffer




Le classiche funzioni standard del C per operare
sulle stringhe (strcpy(), strcmp(), etc.) non sono
adatte per operare sui buffer di trasmissione e
ricezione.
Esse infatti ipotizzano che ogni stringa sia terminata
dal carattere null e, di conseguenza, non contenga
caratteri null.
Ciò non può essere considerato vero per i dati che
si trasmettono e che si ricevono sulle socket.
E’ stato necessario quindi prevedere altre funzioni
per le operazioni sui buffer.
47
Operazioni sui buffer
bcopy(char *src, char *dest, int nbytes);
bzero(char *dest, int nbytes);
int bcmp(char *ptr1, char *ptr2, int nbytes);



bcopy() copia nbytes bytes dalla locazione src alla locazione
dest.
bzero() imposta a zero nbytes a partire dalla locazione dest.
bcmp() confronta nbytes bytes a partire dalle locazioni ptr1 e
ptr2, restituendo 0 se essi sono identici, altrimenti un valore
diverso da 0.
48
Conversione di indirizzi

Poiché spesso nel mondo Internet gli indirizzi vengono espressi
in notazione dotted-decimal (p.es. 192.168.1.1), sono state
previste due routines per la conversione tra questo formato e il
formato in_addr.
u_long
char


inet_addr(char *ptr);
*inet_ntoa(struct in_addr inaddr);
inet_addr() converte una stringa (C-style) dalla notazione dotteddecimal alla notazione in_addr (che è un intero a 32 bit).
inet_ntoa() effettua la conversione opposta.
49
Nomi logici dei nodi e indirizzi
fisici




struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const char *addr, int len, int type);
gethostbyname riceve in ingresso il nome logico di un host Internet e
restituisce una struttura hostent (contenente l’indirizzo fisico IP del nodo).
gethostbyaddr riceve in ingresso l’indirizzo fisico di un host Internet e
restituisce una struttura hostent (contenente in nome della macchina).
Nomi logici dei nodi e indirizzi fisici
struct hostent {
char *h_name;
/* canonical name of host */
char **h_aliases;
/* alias list */
int h_addrtype;
/* host address type */
int h_length;
/* length of address */
char **h_addr_list;
/* list of addresses */
#define h_addr h_addr_list[0] /* address, for backward
compatiblity */
};

50
Opzioni di socket

getsockopt(), setsockopt()
int getsockopt(int sockfd, int livello, int nomeopz,
char *opzval, int *lunghopz)
int setsockopt(int sockfd, int livello, int nomeopz,
char *opzval, int *lunghopz)

livello: specifica l’entità che deve interpretare
l’opzione nel sistema.
51
Opzioni di socket
livello
nimeopz
get
set
IPPROTO_IP
IP_OPTIONS
*
*
Opzioni di intestazione di IP
IPPROTO_TCP
TCP_MAXSEG
*
*
int
*
Legge la max dim. del segmento in
TCP
Non ritarda la trasmissione per
riunire i pacchetti
Permette l’invio in broadcast
Attiva il debug
Uso solo indirizzo di interfaccia
leggo lo stato di errore
tiene vive le connessioni
indugia sulla chiusura se ci sono
dati
Riceve le dim. del buffer di ricezione
Riceve le dim. del buffer di trasm.
legge il tipo di socket
int
int
int
int
int
int
int
int
int
TCP_NODELAY
SOL_SOCKET
SO_BROADCAST
SO_DEBUG
SO_DONTROUTE
SO_ERROR
SO_KEEPALIVE
SO_LINGER
SO_RCVBUF
SO_SNDBUF
SO_TYPE
…
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
descrizione
tipo di
dato
int
52
Concorrenza


Diverse computazioni vengono eseguite
simultaneamente e interagiscono tra di loro
Uso concorrente di risorse condivise (accesso a un
file per esempio), puo’ portare a race conditions,
deadlock e starvation
Corse critiche (Race
conditions)



Processi in esecuzione condividono una risorsa comune
(area di memoria o periferica). Se il risultato finale
dell’esecuzione di piu’ processi dipende dall’ordine in cui
essi vengono eseguiti, questa e’ una condizione di corsa
critica. Il risultato dell’esecuzione nel caso di corse
critiche e’ impredicibile
Il problema delle corse critiche puo’ essere evitato
impedendo che piu’ di un processo per volta acceda a
risorse condivise
Con la mutua esclusione si evita che piu’ processi che
contengono una risorsa riescano ad accedervi
contemporaneamente
Stallo (Deadlock)



Quando ad un processo viene garantito l’accesso esclusivo (p.e.
tramite la mutua esclusione) ad una risorsa
Formalmente un insieme di processi è in stallo quando ogni
processo dell'insieme attende un evento che può avvenire soltanto
tramite un altro processo dell'insieme
Soluzioni:
 Risoluzione mediante prerilascio (preemption): viene scelto
un processo che detiene una risorsa dall'insieme dei processi in
stallo e viene tolto l'accesso esclusivo ad una risorsa condivisa.
 Risoluzione mediante punto di controllo: vengono creati dei
registri (checkpoint) che descrivono lo stato di utilizzo delle
risorse condivise. Quando viene rilevato uno stallo si effettua un
"ritorno" (rollback to checkpoint) alle condizioni precedenti.
 Risoluzione mediante eliminazione: viene scelto un processo
e viene terminato.
Starvation


Problema legato allo stallo
Quando le politiche di assegnazione delle risorse
condivise favoriscono un processo rispetto ad un altro, il
processo a cui vengono assegnate in minor misura
soffre di starvation. Esso è infatti bloccato e non può
proseguire sebbene non si trovi in una condizione di
stallo. Nei sistemi in cui si accede a risorse condivise è
sempre necessario stabilire una politica per le priorità e
l'ordine con cui esse vengono ripartite. Sebbene queste
politiche possano risultare quanto più eque, esse
possono portare a condizioni di starvation.
InterProcess Communication
(IPC) 1/2


Mutex: variabili binarie che permettono di gestire
l'accesso ad una risorsa condivisa mediante accesso
esclusivo di uno dei contendenti. Le operazioni di blocco
e sblocco sono atomiche.
Semafori n-ari: variabili n-arie che possono essere
incrementate e decrementate. Il processo che
decrementa il semaforo si bloccherà appena raggiunto lo
zero della variabile. Un processo che incrementa il
semaforo invece risveglia tutti i processi che si erano
bloccati in fase di decremento. Questa è una delle
primitive base che consentono la sincronizzazione. Le
operazioni di incremento, decremento e controllo del
semaforo sono atomiche.
InterProcess Communication
(IPC) 2/2



Variabili di tipo condizione: conosciute anche come Condition Variables,
sono variabili con associate due primitive: wait (aspetta) e signal
(segnala, risveglia). Una procedura che richiama la primitiva wait si pone
in attesa indefinita, una procedura che richiama la primitiva signal ne
risveglia una in attesa su wait. Anche in questo caso le operazioni sono
atomiche.
Scambio di messaggi: due procedure, send e receive, permettono a due
processi di scambiarsi messaggi. Lo scambio di messaggi è solitamente
usato in sistemi paralleli.
Barriere: talvolta le applicazioni sono divise in fasi con la regola che
nessun processo può proseguire se prima tutti i suoi simili non sono
pronti a farlo. Le barriere implementano questo concetto: un processo
che ha terminato la sua fase chiama una primitiva barrier e si blocca.
Quando tutti i processi coinvolti hanno terminato il loro stadio di
esecuzione invocando anch'essi la primitiva barrier, il sistema li sblocca
tutti permettendo di passare ad uno stadio successivo.
File Locking



Puo’ essere di tipo mandatory o advisory
Mandatory: prevengono read e write al file
Advisory: processi possono continuare a fare read e write ma sanno
l’esistenza di un lock sul file. E’ un tipo di locking cooperativo.
struct flock fl;
int fd;
fl.l_type
= F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len
= 0;
fl.l_pid
= getpid();
/*
/*
/*
/*
/*
tipo di lock - F_RDLCK, F_WRLCK, F_UNLCK
*/
offset per offset - SEEK_SET, SEEK_CUR, SEEK_END */
Offset from l_whence
*/
length, 0 = to EOF
*/
our PID
*/
fd = open("filename", O_WRONLY);
fcntl(fd, F_SETLKW, &fl); /* F_GETLK, F_SETLK, F_SETLKW */
. . .
fl.l_type
= F_UNLCK; /* tell it to unlock the region */
fcntl(fd, F_SETLK, &fl);/* set the region to unlocked
*/
Semaphores (POSIX)
Usati per controllare l’accesso a file, memoria condivisa.
 Operazioni base: init, controllo, attesa (test-n-set)
Acquisizione di qualche semaforo

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
key : generated using ftok
nsems : number of semaphores in the semaphore set
semflg : permissions on the new semaphore set
#include <sys/ipc.h>
#include <sys/sem.h>
key_t key;
int semid;
key = ftok("/home/somepath/somefile", 'E');
semid = semget(key, 10, 0666 | IPC_CREAT);
On Linux, use ipcs command to check it out and remove it using ipcrm
Semaphores (POSIX)
test-n-set
struct sembuf {
ushort sem_num; // num of semaphores to manipulate
short sem_op;
// operation with the semaphores
short sem_flg;
};
Sem_op value
Positive - valore di sem_op viene aggiunto al valore del semaforo. Si usa per
marcare una risorsa come allocata
Negative - Se il valore assoluto di sem_op e’ > valore del semaforo, il
processo chiamate si blocca fino a quando il semaforo raggiunge il valore
assoluto di sem_op. Quindi il valore assoluto di sem_op e’ sottratto dal
valore del semaforo. Si usa per rilasciare una risorsa
0 - il processo aspetta fino a quando il semaforo raggiunge lo 0
int semop(int semid ,struct sembuf *sops, unsigned int nsops)
semid : ottenuto da semget()
sops : puntatore a sembuf
nsops : quante struct sembuf sto passando
Semaphores (POSIX)
Destroying a semaphore
struct semun {
int val;
/* used for SETVAL only */
struct semid_ds *buf /* for IPC_STAT and IPC_SET */
ushort *array; /* used for GETALL and SETALL */
};
int semctl(int semid ,int semnum, int cmd, union semun arg);
Example:
semct(semid, 0, IPC_RMID, dummy);
Semaphores (POSIX)
PROBLEMA DI QUESTA IMPLEMENTAZIONE DEI
SEMAFORI
1.
Non e’ possibile definire 1 solo semaforo
2.
Non esiste una funzione che permetta di creare ed
inizializzare un semaforo in un’unica chiamata; occorre
prima creare l’insieme con semget e poi inizializzarlo con
semctl
3.
Come caratteristica degli oggetti del SysV IPC di essere
risorse globali di sistema non vengono cancellate quando
nessuno le usa piu’.
Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a livello di
libreria ed è fornita dalla libreria dei thread; Questa però li implementa solo a livello di
thread e non di processi. Esiste però anche una libreria realizzata da Konstantin
Knizhnik che e’ quella che mostro
Thread
Thread = lightweight process

ha uno stato di esecuzione (running, ready)

salva il contesto del thread quando not running

ha uno stack di esecuzione e spazio per variabili locali

accede allo spazio di indirizzamento della memoria e
risorse del suo processo

tutti i thread di un processo lo condividono quando un
thread altera un oggetto della memoria (se un thread apre
un file esso e’ disponibile a tutti gli altri)
Thread - benefits
1.
2.
3.
4.
Piu’ veloce creare un thread nuovo di un processo dato
che il thread usa lo spazio di indirizzamento corrente
Piu’ veloce terminare un thread di un processo
Piu’ veloce lo switch tra 2 thread entro lo stesso processo
C’e’ meno overhead della comunicazione
The Posix Threads Library
int pthread_create(pthread *tid, const pthread_attr
*tattr, void*(*start_routine)(void *), void *arg);
int pthread_join(thread_t tid, void **status); // only fot
nondetached threads
int pthread_detach(thread_t tid);
References






http://info.maxblar.com/gapil/gapil.html#gapilpa2.html
http://www.ecst.csuchico.edu/~beej/guide/ipc/semaphore
s.html
Bind: Address Already in Use : http://heawww.harvard.edu/~fine/Tech/addrinuse.html
http://www.cact.unile.it/facilities/XC6000/htmlman/gapil/gapilsu197.html
http://www.swprog.com/articoli/csc.php
http://www.ce.uniroma2.it/courses/sd0809/#socket
Diego Reforgiato Recupero
[email protected]
http://www.umiacs.umd.edu/~diegoref