leggerli, quando i dati inviati sono destinati a loro.
Per risolvere questo problema, si può usare un'architettura come quella
-illustrata da Stevens in \cite{APUE}, in cui le risposte vengono inviate su
-fifo temporanee identificate dal \acr{pid} dei client, ma in ogni caso il
-sistema è macchinoso e continua ad avere vari inconvenienti\footnote{lo stesso
- Stevens 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, come sia necessario intercettare \macro{SIGPIPE} dato che un
- client può terminare dopo aver fatto una richiesta, ma prima che la risposta
- sia inviata, e come occorra gestire il caso in cui non ci sono client attivi
- (e la lettura dalla fifo nota restituisca al serve un end-of-file.}; 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.
+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'occazione.
+
+\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}{}
+int main(int argc, char *argv[])
+{
+ int i, n = 10;
+ char *fortunefilename = "/usr/share/games/fortunes/kids";
+ char *fifoname = "/tmp/fortune.fifo";
+ char **fortune;
+ char line[80];
+ int fifo_server, fifo_client;
+ int nread;
+ ...
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ /*
+ * Comunication section
+ */
+ if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
+ if (errno!=EEXIST) {
+ perror("Cannot create well known fifo");
+ exit(-1);
+ }
+ }
+ while (1) {
+ fifo_server = open(fifoname, O_RDONLY); /* open well known fifo */
+ if (fifo_server < 0) {
+ perror("Cannot open well known fifo");
+ exit(-1);
+ }
+ nread = read(fifo_server, line, 79); /* read request */
+ line[nread] = 0;
+ n = random() % i; /* select random value */
+ fifo_client = open(line, O_WRONLY); /* open client fifo */
+ nread = write(fifo_client, /* write phrase */
+ fortune[n], strlen(fortune[n])+1);
+ close(fifo_client); /* close well known fifo */
+ close(fifo_server); /* 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}
+
+
+
+
+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, come sia necessario
+ intercettare \macro{SIGPIPE} dato che un client può terminare dopo aver
+ fatto una richiesta, ma prima che la risposta sia inviata, e come occorra
+ gestire il caso in cui non ci sono client attivi (e la lettura dalla fifo
+ nota restituisca al serve un end-of-file.}; 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.
un identificatore può venire riutilizzato.
Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
- al kernel 2.2.x questo numero, ed altri limiti relativi al \textit{System V
- IPC}, potevano essere cambiati solo con una ricompilazione del kernel,
- andando a modificare le costanti definite nei relativi haeder file. A
- partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
- scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
- \file{/proc/sys/kernel} o con \texttt{syscntl}.} e per ciascuno di essi
-viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
+ al kernel 2.2.x questi valori, definiti dalle costanti \macro{MSGMNI},
+ \macro{SEMMNI} e \macro{SHMMNI}, potevano essere cambiati (come tutti gli
+ altri limiti relativi al \textit{System V IPC}) solo con una ricompilazione
+ del kernel, andando a modificarne la definizione nei relativi haeder file.
+ A partire dal kernel 2.4.x è possibile cambiare questi valori a sistema
+ attivo scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
+ \file{/proc/sys/kernel} o con l'uso di \texttt{syscntl}.} e per ciascuno di
+essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
l'oggetto viene creato usando uno spazio che era già stato utilizzato in
precedenza per restituire l'identificatore al numero di oggetti presenti viene
di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato
dalla costante \macro{IPCMNI}, definita in \file{include/linux/ipc.h}, che
- indica il limite massimo per il numero di oggetti di IPC, il cui valore è
+ indica il limite massimo per il numero di oggetti di IPC, ed il cui valore è
32768.} si evita così il riutilizzo degli stessi numeri, e si fa sì che
l'identificatore assuma tutti i valori possibili.
* Read n fortunes from fortune file file, and put it into the
* string array fortune
*
- * $Id: FortuneParse.c,v 1.1 2002/08/18 10:34:10 piccardi Exp $
+ * $Id: FortuneParse.c,v 1.2 2002/08/18 14:38:04 piccardi Exp $
*
****************************************************************/
/*
#include <errno.h> /* error definitions */
#include <fcntl.h> /* */
+#include "macros.h"
+
/* Subroutines declaration */
extern void usage(void);
/* Variables definition */
FILE *fortunefile;
char line[80];
- int i;
+ int i, len;
/*
* fortune file scanning, read string in memory
*/
perror("Read error");
exit(-1);
}
- if (line[0]=='\n') {
+ debug("i=%d, line=%s", i, line);
+ if (line[0]=='%') {
if (fortune[i]!=NULL) i++;
continue;
}
+ len = strlen(line) + 1;
if (fortune[i]==NULL) {
- fortune[i] = (char *) malloc(strlen(line)+1);
- strncpy(fortune[i], line, strlen(line)+1);
+ fortune[i] = malloc(len);
+ strncpy(fortune[i], line, len);
} else {
- fortune[i] = (char *) realloc(fortune[i], strlen(line)+1);
- strncat(fortune[i], line, strlen(line)+1);
+ fortune[i] = realloc(fortune[i], strlen(fortune[i])+len+1);
+ strncat(fortune[i], line, len);
}
} while (i<n);
return i;
*
* Usage: fortuned -h give all info
*
- * $Id: FortuneServer.c,v 1.1 2002/08/18 10:34:10 piccardi Exp $
+ * $Id: FortuneServer.c,v 1.2 2002/08/18 14:38:04 piccardi Exp $
*
****************************************************************/
/*
int main(int argc, char *argv[])
{
/* Variables definition */
- int n = 0;
- FILE *fortunefile;
- char *fortunefilename = "/usr/share/misc/fortune/fortune.it";
+ int i, n = 0;
+ char *fortunefilename = "/usr/share/games/fortunes/kids";
char *fifoname = "/tmp/fortune.fifo";
char **fortune;
char line[80];
* Input section: decode parameters passed in the calling
* Use getopt function
*/
- int i;
- opterr = 0; /* don't want writing to stderr */
+ opterr = 0; /* don't want writing to stderr */
while ( (i = getopt(argc, argv, "hn:f:")) != -1) {
switch (i) {
/*
n = strtol(optarg, NULL, 10);
fortune = (char **) calloc(sizeof(*fortune), n);
break;
- case '?': /* unrecognized options */
+ case '?': /* unrecognized options */
printf("Unrecognized options -%c\n",optopt);
usage();
- default: /* should not reached */
+ default: /* should not reached */
usage();
}
}
* Main code beginning
*
* ***********************************************************/
- if (n==0) { /* if no pool depth exit */
- usage(); /* print usage info */
- }
- i = FortuneParse(fortunefilename, fortune, n);
- for (n=0; n<i; n++) debug("%s", fortune[n]);
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ for (n=0; n<i; n++) debug("%s\n\n", fortune[n]);
/*
* Comunication section
*/
- if (mkfifo(fifoname, 0622)) {
+ if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
if (errno!=EEXIST) {
perror("Cannot create well known fifo");
exit(-1);
}
}
+ /* Main body: loop over requests */
while (1) {
- fifo_server = open(fifoname, O_RDONLY);
+ fifo_server = open(fifoname, O_RDONLY); /* open well known fifo */
if (fifo_server < 0) {
perror("Cannot open well known fifo");
exit(-1);
}
- nread = read(fifo_server, line, 79);
+ nread = read(fifo_server, line, 79); /* read request */
line[nread] = 0;
debug("%s %d\n", line,nread);
- n = random() % i;
+ n = random() % i; /* select random value */
debug("fortune[%d]=%s\n", n, fortune[n]);
- fifo_client = open(line, O_WRONLY);
- nread = write(fifo_client, fortune[n], strlen(fortune[n])+1);
- close(fifo_client);
- close(fifo_server);
+ fifo_client = open(line, O_WRONLY); /* open client fifo */
+ nread = write(fifo_client, /* write phrase */
+ fortune[n], strlen(fortune[n])+1);
+ close(fifo_client); /* close well known fifo */
+ close(fifo_server); /* close client fifo */
}
}
/*