Abbozzo di fortune server con le message queues
authorSimone Piccardi <piccardi@gnulinux.it>
Mon, 26 Aug 2002 21:11:49 +0000 (21:11 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Mon, 26 Aug 2002 21:11:49 +0000 (21:11 +0000)
ipc.tex
sources/MQFortuneServer.c [new file with mode: 0644]

diff --git a/ipc.tex b/ipc.tex
index 0637d4722a7bf91b71c319ea466b1d2be98f2259..286cfdd56565fbb3b1be9e4a4c6b4d4dca990dde 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -124,7 +124,7 @@ consiste nell'inviare l'output di un processo (lo standard output) sull'input
 di un'altro. Realizzeremo il programma di esempio nella forma di un
 \textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un
   programma che permette la creazione dinamica di un oggetto da inserire
-  all'interno di una pagina HTML.}  per apache, che genera una immagine JPEG
+  all'interno di una pagina HTML.}  per Apache, che genera una immagine JPEG
 di un codice a barre, specificato come parametro di input.
 
 Un programma che deve essere eseguito come \textit{CGI} deve rispondere a
@@ -558,7 +558,7 @@ leggerli, quando i dati inviati sono destinati a loro.
 Per risolvere questo problema, si può usare un'architettura come quella
 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.
+server a ciascuno di essi su una fifo temporanea creata per l'occasione.
 
 \begin{figure}[htb]
   \centering
@@ -1229,11 +1229,11 @@ coda.
                                           messaggi. \\
     \macro{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
                                           messaggio.\\
-    \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima di una coda di 
-                                          messaggi.\\
+    \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di 
+                                          una coda.\\
     \hline
   \end{tabular}
-  \caption{Valori delle costanti associati ai limiti delle code di messaggi.}
+  \caption{Valori delle costanti associate ai limiti delle code di messaggi.}
   \label{tab:ipc_msg_limits}
 \end{table}
 
@@ -1297,7 +1297,7 @@ riportato nella figura. In questa struttura il kernel\footnote{come accennato
   questo vale fino ai kernel della serie 2.2.x, essa viene usata nei kernel
   della serie 2.4.x solo per compatibilità in quanto è quella restituita dalle
   funzioni dell'interfaccia.  In \figref{fig:ipc_msgid_sd} sono elencati i
-  campi significativi definiti in \file{sys/msg.h}, a cui si sono agguinti gli
+  campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
   ultimi tre campi che sono previsti dalla implementazione originale di System
   V, ma non dallo standard Unix98.}  mantiene le principali informazioni
 riguardo lo stato corrente della coda.  Quando si crea una nuova coda con
@@ -1315,9 +1315,10 @@ invece:
   rispettivamente il tempo in cui è stato inviato o ricevuto l'ultimo
   messaggio sulla coda, sono inizializzati a 0.
 \item il campo \var{msg\_ctime} viene inizializzato al tempo corrente.
-\item il campo \var{msg\_qbytes} viene inizializzati al limite di sistema.
+\item il campo \var{msg\_qbytes} viene inizializzato al valore preimpostato
+  del sistema (\macro{MSGMNB}).
 \item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
-  primo e ultimo messagio sono inizializzati a \macro{NULL} e
+  primo e ultimo messaggio sono inizializzati a \macro{NULL} e
   \var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è
   inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
   e non devono essere utilizzati da programmi in user space).
@@ -1356,7 +1357,7 @@ mantenuta all'indirizzo \param{buf}, per la coda specificata
 dall'identificatore \param{msqid}. Il comportamento della funzione dipende dal
 valore dell'argomento \param{cmd}, che specifica il tipo di azione da
 eseguire; i valori possibili sono:
-\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}}
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
 \item[\macro{IPC\_STAT}] Legge le informazioni riguardo la coda nella
   struttura indicata da \param{buf}. Occorre avere il permesso di lettura
   sulla coda.
@@ -1373,9 +1374,8 @@ eseguire; i valori possibili sono:
   struttura \var{msqid\_ds} puntata da \param{buf}.  Per modificare i valori
   di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre
   essere il proprietario o il creatore della coda, oppure l'amministratore; lo
-  stesso vale per \var{msg\_qbytes}, con la restrizione che solo
-  l'amministratore può incrementarne il valore a limiti superiori a
-  \macro{MSGMNB}.
+  stesso vale per \var{msg\_qbytes}, ma l'amministratore ha la facoltà di
+  incrementarne il valore a limiti superiori a \macro{MSGMNB}.
 \end{basedescript}
 
 
@@ -1413,22 +1413,31 @@ La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; il
 messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso
 l'argomento \param{msgp}.  Quest'ultimo deve venire passato sempre in una
 forma che corrisponda alla struttura \var{msgbuf} riportata in
-\figref{fig:ipc_msbug}.  La struttura è solo un modello, la sola cosa che
-conta è abbia come primo membro un campo \var{mtype}, come nell'esempio; esso
-infatti serve ad identificare il tipo di messaggio e deve essere sempre
-specificato come intero positivo.  Il campo \var{mtext} invece può essere di
-qualsiasi tipo e dimensione, e deve contenere il testo del messaggio.
-
-In generale pertanto occorrerà ridefinire una struttura analoga a quella di
-\figref{fig:ipc_msbug}, adattando alle proprie esigenze il campo \var{mtype},
-e avendo cura di mantenere come primo campo un valore di tipo \ctyp{long}. Il
-resto della struttura andrà a costituire il corpo del messaggio, la cui
-dimensione deve essere specificata sempre attraverso \param{msgsz}. Si tenga
-presente che la lunghezza che deve essere indicata in questo argomento è solo
-quella del messaggio, non di tutta la struttura, se cioè \var{message} è la
-struttura che si passa alla funzione, \param{msgsz} dovrà essere uguale a
-\code{sizeof(message)-sizeof(long)} (se consideriamo il caso dell'esempio in
-\figref{fig:ipc_msbug} \param{msgsz} dovrà essere pari a \macro{LENGHT}).
+\figref{fig:ipc_msbug}.  La dimensione massima per il testo di un messaggio
+non può comunque superare il limite \macro{MSGMAX}.
+
+La struttura di \figref{fig:ipc_msbug} comunque è solo un modello, tanto che
+la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo
+campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
+La sola cosa che conta è che abbia come primo membro un campo \var{mtype},
+come nell'esempio; esso infatti serve ad identificare il tipo di messaggio e
+deve essere sempre specificato come intero positivo.  Il campo \var{mtext}
+invece può essere di qualsiasi tipo e dimensione, e deve contenere il testo
+del messaggio.
+
+In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
+ridefinire una struttura simile a quella di \figref{fig:ipc_msbug}, adattando
+alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
+corpo del messaggio, anche con più campi o con strutture più complesse) avendo
+però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
+indica il tipo.
+
+Si tenga presente che la lunghezza che deve essere indicata in questo
+argomento è solo quella del messaggio, non quella di tutta la struttura, se
+cioè \var{message} è una propria struttura che si passa alla funzione,
+\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
+consideriamo il caso dell'esempio in \figref{fig:ipc_msbug}, \param{msgsz}
+dovrà essere pari a \macro{LENGHT}).
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1512,46 +1521,51 @@ rimosso dalla stessa) 
 }
 \end{functions}
 
-La funzione permette di estrarre un messaggio dalla coda e di scriverlo nel
-buffer indicato da \param{msgp}, che deve puntare ad una struttura della forma
-mostrata in \figref{fig:ipc_msbug}. L'argomento \param{msgsz} indica la
-lunghezza massima del testo del messaggio (equivalente al valore del parametro
-\macro{LENGHT} nell'esempio di \figref{fig:ipc_msbug}). 
+La funzione legge un messaggio dalla coda specificata scrivendolo nel buffer
+indicato da \param{msgp}, che avrà un formato analogo a quello di
+\figref{fig:ipc_msbug}. L'argomento \param{msgsz} indica la lunghezza massima
+del testo del messaggio (equivalente al valore del parametro \macro{LENGHT}
+nell'esempio di \figref{fig:ipc_msbug}).
 
 Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
-rimosso dalla coda, in caso contrario se \param{msgflg} è impostato a
-\macro{MSG\_NOERROR} il messaggio viene troncato e la parte in eccesso viene
+rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
+\macro{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
 perduta, altrimenti il messaggio non viene estratto e la funzione ritorna con
 un errore di \macro{E2BIG}.
 
 L'argomento \param{msgtyp} permette di restringere la ricerca ad un
-sottoinsieme dei messaggi presenti sulla coda; in particolare:
+sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
+una scansione della struttura mostrata in \figref{fig:ipc_mq_schema},
+restituendo il primo messaggio incontrato che corrisponde ai criteri
+specificati (che quindi, visto che i messaggi vengono sempre inseriti dalla
+coda, è quello meno recente); in particolare:
 \begin{itemize}
 \item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
   quello fra i presenti che è stato inserito inserito per primo. 
 \item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
-  tipo (il valore del campo \var{mtype}) corrisponde a quanto specificato.
-\item se \param{msgtyp} è negativo viene estratto il primo messaggio nella coda
-  con il tipo più basso, fra quelli di tipo inferiore al valore assoluto di
-  quanto specificato.
+  tipo (il valore del campo \var{mtype}) corrisponde al valore di
+  \param{msgtyp}.
+\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
+  il tipo di valore più basso, fra tutti quelli con un tipo inferiore al
+  valore assoluto di \param{msgtyp}.
 \end{itemize}
 
 Il valore di \param{msgflg} permette di controllare il comportamento della
-funzione, esso può assumere valore nullo o essere specificato come maschera
-binaria di uno o più dei valori. Oltre al precedente \macro{MSG\_NOERROR}, si
-può impostare il valore \macro{MSG\_EXCEPT}, che quando \param{msgtyp} è
-positivo permette di leggere il primo messaggio nella coda con tipo diverso da
-\param{msgtyp}, ed il valore \macro{IPC\_NOWAIT} che causa il ritorno
-immediato della funzione quando non ci sono messaggi sulla coda.
-
-Il comportamento usuale della funzione infatti, quando non ci sono messaggi
+funzione, esso può essere nullo o una maschera binaria composta da uno o più
+valori.  Oltre al precedente \macro{MSG\_NOERROR}, sono possibili altri due
+valori: \macro{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
+di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e
+\macro{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non
+ci sono messaggi sulla coda.
+
+Il comportamento usuale della funzione infatti, se non ci sono messaggi
 disponibili per la lettura, è di bloccare il processo in stato di
-\textit{sleep}; nel caso però si sia specificato \macro{IPC\_NOWAIT} la
+\textit{sleep}. Nel caso però si sia specificato \macro{IPC\_NOWAIT} la
 funzione ritorna immediatamente con un errore \macro{ENOMSG}. Altrimenti la
 funzione ritorna normalmente non appena viene inserito un messaggio del tipo
-desiderato, oppure ritorna con errore qualora la cosa sia rimossa (con un
-\macro{EIDRM}) o se il processo viene interrotto da un segnale (con un
-\macro{EINTR}).
+desiderato, oppure ritorna con errore qualora la coda sia rimossa (con
+\var{errno} settata a \macro{EIDRM}) o se il processo viene interrotto da un
+segnale (con \var{errno} settata a \macro{EINTR}).
 
 Una volta completata con successo l'estrazione del messaggio dalla coda, la
 funzione aggiorna i dati mantenuti in \var{msqid\_ds}, in particolare vengono
@@ -1563,6 +1577,10 @@ modificati:
 \item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente.
 \end{itemize}
 
+Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
+server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
+useremo una coda di messaggi, usando il \acr{pid} del client come valore per
+il tipo di messaggio, per restituire indietro le frasi ai client.
 
 
 
@@ -1621,7 +1639,6 @@ struct semid_ds
     time_t sem_ctime;                   /* last time changed by semctl() */
     unsigned long int sem_nsems;        /* number of semaphores in set */
 };
-
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
@@ -1630,6 +1647,24 @@ struct semid_ds
   \label{fig:ipc_semid_sd}
 \end{figure}
 
+\begin{table}[htb]
+  \footnotesize
+  \centering
+  \begin{tabular}[c]{|c|r|l|l|}
+    \hline
+    \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{SEMMNI}&   16& Numero massimo di insiemi di semafori. \\
+    \macro{SEMMAX}& 8192& .\\
+    \macro{SEMMNB}&16384& .\\
+    \hline
+  \end{tabular}
+  \caption{Valori delle costanti associate ai limiti degli insiemi di
+    semafori.} 
+  \label{tab:ipc_sem_limits}
+\end{table}
+
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_sysv_shm}
diff --git a/sources/MQFortuneServer.c b/sources/MQFortuneServer.c
new file mode 100644 (file)
index 0000000..e131978
--- /dev/null
@@ -0,0 +1,147 @@
+/* MQFortuneServer.c
+ * 
+ * Copyright (C) 2002 Simone Piccardi
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program fortuned 
+ * Fortune server - Using Messag queues
+ *
+ * Author: Simone Piccardi
+ * Aug. 2002
+ *
+ * Usage: fortuned -h give all info
+ *
+ * $Id: MQFortuneServer.c,v 1.1 2002/08/26 21:11:49 piccardi Exp $
+ *
+ ****************************************************************/
+/* 
+ * Include needed headers
+ */
+#include <sys/types.h>   /* predefined types */
+#include <sys/stat.h>    /*  */
+#include <unistd.h>      /* include unix standard library */
+#include <stdio.h>       /* include standard I/O library */
+#include <stdlib.h>     /* standard library */
+#include <string.h>     /* ANSI C standard string */
+#include <errno.h>      /* errorstring */
+#include <signal.h>     /* signals */
+#include <fcntl.h>      /*  */
+
+#include "macros.h"
+#include "wrappers.h"
+
+/* Subroutines declaration */
+void usage(void);
+void HandSIGTERM(int signo);
+int FortuneParse(char *file, char **fortune, int n);
+
+/* name of well known fifo */
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+    int i, n = 0;
+    char **fortune;
+    struct msgbuf_read {
+       long mtype;      /* message type, must be > 0 */
+       int pid;         /* message data */
+    } msg_read;
+    struct msgbuf_write {
+       long mtype;      /* message type, must be > 0 */
+       char mtext[MSGMAX];  /* message data */
+    } msg_write;
+    int msgid;
+    key_t key;
+    int size;
+    /*
+     * Input section: decode parameters passed in the calling 
+     * Use getopt function
+     */
+    opterr = 0;                                     /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hn:f:")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(0);
+           break;
+       case 'f':
+           fortunefilename = optarg;
+           break;
+       case 'n':
+           n = strtol(optarg, NULL, 10);
+           fortune = (char **) calloc(sizeof(*fortune), n);
+           break;
+       case '?':                                    /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+       default:                                       /* should not reached */
+           usage();
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    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 */
+    for (n=0; n<i; n++) debug("%s%%\n", fortune[n]);
+    /* 
+     * Comunication section 
+     */
+    key = ftok("./MQFortuneServer.c", 1); 
+    msgid = msgget(key, IPC_CREAT|666); 
+    
+    /* Main body: loop over requests */
+    while (1) {
+       msgrcv(msgid, &msg_read, 1, sizeof(int), MSG_NOERROR);
+       n = random() % i;                             /* select random value */
+       strncpy(msgbuf_write.mtext, fortune[n], MSGMAX);
+       size = min(strlen(fortune[n])+1, MSGMAX);  
+       msgsnd(msgid,  &msg_write, size, 0);
+    }
+    debug("Exiting for unknown reasons\n");
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+    printf("Elementary fortune server\n");
+    printf("Usage:\n");
+    printf("  fortuned [-h] [-f] -n XXX \n");
+    printf("  -h   print this help\n");
+    printf("  -f filename   set file for fortunes\n");
+    printf("  -n XXX        set pool depth\n");
+    exit(1);
+}
+/*
+ * Signal Handler to manage termination
+ */
+void HandSIGTERM(int signo) {
+    debug("Terminated by %s\n", strsignal(signo));
+    unlink(fifoname);
+    exit(0);
+}