informatica:sol:laboratorio18:esercitazionib:fifoexample
Esempio di programma client/server che utilizza pipe con nome (FIFO)
Client e server comunicano con una pipe FIFO. Il server riceve i comandi da eseguire su una FIFO “pubblica” e restituisce le risposte su una FIFO privata del client il cui nome è stato inviato insieme al messaggio di richiesta. Il processo server “forka” un processo figlio per eseguire il comando richiesto dal client redirigendo lo standard output per ottenere il risultato.
msg.h
#if !defined(MSG_H) #define MSG_H #include <linux/limits.h> /* Linux specific definisce PIPE_BUF */ #define F_SIZE 256 /* size massima del nome della FIFO del client */ #define B_SIZE (PIPE_BUF-F_SIZE) /* size massima dei dati scambiati in modo atomico */ #define SYSCALL(r,c,e) \ if((r=c)==-1) { perror(e);exit(errno); } // FIFO pubblica per inviare le richieste al server const char *PUBLIC = "/tmp/PUBLIC"; /* * In un singolo messaggio vogliamo inviare sia il comando da eseguire * che il nome della FIFO su cui vogliamo ottenere il risultato. */ struct message { char fifo_name[F_SIZE]; char cmd_line[B_SIZE]; }; #endif /* MSG_H */
client.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include "msg.h" // nome della FIFO privata char fifo_name[F_SIZE]; void cleanup() { int n; SYSCALL(n, unlink(fifo_name), "cleanup: unlink private fifo"); } int main() { static char buffer[PIPE_BUF]; struct message msg; int publicfifo, privatefifo, n; // fifo privata per ricevere le risposte dal server snprintf(fifo_name, F_SIZE, "/tmp/fifo%d", getpid()); SYSCALL(n, mkfifo(fifo_name, 0666), "mkfifo"); // qualora qualcosa vada storto if (atexit(cleanup) != 0) { fprintf(stderr, "ERRORE in atexit\n"); exit(EXIT_FAILURE); } // apro la FIFO pubblica in sola scrittura SYSCALL(publicfifo, open(PUBLIC,O_WRONLY), "open public fifo"); while(1) { SYSCALL(n,write(1, "\n cmd>", 6), "write 1"); // resetto il messaggio memset(msg.fifo_name, 0x0, F_SIZE); memset(msg.cmd_line, 0x0, B_SIZE); // leggo il comando da inviare al server SYSCALL(n,read(0, msg.cmd_line, B_SIZE), "read 0"); // devo uscire ? if(strncmp("quit", msg.cmd_line, n-1) == 0) break; strncpy(msg.fifo_name,fifo_name, strlen(fifo_name)+1); // mando la richiesta al server SYSCALL(n, write(publicfifo, &msg, sizeof(msg)), "write public fifo"); // apro la FIFO privata in sola lettura aspettando che il server la apra in scrittura SYSCALL(privatefifo, open(msg.fifo_name, O_RDONLY), "open private fifo"); do { memset(buffer, 0x0, PIPE_BUF); SYSCALL(n ,read(privatefifo, buffer, PIPE_BUF), "read private fifo"); fprintf(stdout, "%s", buffer); } while(n>0); SYSCALL(n, close(privatefifo), "close private fifo"); } SYSCALL(n, close(publicfifo), "close public fifo"); return 0; }
server.c
#include <errno.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include "msg.h" #define MAXARGS 100 // massimo numero di argomenti di un comando // costruisce un vettore di argomenti da una stringa void buildargs(char *line, char * args[]) { int i = 0; args[i++] = strtok(line," \n"); do { args[i] = strtok(NULL," \n"); } while(args[i++]!=NULL); } int main() { struct message msg; static char buffer[PIPE_BUF]; /* creo la FIFO pubblica */ if ((mkfifo(PUBLIC, 0666) == -1) && errno!=EEXIST) { perror("mkfifo public fifo"); exit(errno); } int publicfifo; // apertura in sola lettura per ricevere i comandi dai clients, aspetto che // almeno uno dei client apra la FIFO in scrittura SYSCALL(publicfifo, open(PUBLIC, O_RDONLY), "open public fifo (read)"); // apro la FIFO in scrittura per evitare di ricevere EOF sulla FIFO pubblica // che rimane sempre aperta int notused; SYSCALL(notused, open(PUBLIC, O_WRONLY|O_NONBLOCK), "open public fifo (write)"); while(1) { int n, done; SYSCALL(n, read(publicfifo, &msg, sizeof(msg)), "read public fifo"); if (n == 0) break; // ho letto End-Of-File (EOF), esco n=0, done=0; do { int privatefifo; // attendo che il client si connetta riprovando un po' di volte if ((privatefifo = open(msg.fifo_name, O_WRONLY|O_NONBLOCK)) == -1) { sleep(2); } else { int channel[2]; int r; SYSCALL(r, pipe(channel), "pipe"); // creo una pipe senza nome char *args[MAXARGS]; buildargs(msg.cmd_line, args); if (fork() == 0) { // figlio SYSCALL(r, close(channel[0]), "close reader"); SYSCALL(r, dup2(channel[1],1), "dup2 writer"); SYSCALL(r, close(channel[1]), "close writer"); execvp(args[0], &args[0]); fprintf(stderr, "execvp fallita"); exit(EXIT_FAILURE); } // padre SYSCALL(r, close(channel[1]), "close writer"); SYSCALL(r, write(privatefifo,"\n",1), "write private fifo"); do { SYSCALL(n, read(channel[0], buffer, PIPE_BUF), "read channel[0]"); SYSCALL(r, write(privatefifo,buffer,n), "write private fifo"); memset(buffer, 0x0, PIPE_BUF); } while(n>0); SYSCALL(r, close(channel[0]), "close reader"); SYSCALL(r, close(privatefifo), "close private fifo"); // invio EOF done = 1; } }while(!done && n++ < 10); if (!done) { fprintf(stderr, "Il client non ha inviato il comando, condizione di fallimento\n"); exit(EXIT_FAILURE); } } return 0; }
informatica/sol/laboratorio18/esercitazionib/fifoexample.txt · Ultima modifica: 17/04/2018 alle 08:25 (7 anni fa) da Massimo Torquati