+illustrata in \figref{fig:ipc_fifo_server_arch} in cui i client inviano le
+richieste al server su una fifo nota mentre le risposte vengono reinviate dal
+server a ciascuno di essi su una fifo temporanea creata per l'occasione.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[height=9cm]{img/fifoserver}
+ \caption{Schema dell'utilizzo delle fifo nella realizzazione di una
+ architettura di comunicazione client/server.}
+ \label{fig:ipc_fifo_server_arch}
+\end{figure}
+
+Come esempio di uso questa architettura e dell'uso delle fifo, abbiamo scritto
+un server di \textit{fortunes}, che restituisce, alle richieste di un client,
+un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
+dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
+da riga di comando. Il corpo principale del server è riportato in
+\figref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
+gestione delle opzioni a riga di comando, che effettua il settaggio delle
+variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
+ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
+diverso da quelli preimpostati. Il codice completo è nel file
+\file{FortuneServer.c}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+char *fifoname = "/tmp/fortune.fifo";
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int i, n = 0;
+ char *fortunefilename = "/usr/share/games/fortunes/italia";
+ char **fortune;
+ char line[80];
+ int fifo_server, fifo_client;
+ int nread;
+ ...
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
+ if (errno!=EEXIST) {
+ perror("Cannot create well known fifo");
+ exit(1);
+ }
+ }
+ /* open fifo two times to avoid EOF */
+ fifo_server = open(fifoname, O_RDONLY);
+ if (fifo_server < 0) {
+ perror("Cannot open read only well known fifo");
+ exit(1);
+ }
+ if (open(fifoname, O_WRONLY) < 0) {
+ perror("Cannot open write only well known fifo");
+ exit(1);
+ }
+ /* Main body: loop over requests */
+ while (1) {
+ nread = read(fifo_server, line, 79); /* read request */
+ if (nread < 0) {
+ perror("Read Error");
+ exit(1);
+ }
+ line[nread] = 0; /* terminate fifo name string */
+ n = random() % i; /* select random value */
+ fifo_client = open(line, O_WRONLY); /* open client fifo */
+ if (fifo_client < 0) {
+ perror("Cannot open");
+ exit(1);
+ }
+ nread = write(fifo_client, /* write phrase */
+ fortune[n], strlen(fortune[n])+1);
+ close(fifo_client); /* close client fifo */
+ }
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del server di \textit{fortunes}
+ basato sulle fifo.}
+ \label{fig:ipc_fifo_server}
+\end{figure}
+
+Il server richiede (\texttt{\small 12}) che sia stata impostata una dimensione
+dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore
+\var{fortune} avviene solo quando questa dimensione viene specificata, la
+presenza di un valore nullo provoca l'uscita dal programma attraverso la
+routine (non riportata) che ne stampa le modalità d'uso. Dopo di che installa
+(\texttt{\small 13--15}) la funzione che gestisce i segnali di interruzione
+(anche questa non è riportata in \figref{fig:ipc_fifo_server}) che si limita a
+rimuovere dal filesystem la fifo usata dal server per comunicare.
+
+Terminata l'inizializzazione (\texttt{\small 16}) si effettua la chiamata alla
+funzione \code{FortuneParse} che legge dal file specificato in
+\var{fortunefilename} le prime \var{n} frasi e le memorizza (allocando
+dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}.
+Anche il codice della funzione non è riportato, in quanto non direttamente
+attinente allo scopo dell'esempio.
+
+Il passo successivo (\texttt{\small 17--22}) è quello di creare con
+\func{mkfifo} la fifo nota sulla quale il server ascolterà le richieste,
+qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso
+in cui la funzione \func{mkfifo} fallisce per la precedente esistenza della
+fifo).
+
+Una volta che si è certi che la fifo di ascolto esiste si procede
+(\texttt{\small 23--32}) alla sua apertura. Questo viene fatto due volte
+per evitare di dover gestire all'interno del ciclo principale il caso in cui
+il server è in ascolto ma non ci sono client che effettuano richieste.
+Si ricordi infatti che quando una fifo è aperta solo dal capo in lettura,
+l'esecuzione di \func{read} ritorna con zero byte (si ha cioè una condizione
+di end-of-file).
+
+Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque
+client non apre a sua volta la fifo nota in scrittura per effettuare la sua
+richiesta. Pertanto all'inizio non ci sono probelmi, il client però, una volta
+ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la fifo.
+A questo punto il server resta (se non ci sono altri client che stanno
+effettuando richieste) con la fifo chiusa sul lato in lettura e a questo punto
+\func{read} non si bloccherà in attesa di input, ma ritornerà in continuazione
+restituendo un end-of-file.\footnote{Si è usata questa tecnica per
+ compatibilità, Linux infatti supporta l'apertura delle fifo in
+ lettura/scrittura, per cui si sarebbe potuto effettuare una singola apertura
+ con \macro{O\_RDWR}, la doppia apertura comunque ha il vantaggio che non si
+ può scrivere per errore sul capo aperto in sola lettura.}
+
+Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
+ 24--28}),\footnote{di solito si effettua l'apertura del capo in lettura in
+ modalità non bloccante, per evitare il rischio di uno stallo (se nessuno
+ apre la fifo in scrittura il processo non ritornerà mai dalla \func{open})
+ che nel nostro caso non esiste, mentre è necessario potersi bloccare in
+ lettura in attesa di una richiesta.} si esegue una seconda apertura in
+scrittura (\texttt{\small 29--32}), scartando il relativo file descriptor che
+non sarà mai usato, ma lasciando la fifo comunque aperta anche in scrittura,
+cosicché le successive possano bloccarsi.
+
+A questo punto si può entrare nel ciclo principale del programma che fornisce
+le risposte ai client (\texttt{\small 34--50}), che viene eseguito
+indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
+modo da passare attraverso la routine di chiusura che cancella la fifo).
+
+Il server è progettato per accettare come richieste dai client delle stringhe
+che contengono il nome della fifo sulla quale deve essere inviata la risposta.
+Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
+richiesta dalla fifo nota (che a questo punto si bloccherà tutte le volte che
+non ci sono richieste). Dopo di che, una volta terminata la stringa
+(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
+ricavare la frase da inviare, si procederà (\texttt{\small 42--46})
+all'apertura della fifo per la risposta, che \texttt{\small 47--48}) poi vi
+sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
+non serve più.
+
+Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
+in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
+a video le informazioni di utilizzo ed esce, riportando solo la sezione
+principale del programma e le definizioni delle variabili. Il codice completo
+è nel file \file{FortuneClient.c} dei sorgenti allegati.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int n = 0;
+ char *fortunefilename = "/tmp/fortune.fifo";
+ char line[80];
+ int fifo_server, fifo_client;
+ char fifoname[80];
+ int nread;
+ char buffer[PIPE_BUF];
+ ...
+ snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */
+ if (mkfifo(fifoname, 0622)) { /* open client fifo */
+ if (errno!=EEXIST) {
+ perror("Cannot create well known fifo");
+ exit(-1);
+ }
+ }
+ fifo_server = open(fortunefilename, O_WRONLY); /* open server fifo */
+ if (fifo_server < 0) {
+ perror("Cannot open well known fifo");
+ exit(-1);
+ }
+ nread = write(fifo_server, fifoname, strlen(fifoname)+1); /* write name */
+ close(fifo_server); /* close server fifo */
+ fifo_client = open(fifoname, O_RDONLY); /* open client fifo */
+ if (fifo_client < 0) {
+ perror("Cannot open well known fifo");
+ exit(-1);
+ }
+ nread = read(fifo_client, buffer, sizeof(buffer)); /* read answer */
+ printf("%s", buffer); /* print fortune */
+ close(fifo_client); /* close client */
+ close(fifo_server); /* close server */
+ unlink(fifoname); /* remove client fifo */
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del client di \textit{fortunes}
+ basato sulle fifo.}
+ \label{fig:ipc_fifo_client}
+\end{figure}
+
+La prima istruzione (\texttt{\small 12}) compone il nome della fifo che dovrà
+essere utilizzata per ricevere la risposta dal server. Si usa il \acr{pid}
+del processo per essere sicuri di avere un nome univoco; dopo di che
+(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo
+in caso di errore (a meno che il file non sia già presente sul filesystem).
+
+A questo punto il client può effettuare l'interrogazione del server, per
+questo prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
+(\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
+della fifo da utilizzare per la risposta. Infine si richiude la fifo del
+server che a questo punto non serve più (\texttt{\small 25}).
+
+Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto
+si apre (\texttt{\small 26--30}) la fifo appena creata, da cui si deve
+riceverla, dopodiché si effettua una lettura (\texttt{\small 31})
+nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate
+dal server siano sempre di dimensioni inferiori a \macro{PIPE\_BUF},
+tralasciamo la gestione del caso in cui questo non è vero. Infine si stampa
+(\texttt{\small 32}) a video la risposta, si chiude (\texttt{\small 33}) la
+fifo e si cancella (\texttt{\small 34}) il relativo file.
+
+Si noti come la fifo per la risposta sia stata aperta solo dopo aver inviato
+la richiesta, se non si fosse fatto così si avrebbe avuto uno stallo, in
+quanto senza la richiesta, il server non avrebbe potuto aprirne il capo in
+scrittura e l'apertura si sarebbe bloccata indefinitamente.
+
+Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
+complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
+ che esamina questa architettura in \cite{APUE}, nota come sia impossibile
+ per il server sapere se un client è andato in crash, con la possibilità di
+ far restare le fifo temporanee sul filesystem, di come sia necessario
+ intercettare \macro{SIGPIPE} dato che un client può terminare dopo aver
+ fatto una richiesta, ma prima che la risposta sia inviata (cosa che nel
+ nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle
+fifo non è adatta a risolvere questo tipo di problemi, che possono essere
+affrontati in maniera più semplice ed efficace o usando i
+\textit{socket}\index{socket} (che tratteremo in dettaglio a partire da
+\capref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione diversi,
+come quelli che esamineremo in seguito.