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
© Copyright 2024 ExpyDoc