Politecnico di Milano © Domenico Barretta Processi concorrenti in Unix Docente Domenico Barretta Politecnico di Milano
Processi concorrenti in Unix© Domenico Barretta- 2 - Contenuto Funzioni per la comunicazione fra processi Meccanismi utilizzati: Scambio di messaggi Pipes Memoria condivisa e semafori Socket Esempi di codice
Processi concorrenti in Unix© Domenico Barretta- 3 - Scambio di messaggi Viene gestito tramite una coda a cui più processi possono accedere I processi che intendono utilizzare lo scambio di messaggi devono utilizzare la stessa coda Ciascun processo può utilizzare una coda sia per inviare messaggi che per riceverne A ciascun messaggio è possibile associare un tipo di messaggio Utilizzabile per indirizzare un messaggio ad uno dei processi che accedono in lettura ad una coda condivisa
Processi concorrenti in Unix© Domenico Barretta- 4 - Scambio di messaggi Le librerie da importare per l’utilizzo dello scambio di messaggi sono sys/ipc.h sys/msg.h Per poter utilizzare i messaggi è prima necessario inizializzare una coda con la funzione msgget() Una volta inizializzata la coda (da parte di tutti i processi che devono comunicare) è possibile: Inviare un messaggio con la funzione msgsnd() Ricevere un messaggio con la funzione msgrcv()
Processi concorrenti in Unix© Domenico Barretta- 5 - msgget() Sintassi int msgget(key_t key, int msgflg) Effetto Se non è ancora stata creata una coda a partire dalla chiave specificata, viene creata la coda e ne viene restituito l’identificatore Altrimenti viene restituito l’identificatore della coda creata in precedenza
Processi concorrenti in Unix© Domenico Barretta- 6 - msgget() - parametri Il primo parametro serve a fare in modo che tutti i processi che chiamano la msgget() con la stessa chiave (un valore numerico ottenibile con la funzione ftok() ) facciano riferimento alla stessa coda; se viene specificato come IPC_PRIVATE la coda è utilizzabile solo dal processo che la crea Il secondo parametro è definito come l’or di seguenti parametri: IPC_CREAT da specificare se la coda va creata qualora non esista già IPC_EXCL da specificare insieme a IPC_CREAT se la funzione deve fallire qualora la coda esista già I permessi di accesso (notazione ottale)
Processi concorrenti in Unix© Domenico Barretta- 7 - Struttura dei messaggi I messaggi sono tipicamente strutturati come una struct costituita da due campi: Un long che costituisce il tipo del messaggio Un array di caratteri che costituisce il contenuto del messaggio Esempio ( MSGSZ è la massima dimensione di un messaggio): typedef struct msgbuf { long mtype; char mtext[MSGSZ]; } message_buf
Processi concorrenti in Unix© Domenico Barretta- 8 - msgsnd() Sintassi int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); Effetto Invia il messaggio alla coda specificata e restituisce il numero di byte spediti Parametri L’identificatore della coda a cui inviare il messaggio Un puntatore al messaggio La dimensione del messaggio 0 o IPC_NOWAIT a seconda se il processo vada sospeso o meno in caso di coda piena
Processi concorrenti in Unix© Domenico Barretta- 9 - msgrcv() Sintassi int msgsrv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg); Effetto Riceve il messaggio del tipo indicato e restituisce il numero di byte ricevuti Parametri L’identificatore della coda Un puntatore all’area dove scrivere il messaggio ricevuto La massima dimensione da ricevere
Processi concorrenti in Unix© Domenico Barretta msgrcv() - continua Altri parametri Il tipo di parametro da ricevere 0 per ricevere il primo messaggio della coda Un numero positivo per ricevere il primo messaggio del tipo specificato Un numero negativo per ricevere il primo messaggio con tipo maggiore del modulo del valore specificato Un flag: IPC_NOWAIT se in assenza di messaggi si vuole che la funzione ritorni subito MSG_NOERROR se si vogliono troncare messaggi più lunghi della dimensione specificata MSG_EXCEPT se si specifica il tipo di messaggio da non ricevere
Processi concorrenti in Unix© Domenico Barretta Messaggi – Esempio di codice Si tratta di un semplice programma che: Crea un processo figlio Invia un messaggio al processo figlio Il processo figlio riceve il messaggio e lo stampa a video Tratto dal sito
Processi concorrenti in Unix© Domenico Barretta Messaggi – Esempio di codice #include #define MSGSZ 128 /* * Declare the message structure. */ typedef struct msgbuf { long mtype; char mtext[MSGSZ- sizeof(long)]; } message_buf; main() { int temp; int msqid; int msgflg = IPC_CREAT | 0666; key_t key; message_buf sbuf; message_buf rbuf; size_t buf_length; pid_t pid; /* * Get the message queue id for * the "name" 1234, which was * created by the server. */ key = 1234;
Processi concorrenti in Unix© Domenico Barretta Messaggi – Esempio di codice if ((pid=fork()) <0 ) { perror("Error in fork"); exit(1); } if (0 == pid)//figlio { if ((msqid = msgget(key, 0666)) < 0) { perror("msgget"); exit(1); } /* * Receive an answer of message * type 1. */ temp=msgrcv(msqid, &rbuf, MSGSZ, 1, 0); if (temp < 0) { perror("msgrcv"); exit(1); } rbuf.mtext[temp]=0; /* * Print the answer. */ printf("In ricezione ho avuto %s\n", rbuf.mtext); } //Fine figlio
Processi concorrenti in Unix© Domenico Barretta Messaggi – Esempio di codice else//padre { (void) fprintf(stderr, "\nmsgget: Calling msgget(%#lx,%#o)\n",key, msgflg); if ((msqid = msgget(key, msgflg )) < 0) { perror("msgget"); exit(1); } else (void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid); /* * We'll send message type 1 */ sbuf.mtype = 1; (void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid); (void) strcpy(sbuf.mtext, "Did you get this?"); (void) fprintf(stderr,"msgget: msgget succeeded: msqid = %d\n", msqid);
Processi concorrenti in Unix© Domenico Barretta Messaggi – Esempio di codice buf_length = strlen(sbuf.mtext) ; /* * Send a message. */ if (msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT) < 0) { printf ("%d, %d, %s, %d\n", msqid, sbuf.mtype, sbuf.mtext, buf_length); perror("msgsnd"); exit(1); } else printf("Message: \"%s\" Sent\n", sbuf.mtext); wait(); } exit(0); }
Processi concorrenti in Unix© Domenico Barretta Pipes Una pipe è una coda circolare gestita dal sistema operativo Tipicamente esistono uno o più processi che scrivono sulla pipe e un processo che legge dalla pipe Una volta inizializzata una pipe, è possibile utilizzarla per scrivere e leggere bytes E’ un canale di comunicazione unidirezionale
Processi concorrenti in Unix© Domenico Barretta Pipes Le librerie da importare sono: sys/types.h unistd.h stdio.h Si definisce un vettore di due interi che corrispondono all’ingresso e all’uscita della coda Si inizializza la pipe tramite la funzione pipe() La scrittura avviene tramite la funzione write() La lettura avviene tramite la funzione read() La chiusura avviene tramite la funzione close()
Processi concorrenti in Unix© Domenico Barretta pipe() Sintassi int pipe(int pipedes[2]) Effetto Crea una pipe I byte scritti in pipedes[1] possono essere letti da pipedes[0] Restituisce 0 in caso di successo, -1 altrimenti Parametri Un vettore di 2 interi in cui memorizzare i descrittori della pipe
Processi concorrenti in Unix© Domenico Barretta read() Sintassi size_t read(int fd, void *buf, size_t nbytes) Effetto Legge dalla pipe e memorizza i dati letti in buf Restituisce il numero di bytes letti, oppure 0 se è stato raggiunto EOF oppure -1 in caso di errore Parametri Come primo parametro si usa pipedes[0] Il secondo parametro è un puntatore all’area di memoria in cui scrivere quanto letto Il numero di bytes che si intende leggere
Processi concorrenti in Unix© Domenico Barretta Altre funzioni size_t write(int fd, const void *buf, size_t nbytes) Analoga alla read Si utilizza pipedes[1] come secondo parametro int close(int fd) Se utilizzata con pipedes[0] chiude la lettura della pipe Se utilizzata con pipedes[1] chiude la scrittura della pipe
Processi concorrenti in Unix© Domenico Barretta Pipe - Esempio di codice #include #define MAX 25 /* maximum number of letters communicated */ int main (void) { int fd[2]; /* provide file descriptor pointer array for pipe */ /* within pipe: fd[0] will be input end fd[1] will be output end */ pid_t pid; char line[MAX]; /* character array (string) for reading */ if (pipe (fd) < 0) /* create pipe and check for an error */ { perror(''pipe error''); exit (1); } if ((pid = fork()) < 0) /* apply fork and check for error */ { perror (''error in fork''); exit (1); }
Processi concorrenti in Unix© Domenico Barretta Pipe - Esempio di codice if (0 == pid) { /* processing for child */ printf (''The child process is active.``n''); close (fd[1]); /* close output end, leaving input open */ read(fd[0], line, MAX); printf (“The string received is '%s'``n'', line); } else { /* processing for parent */ printf (''The parent process is active.``n''); close (fd[0]); /* close input end, leaving output open */ write (fd[1], ''Your parent is calling'', 22); /* print string and indicate byte length */ } wait() exit (0);
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa Ogni processo ha uno spazio di indirizzamento privato Il sistema operativo non consente di accedere allo spazio di indirizzamento di un altro processo Esistono delle funzioni che permettono di definire dello spazio in memoria come condiviso da più processi
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa La funzione che permette di condividere un’area di memoria è la mmap() di cui non vediamo tutti i dettagli Libreria da includere: sys/mman.h Una volta condiviso un’area di memoria, è possibile leggere e scrivere al suo interno come per una qualsiasi altra area di memoria L’utilizzo della memoria condivisa implica la necessità di gestire in maniera corretta l’accesso concorrente ad essa (mutua esclusione)
Processi concorrenti in Unix© Domenico Barretta mmap() Sintassi void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off) Effetto Condivide una zona di memoria Parametri Il primo e l’ultimo parametro sono solitamente 0 len è la dimensione dell’area di memoria prot indica i criteri di protezione: PROT_NONE i dati non sono accessibili Un or di PROT_WRITE PROT_READ e/o PROT_EXEC per rendere possibile ciascuna delle tre operazioni
Processi concorrenti in Unix© Domenico Barretta mmap() Altri parametri flags (principali valori) MAP_SHARED per condividere i cambiamenti dovuti a scritture MAP_PRIVATE le modifiche non si ripercuotono sugli altri processi fildes Un descrittore di file, tipicamente si usa –1 per l’uso qui descritto della mmap
Processi concorrenti in Unix© Domenico Barretta Semafori I semafori sono una delle possibili soluzioni al problema dell’accesso a risorse condivise in mutua esclusione Un semaforo è un contatore intero positivo a cui sono associate Una coda dei processi sospesi sul semaforo Tre operazioni Inizializzazione Post (nota anche come signal e come V) Wait (nota anche come P)
Processi concorrenti in Unix© Domenico Barretta Semafori Esistono diverse implementazioni dei semafori Nell’implementazione standard di Unix i semafori vengono raggruppati in vettori Le principali funzioni per la gestione di vettori di semafori sono: semget() Inizializza un vettore di semafori semop() Agisce su un semaforo semctl() Gestisce i semafori
Processi concorrenti in Unix© Domenico Barretta semget() Sintassi int semget(key_t key, int nsem, int semflg) Effetto Crea un vettore di semafori e restituisce l’identificatore del vettore creato se ha successo, -1 altrimenti Parametri (confrontare con la msgget() ) Una chiave numerica Il numero di semafori da creare nel vettore I flag
Processi concorrenti in Unix© Domenico Barretta semop() Sintassi int semop (int semid, struct sembuf *sops, unsigned nsops) Effetto Effettua le operazioni specificate sul vettore di semafori Parametri semid l’identificatore del vettore di semafori sops un vettore di strutture dati che definisce le operazioni nsops il numero di operazioni specificate in sembuf
Processi concorrenti in Unix© Domenico Barretta struct sembuf E’ la struttura dati che descrive un’operazione da svolgere su un semaforo tramite la semop() Se si vuole agire su un solo semaforo si crea un vettore composto da un solo elemento I campi della struttura sono: sem_num : l’indice del semaforo su cui agire all’interno del vettore sem_op : il valore da sommare al semaforo sem_flg : è possibile specificare come flag IPC_NOWAIT se non si desidera sospendere il processo sull’operazione sul semaforo
Processi concorrenti in Unix© Domenico Barretta semctl() Sintassi int semctl (int semid, int semnum, int cmd, union semun arg) Parametri L’identificatore del vettore di semafori Il numero del semaforo su cui agire Il comando da eseguire (fra cui SETVAL per inizializzare e IPC_RMID per distruggere il vettore di semafori) Un parametro opzionale dipendente dal comando (per la SETVAL si può utilizzare un intero che corrisponde al valore iniziale del semaforo)
Processi concorrenti in Unix© Domenico Barretta Semafori La funzione per operare sui semafori ( semop() ) è scomoda da utilizzare Un’unica funzione implementa sia la wait che la post Solitamente si definiscono due funzioni più intuitive che effettuano la post e la wait Analogamente per l’inizializzazione dei semafori Si veda in proposito l’esempio di codice sulla memoria condivisa
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa - esempio /* A readers/writers program using a shared buffer and semaphores */ #include #define BUF_SIZE 5 /* logical size of buffer */ #define SHARED_MEM_SIZE (BUF_SIZE+2)*sizeof(int) /* size of shared memory */ #define run_length 10 /* number of iterations in test run */ #define buf_used 0 /* semaphore array index to check buffer elts used */ #define buf_space 1 /* semaphore array index to check buffer elts empty */ int sem_init(void) { /* procedure to create and initialize semaphores and return semaphore id, assuming two semaphores defined in the given array of semaphores */ int semid; /* create new semaphore set of 2 semaphores */ if ((semid = semget (IPC_PRIVATE, 2, IPC_CREAT | 0600)) < 0) { perror ("error in creating semaphore");/* 0600 = read/alter by user */ exit (1); }
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa - esempio /* initialization of semaphores */ /* BUF_SIZE free spaces in empty buffer */ if (semctl (semid, buf_space, SETVAL, BUF_SIZE) < 0) { perror ("error in initializing first semaphore"); exit (1); } /* 0 items in empty buffer */ if (semctl (semid, buf_used, SETVAL, 0) < 0) { perror ("error in initializing second semaphore"); exit (1); } return semid; } void sem_wait(int semid, int index) { /* procedure to perform a P or wait operation on a semaphore of given index */ struct sembuf sops[1]; /* only one semaphore operation to be executed */ sops[0].sem_num = index; sops[0].sem_op = -1; sops[0].sem_flg = 0; if (semop(semid, sops, 1) == -1) { perror("error in semaphore operation"); exit (1); }
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa - esempio void sem_post(int semid, int index) { /* procedure to perform a V or signal operation on semaphore of given index */ struct sembuf sops[1]; sops[0].sem_num = index; sops[0].sem_op = 1; sops[0].sem_flg = 0; if (semop(semid, sops, 1) == -1) { perror ("error in semaphore operation"); exit (1); } int main (void) { pid_t pid; /* variable to record process id of child */ /* shared memory elements */ caddr_t shared_memory; /* shared memory base address */ int *in; /* pointer to logical 'in' address for writer */ int *out; /* pointer to logical 'out' address for reader */ int *buffer; /* logical base address for buffer */ /* semaphore elements */ int semid; /* identifier for a semaphore set */ /* local variables */ int i_child, j_child; /* index variables */ int value; /* value read by child */
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa - esempio /* set up shared memory segment */ shared_memory=mmap(0, SHARED_MEM_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (shared_memory == (caddr_t) -1) { perror ("error in mmap while allocating shared memory\n"); exit (1); } /* set up pointers to appropriate places in shared memory segment */ buffer = (int*) shared_memory; /* logical buffer starts at shared segment */ in = (int*) shared_memory + BUF_SIZE*sizeof(int); out = (int*) shared_memory + (BUF_SIZE+1)*sizeof(int); *in = *out = 0; /* initial starting points */ /* create and initialize semaphore */ semid = sem_init(); if (-1 == (pid = fork())) /* check for error in spawning child process */ { perror ("error in fork"); exit (1); } if (0 == pid) { /* processing for child == reader */ printf ("The reader process begins.\n"); for (i_child = 0; i_child < run_length; i_child++) { sem_wait(semid, buf_used); /* wait semaphore for something used */ value = buffer[*out]; *out = (*out + 1) % BUF_SIZE;
Processi concorrenti in Unix© Domenico Barretta Memoria condivisa - esempio printf ("Reader's report: item %2d == %2d\n", i_child, value); sem_post(semid, buf_space); /* signal semaphore for space available */ } printf ("Reader done.\n"); } else { /* processing for parent == writer */ printf ("The writer process begins.\n"); for (j_child = 0; j_child < run_length; j_child++) { sem_wait(semid, buf_space); /* wait semaphore for space available */ buffer[*in] = j_child*j_child; /* put data in buffer */ *in = (*in + 1) % BUF_SIZE; printf ("Writer's report: item %2d put in buffer\n", j_child); sem_post(semid, buf_used); /* signal semaphore for something used */ } wait (pid); printf ("Writer done.\n"); /* Remove the semaphore from the system */ if (semctl (semid, 0, IPC_RMID) < 0) { perror ("error in removing semaphore from the system"); exit (1); } printf ("Semaphore cleanup complete.\n"); } exit (0); }
Processi concorrenti in Unix© Domenico Barretta Semafori Posix Una interessante libreria di semafori è quella dello standard Posix Comoda, ma non sempre implementata La libreria da importare è la semaphore.h Il tipo di un semaforo è sem_t Le principali funzioni per l’utilizzo dei semafori sono: sem_init() sem_wait() sem_post() sem_trywait()
Processi concorrenti in Unix© Domenico Barretta Posix - sem_init() Sintassi int sem_init(sem_t *sem, int pshared, unsigned int value) Effetto Inizializza il semaforo sem con il valore iniziale value Ritorna –1 in caso di errore Parametri Il semaforo da creare Se pshared è 0 il semaforo non è condiviso, altrimenti è condiviso Il valore iniziale
Processi concorrenti in Unix© Domenico Barretta Posix - sem_wait() Sintassi int sem_wait(sem_t *sem) Effetto Decrementa il valore del semaforo Se il semaforo è a 0, il chiamante viene sospeso Utilizzando la sem_trywait() si ha lo stesso effetto senza sospensione del processo Restituisce 0 in caso di successo, -1 altrimenti Parametri Il semaforo su cui agire
Processi concorrenti in Unix© Domenico Barretta Posix - sem_post() Sintassi int sem_post(sem_t *sem) Effetto Se non ci sono processi sospesi sul semaforo, incrementa il valore del semaforo Se ci sono processi sospesi sul semaforo, ne viene risvegliato uno Restituisce 0 in caso di successo, -1 altrimenti Parametri Il semaforo su cui agire
Processi concorrenti in Unix© Domenico Barretta Socket E’ possibile scrivere programmi in C che utilizzano la rete per comunicare Es: implementazione del paradigma client-server L’interfaccia Socket permette di utilizzare il canale di rete sottostante E’ possibile utilizzare questa interfaccia con diversi protocolli di rete Scelta più comune: TCP/IP Esiste anche per Windows (winsocket) Possibilità di interfacciare programmi che girano su piattaforme diverse
Processi concorrenti in Unix© Domenico Barretta Socket Per comunicare tramite l’interfaccia socket è necessario stabilire una connessione Una connessione fra un processo P e un processo Q è rappresentata da quattro parametri: Indirizzo IP di P Numero di porta di P Indirizzo IP di Q Numero di porta di Q Un processo può avere contemporaneamente attive più connessioni Es: un server per un certo numero di client
Processi concorrenti in Unix© Domenico Barretta Interfaccia (API) di socket I file di libreria da includere per utilizzare i socket sono: sys/types.h, sys/socket.h, netinet/in.h La struttura dati che descrive un socket è la seguente: struct sockaddr_in { short sin_family; //Solitamente AF_INET ushort sin_port; //Numero di porta struct in_addr sin_addr; //Indirizzo IP char sin_zero[8]; } //Inutile
Processi concorrenti in Unix© Domenico Barretta Creazione della connessione Per creare una connessione esistono due modi diversi: Il server utilizza la funzione accept (bloccante) che effettua un’apertura passiva (si dichiara disponibile ad aprire una connessione) Il client utilizza la funzione connect che effettua un’apertura attiva (stabilisce effettivamente la connessione con il server) Perché una connect abbia successo, il server che si intende contattare deve aver effettuato l’apertura passiva
Processi concorrenti in Unix© Domenico Barretta Socket – Lato client Il client esegue le seguenti operazioni: Definisce e inizializza una variabile di tipo struct sockaddr_in contenente le informazioni relative al server (indirizzo IP e porta) Crea un socket della connessione Esegue la connect specificando il proprio socket
Processi concorrenti in Unix© Domenico Barretta Socket – Lato server Il server Predispone una variabile struct sockaddr_in client_addr per memorizzare indirizzo IP e porta del client Predispone una variabile struct sockaddr_in server_addr per memorizzare il proprio indirizzo IP e port (normalmente si specifica solo la porta) Crea un socket per accettare connessioni Effettua, tramite la funzione bind un binding fra il socket e server_addr Effettua la accept per stabilire la connessione
Processi concorrenti in Unix© Domenico Barretta socket() Sintassi int socket(int family, int type, int protocol Effetto Crea un socket e ne restituisce il descrittore; restituisce -1 in caso di errore Parametri Famiglia di protocolli ( AF_INET per TCP/IP) Tipo di comunicazione: SOCK_STREAM per flusso affidabile di dati SOCK_DGRAM per datagrammi UDP Protocollo della famiglia (solitamente 0 )
Processi concorrenti in Unix© Domenico Barretta connect() Sintassi int connect(int sd, struct sockaddr_in *server_addr, int ep_len) Effetto Effettua l’apertura attiva della connessione Parametri Il socket da utilizzare I dati relativi all’indirizzo e porta del server La lunghezza del parametro precedente (tipicamente sizeof(server_addr) )
Processi concorrenti in Unix© Domenico Barretta bind() Sintassi int bind(int sd, struct sockaddr_in *server_addr, int ep_len) Effetto Associa un numero di porta TCP ad un socket. Restituisce 0 in caso di successo, -1 altrimenti Parametri Il socket da utilizzare I dati relativi all’indirizzo e porta del server La lunghezza del parametro precedente (tipicamente sizeof(server_addr) )
Processi concorrenti in Unix© Domenico Barretta listen() Sintassi int listen(int sd, int len) Effetto Crea e dimensiona una coda di richieste di connessione pendenti associata al socket. Restituisce 0 in caso di successo, -1 altrimenti Parametri Il socket per cui creare la coda La lunghezza della coda
Processi concorrenti in Unix© Domenico Barretta accept() Sintassi int accept(int sd, struct sockaddr_in *client_addr, int ep_len) Effetto Accetta una richiesta di collegamento in qualità di server e restituisce un socket Parametri Il socket da utilizzare per la ricezione della richiesta I dati relativi all’indirizzo e porta del client La lunghezza del parametro precedente (tipicamente sizeof(client_addr) )
Processi concorrenti in Unix© Domenico Barretta Trasferimento di dati Per trasferire dati si utilizzano le funzioni send() e recv() int send(ind sd, char *message, int len, int flags) int recv(ind sd, char *message, int len, int flags) Parametri Il socket da utilizzare Una stringa contentente il messaggio La lunghezza della stringa Dei flag per specificare funzioni speciali (di solito 0 ) Restituiscono il numero di caratteri trasferiti
Processi concorrenti in Unix© Domenico Barretta Altre funzioni utili unsigned int inet_addr(char *stringa) Converte l’indirizzo IP da stringa a formato di rete char * inet_ntoa(unsigned int addr) Converte l’indirizzo IP da formato di rete a stringa unsigned short int htons(unsigned short int port) Converte il numero di porta da numero intero a formato di rete unsigned short int ntohs(unsigned short int port) Converte il numero di porta da formato di rete a numero intero
Processi concorrenti in Unix© Domenico Barretta Socket – esempio di client #include #define PORT 4000 void addr_initialize(struct sockaddr_in *indirizzo, int port, long IPaddr) { indirizzo->sin_family = AF_INET; indirizzo->sin_port = htons((u_short) port); /* htons: host to network conversion, short */ indirizzo->sin_addr.s_addr = IPaddr; } void main(int argc, char* argv[]) { int sd; struct sockaddr_in server_addr; struct sockaddr_in mio_addr; int mio_addr_len=sizeof(mio_addr); int error, num, inviati; char dati[12]="abcdefghilm"; addr_initialize(&server_addr, PORT, inet_addr(argv[1])); sd=socket(AF_INET,SOCK_STREAM,0); error=connect(sd,(struct sockaddr*) &server_addr, sizeof(server_addr)); if (error==0) { printf("Ho eseguito la connessione\n"); printf("\n inserire il numero di caratteri da trasmettere: "); scanf("%d", &num);
Processi concorrenti in Unix© Domenico Barretta Socket – esempio di client while (num > 0) { inviati=send(sd,dati,num,0); printf(" inserire il numero di caratteri da trasmettere: "); scanf("%d", &num); } printf("\n Chiudo la connessione \n"); close(sd); } else printf("%s","\nErrore di connect\n\n"); close(sd); }
Processi concorrenti in Unix© Domenico Barretta Socket – esempio di server #include #define PORT 4000 #define MAXCONN 5 #define DIMBUF 6 void addr_initialize(struct sockaddr_in *indirizzo, int port, long IPaddr) { indirizzo->sin_family = AF_INET; indirizzo->sin_port = htons((u_short) port); /* htons: host to network conversion, short */ indirizzo->sin_addr.s_addr = IPaddr; } void main(int argc, char * argv[]) { int sd,new_sd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int client_len=sizeof(client_addr); int ric=1, i; char buf[DIMBUF]; addr_initialize(&server_addr, PORT, INADDR_ANY); sd=socket(AF_INET,SOCK_STREAM,0); bind(sd,(struct sockaddr*) &server_addr,sizeof(server_addr)); listen(sd,MAXCONN);
Processi concorrenti in Unix© Domenico Barretta Socket – esempio di server while (1) { printf("\nMi pongo in attesa di richieste di connessione\n"); new_sd=accept(sd,(struct sockaddr*) &client_addr, &client_len); printf("Ho accettato una connessione\n"); ric=1; while (ric>0) { ric=recv(new_sd,buf,DIMBUF,0); printf("\nHo ricevuto %d caratteri: ",ric); for (i=0; i<ric;i++) printf("%c", buf[i]); } close(new_sd); printf("chiudo la connessione\n"); } /* fine del ciclo perenne */ close(sd); }