Lab. di Sistemi Operativi - Esercitazione n° 11- - Socket Locali - 1 Sommario Esercizi su: Comunicazione FIFO Socket locali 2 - FIFO - 3 FIFO 4 Esercizio n° 1 – FIFO – (comunicazione FIFO Client/Server) 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 su due shell separate sulla stessa macchina) Esecuzione: $ ./server $ ./client 5 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> typedef struct { pid_t clientPID; } richiesta; int main () { creazione della FIFO int fifo; pid_t figlio; richiesta buffer; if (mkfifo("serverFIFO", S_IRUSR | S_IWUSR | S_IXUSR) < 0) if (errno != EEXIST) { perror ("Impossibile creare la serverFIFO.\n"); exit (-1); } /*Continua nella slide successiva*/ 6 Sol. Eser. n° 1 – FIFO – server.c if ((fifo = open ("serverFIFO", O_RDONLY)) == -1) { perror ("Errore nella open.\n"); exit (-1); } while (1) { read (fifo, &buffer, sizeof (richiesta)); if ((figlio = fork()) < 0) { perror ("Impossibile creare il figlio.\n"); exit (-1); } if (figlio == 0) { printf ("Pid del Client: %d\n", buffer.clientPID); break; } } return 0; } 7 Sol. Eser. n° 1 – FIFO – client.c #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> typedef struct { Struttura contenente il pid pid_t clientPID; } richiesta; int main () { int fifo; 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)); close (fifo); return 0; } 8 - Socket locali - 9 Funzione socket 10 Leggere da un socket 11 Scrivere da un socket 12 Il server 13 Il client 14 Esercizio n° 2 – Socket locali– (- client/server con fork -) Scrivere due programmi C, server.c e client.c. Il server.c, crea una socket locale su cui scriverà il messaggio da mandare al client ed un nuovo processo (fork), ogni volta che inizia una connessione con il programma client. Tale processo, dovrà leggere sulla socket il messaggio scritto dal client e scrivere sulla socket il messaggio da mandare al client. Il client.c dovrà creare una socket locale su cui scriverà il messaggio da mandare al server (lanciare l’ esecuzione dei due programmi su due shell distinti della stessa macchina) Esecuzione $ ./server (shell1) MESSAGGIO DA CLIENT: Saluti da client $ ./client (shell2) MESSAGGIO DA SERVER: Saluti dal server 15 Sol. Eser. n° 2 server.c #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/types.h> #include <unistd.h> int connection_handler(int connection_fd) { int nbytes; char buffer[256]; nbytes = read(connection_fd, buffer, 256); buffer[nbytes] = 0; printf("MESSAGGIO DA CLIENT: %s\n", buffer); nbytes = sprintf(buffer, ”Saluti dal server"); write(connection_fd, buffer, nbytes); close(connection_fd); return 0; } 16 Sol. Eser. n° 2 server.c int main(void) { struct sockaddr_un address; int socket_fd, connection_fd; size_t address_length; pid_t child; socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0); if(socket_fd < 0) { printf("socket() failed\n"); return 1; } unlink("./demo_socket"); /*Rimuove la socket se già esiste */ address.sun_family = AF_LOCAL; address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "./demo_socket"); /*Continua nella slide successiva*/ 17 Sol. Eser. n° 2 server.c if(bind(socket_fd, (struct sockaddr *) &address, address_length) ! = 0) {printf("bind() failed\n"); return 1;} if(listen(socket_fd, 5) != 0) {printf("listen() failed\n"); return 1;} while((connection_fd = accept(socket_fd, (struct sockaddr *) &address, &address_length)) > -1) { child = fork(); if(child == 0) { return connection_handler(connection_fd); } close(connection_fd); } close(socket_fd); unlink("./demo_socket"); /*Rimuove la socket*/ return 0; 18 } Sol. Eser. n° 2 client.c #include <stdio.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> int main(void) { struct sockaddr_un address; int socket_fd, nbytes; size_t address_length; char buffer[256]; socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0); if(socket_fd < 0) {printf("socket() failed\n"); return 1;} address.sun_family = AF_LOCAL; address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "./demo_socket"); /*Continua nella slide successiva*/ 19 Sol. Eser. n° 2 client.c if(connect(socket_fd, (struct sockaddr *) &address, address_length) ! = 0) { printf("connect() failed\n"); return 1; } nbytes = sprintf(buffer, “Saluti da client"); write(socket_fd, buffer, nbytes); nbytes = read(socket_fd, buffer, 256); buffer[nbytes] = 0; printf("MESSAGGIO DA SERVER: %s\n", buffer); close(socket_fd); return 0; } 20 Esercizio n° 3 – Socket locali– (- client/server -) Scrivere due programmi C, socket-server.c e socketclient.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 l’esecuzione. 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) Esecuzione server: $ ./socket-server /tmp/socket Esecuzione client: $ ./socket-client /tmp/socket “Messaggio” $ ./socket-client /tmp/socket “quit” 21 Sol. Eser. n° 3 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) Legge la lunghezza del { while (1) messaggio dalla socket e la { int length; mette in length char* text; 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; } 22 Sol. Eser. n° 3 socket-server.c int main (int argc, char* const argv[]) { const char* const socket_name = argv[1]; int socket_fd, serverLen, clientLen; int client_sent_quit_message; struct sockaddr_un serverUNIXAddress;/* Server address */ struct sockaddr_un clientUNIXAddress; /* Client address */ struct sockaddr* serverSockAddrPtr; /* Ptr to server address */ struct sockaddr* clientSockAddrPtr; /* Ptr to client address */ serverSockAddrPtr = (struct sockaddr*) &serverUNIXAddress; serverLen = sizeof (serverUNIXAddress); clientSockAddrPtr = (struct sockaddr*) &clientUNIXAddress; clientLen = sizeof (clientUNIXAddress); /*Continua nella slide successica*/ 23 Sol. Eser. n° 3 socket-server.c socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0); serverUNIXAddress.sun_family = AF_LOCAL; strcpy (serverUNIXAddress.sun_path, socket_name); bind (socket_fd, serverSockAddrPtr, serverLen); listen (socket_fd, 5); /* Maximum pending connection length */ /*Continua nella slide successica*/ 24 Sol. Eser. n° 3 socket-server.c do { int client_socket_fd; client_socket_fd = accept (socket_fd, clientSockAddrPtr, &clientLen); client_sent_quit_message = server (client_socket_fd); close (client_socket_fd); } while (!client_sent_quit_message); close (socket_fd); unlink (socket_name); /*Rimuove la socket*/ return 0; } 25 Sol. Eser. n° 3 socket-client.c #include #include #include #include #include <stdio.h> <string.h> <sys/socket.h> <sys/un.h> <unistd.h> void write_text (int socket_fd, const char* text) { 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); } 26 Sol. Eser. n° 3 socket-client.c int main (int argc, char* const argv[]) { const char* const socket_name = argv[1]; const char* const message = argv[2]; 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); serverUNIXAddress.sun_family = AF_LOCAL; strcpy (serverUNIXAddress.sun_path, socket_name); connect (socket_fd, serverSockAddrPtr, serverLen); write_text (socket_fd, message); close (socket_fd); return 0; } 27 Esercizio n° 4 – Socket locali– (- client/server -) Scrivere due programmi C, chef.c (server) e cook.c (client). Il server crea un socket chiamato “ricetta” e tramite essa fornisce una ricetta a tutti i client che la richiedono. La ricetta è formata da una sequenza di stringhe terminate dal carattere ‘\0’ . Il client si connette al socket chiamato ricetta e legge la ricetta fornita dal server. Man mano che il client legge la ricetta la mostra sullo standard output e quindi termina. Il server, crea un processo figlio che evade la richiesta del client. (lanciare i due programmi, su due shell distinte della stessa macchina) Esecuzione: $ ./chef (shell1) $ ./ cook (shell2) 28 Sol. Eser. n° 4 chef.c (server) #include #include #include #include #include <stdio.h> <signal.h> <sys/types.h> <sys/socket.h> <sys/un.h> /* For AFUNIX sockets */ int writeRicette (int fd) { static char* line1 = “prova, prova, prova, prova,"; static char* line2 = “prova, & prova."; write (fd, line1, strlen (line1) + 1); /* Write first line */ write (fd, line2, strlen (line2) + 1); /* Write second line */ } /*Continua nella slide successiva*/ 29 Sol. Eser. n° 4 chef.c (server) int main (void) { int serverFd, clientFd, serverLen, clientLen; struct sockaddr_un serverUNIXAddress;/* Server address */ struct sockaddr_un clientUNIXAddress; /* Client address */ struct sockaddr* serverSockAddrPtr; /* Ptr to server address */ struct sockaddr* clientSockAddrPtr; /* Ptr to client address */ serverSockAddrPtr = (struct sockaddr*) &serverUNIXAddress; serverLen = sizeof (serverUNIXAddress); clientSockAddrPtr = (struct sockaddr*) &clientUNIXAddress; clientLen = sizeof (clientUNIXAddress); /*Continua nella slide successiva*/ 30 Sol. Eser. n° 4 chef.c (server) serverFd = socket (PF_LOCAL, SOCK_STREAM, 0); serverUNIXAddress.sun_family = AF_LOCAL; /* Set domain type */ strcpy (serverUNIXAddress.sun_path, "ricetta"); /* Set name */ unlink ("ricetta"); /* Remove file if it already exists */ bind (serverFd, serverSockAddrPtr, serverLen); /* Create file */ listen (serverFd, 5); /* Maximum pending connection length */ while (1) { clientFd = accept (serverFd, clientSockAddrPtr, &clientLen); if (fork () == 0) { /* Create child to send receipe */ writeRicette (clientFd); /* Send the recipe */ printf("La ricetta è stata scritta nel socket\n"); close (clientFd); /* Close the socket */ exit (0); /* Terminate */ } else close (clientFd); /* Close the client descriptor */ } } 31 Sol. Eser. n° 4 cook.c (client) #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> /* For AF_UNIX sockets */ int readRicetta (int fd) { char str[200]; while (readLine (fd, str)) /* Read lines until end-ofinput */ printf ("%s\n", str); /* Echo line from socket */ } int readLine (int fd, char *str) { int n; do { /* Read characters until ’\0’ or end-of-input */ n = read (fd, str, 1); /* Read one character */ } while (n > 0 && *str++ != ’\0’); return (n > 0); /* Return false if end-of-input */ } 32 Sol. Eser. n° 4 cook.c (client) int main (void) { int clientFd, serverLen, result; struct sockaddr_un serverUNIXAddress; struct sockaddr* serverSockAddrPtr; serverSockAddrPtr = (struct sockaddr*) &serverUNIXAddress; serverLen = sizeof (serverUNIXAddress); clientFd = socket (PF_LOCAL, SOCK_STREAM, 0); serverUNIXAddress.sun_family = AF_LOCAL; strcpy (serverUNIXAddress.sun_path, "ricetta"); /*Continua nella slide successiva*/ 33 Sol. Eser. n° 4 cook.c (client) /*In attesa di connettersi alla socket*/ do { result = connect (clientFd, serverSockAddrPtr, serverLen); if (result == -1) sleep (1); /* Wait and then try again */ } while (result == -1); readRicetta (clientFd); /* Read the recipe */ close (clientFd); /* Close the socket */ exit (0); /* Done */ } 34