Aggiunta versione concorrente del server daytime. Iniziata la relativa
authorSimone Piccardi <piccardi@gnulinux.it>
Sat, 19 May 2001 20:47:03 +0000 (20:47 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sat, 19 May 2001 20:47:03 +0000 (20:47 +0000)
spiegazione.

elemtcp.tex
main.tex
sources/ElemDaytimeTCPCuncServ.c [new file with mode: 0644]
sources/SimpleDaytimeTCPServer.c

index fcb3b32ec8c98f279bb6acf51b05cb0974e90931..fd2d34a23c1951015357132c800a1c5a9e230356 100644 (file)
@@ -876,7 +876,7 @@ Storicamente il valore del parametro \texttt{backlog} era corrispondente al
 massimo valore della somma del numero di entrate possibili per ciascuna di
 dette code. Stevens riporta che BSD ha sempre applicato un fattore di 1.5 al
 valore, e provvede una tabella con i risultati ottenuti con vari kernel,
-compreso linux 2.0, che mostrano le differenze fra diverse implementazioni.
+compreso linux 2.0, che mostrano le differenze fra diverse implementazioni. 
 
 Ma in linux il significato di questo valore è cambiato a partire dal kernel
 2.2 per prevenire l'attacco chiamato \texttt{syn flood}. Questo si basa
@@ -893,7 +893,9 @@ la \texttt{sysctl} o scrivendola direttamente in
 \texttt{/proc/sys/net/ipv4/tcp\_max\_syn\_backlog}. Quando si attiva la
 protezione dei syncookies però (con l'opzione da compilare nel kernel e da
 attivare usando \texttt{/proc/sys/net/ipv4/tcp\_syncookies}) questo valore
-viene ignorato e non esiste più un valore massimo.
+viene ignorato e non esiste più un valore massimo.  In ogni caso in linux il
+valore di \texttt{backlog} viene troncato ad un massimo di \texttt{SOMAXCONN}
+se è superiore a detta constante (che di default vale 128).
 
 La scelta storica per il valore di questo parametro è di 5, e alcuni vecchi
 kernel non supportavano neanche valori superiori, ma la situazione corrente è
@@ -904,11 +906,11 @@ conviene specificare questo valore con una costante (il cui cambiamento
 richiederebbe la ricompilazione del server) ma usare piuttosto una variabile
 di ambiente (vedi \secref{sec:xxx_env_var}).  Lo Stevens tratta accuratamente
 questo argomento, con esempi presi da casi reali su web server, ed in
-particolare evidenzia come non sia più vero che la ragione della coda è quella
-di gestire il caso in cui il server è occupato fra chiamate successive alla
-\texttt{accept} (per cui la coda più occupata sarebbe quella delle connessioni
-compeltate), ma è invece necessaria a gestire la presenza di un gran numero di
-SYN in attesa di completare il three-way handshake.
+particolare evidenzia come non sia più vero che il compito principale della
+coda sia quello di gestire il caso in cui il server è occupato fra chiamate
+successive alla \texttt{accept} (per cui la coda più occupata sarebbe quella
+delle connessioni compeltate), ma piuttosto quello di gestire la presenza di
+un gran numero di SYN in attesa di completare il three-way handshake.
 
 Come accennato nel caso del TCP se un SYN arriva con tutte le code piene, il
 pacchetto sarà ignorato. Questo viene fatto perché la condizione delle code
@@ -981,7 +983,7 @@ E da chiarire che linux presenta un comportamento diverso nella gestione degli
 errori rispetto ad altre implementazioni dei socket BSD, infatti la funzione
 \texttt{accept} passa gli errori di rete pendenti sul nuovo socket come codici
 di errore per \texttt{accept}. Inoltre la funzione non fa ereditare ai nuovi
-socket flag come \texttt{O_NONBLOCK}, che devono essere rispecificati volta
+socket flag come \texttt{O\_NONBLOCK}, che devono essere rispecificati volta
 volta, questo è un comportamento diverso rispetto a quanto accade con BSD e
 deve essere tenuto in conto per scrivere programmi portabili.
 
@@ -1021,4 +1023,87 @@ creato da \texttt{accept} viene chiuso dopo l'invio dei dati.
 \section{Un server concorrente su TCP}
 \label{sec:TCPel_cunc_serv}
 
+Il server \texttt{daytime} dell'esempio in \secref{sec:net_cli_sample} è un
+tipico esempio di server iterativo, in cui viene servita una richiesta alla
+volta; in generale però, specie se il servizio è più complesso e comporta uno
+scambio di dati più sostanzioso di quello in questione, non è opportuno
+bloccare un server nel servizio di un client per volta; per questo si ricorre
+alle capacità di multitasking del sistema.
+
+Il modo più immediato per creare un server concorrente è allora quello di
+usare la funzione \texttt{fork} per far creare al server per ogni richiesta da
+parte di un client un processo figlio che si incarichi della gestione della
+comunicazione.
+
+Per illustrare questo meccanismo abbiamo allora riscritto il server
+\texttt{daytime} in forma concorrente, inserendo anche una opzione per la
+stampa degli indirizzi delle connessioni ricevute.
+
+In \nfig\ è mostrato un estratto del codice, in cui si sono tralasciate il
+trattamento delle opzioni e le parti rimaste invariate rispetto al precedente
+esempio. Al solito il sorgente completo del server
+\texttt{ElemDaytimeTCPCuncServ.c} è allegato nella directory dei sorgenti.
+
+\begin{figure}[!htb]
+  \footnotesize
+  \begin{lstlisting}{}
+#include <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>       /* include standard I/O library */
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+    int list_fd, conn_fd;
+    int i;
+    struct sockaddr_in serv_add, client;
+    char buffer[MAXLINE];
+    socklen_t len;
+    time_t timeval;
+    pid_t pid;
+    int logging=0;
+     ...
+    /* write daytime to client */
+    while (1) {
+        if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len)) 
+             <0 ) {
+            perror("accept error");
+            exit(-1);
+        }
+        /* fork to handle connection */
+        if ( (pid = fork()) < 0 ){
+            perror("fork error");
+            exit(-1);
+        }
+        if (pid == 0) {                 /* child */
+            close(list_fd);
+            timeval = time(NULL);
+            snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+            if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+                perror("write error");
+                exit(-1);
+            }
+            if (logging) {
+                inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+                printf("Request from host %s, port %d\n", buffer,
+                       ntohs(client.sin_port));
+            }
+            close(conn_fd);
+            exit(0);
+        } else {                        /* parent */
+            close(conn_fd);
+        }
+    }
+    /* normal exit, never reached */
+    exit(0);
+}
+  \end{lstlisting}
+  \caption{Esempio di codice di un server concorrente elementare per il 
+    servizio daytime.}
+  \label{fig:net_cli_code}
+\end{figure}
+
+Come si può vedere (\texttt{\small 21--25}) alla funzione \texttt{accept} 
 
index 097db57d8bb106682ad1e1f5e5fb69122ecc901a..55daeecf08ff81459e2212cf36a3b4345b6086da 100644 (file)
--- a/main.tex
+++ b/main.tex
@@ -1,4 +1,4 @@
-%% 
+%%
 %% GaPiL : Guida alla Programmazione in Linux
 %% 
 %% S. Piccardi Feb. 2001
@@ -21,7 +21,7 @@
 \usepackage{color} 
 %
 % Setting page layout
-% 
+%
 \oddsidemargin=0.5cm
 \evensidemargin=-0.5cm
 \textwidth=16cm
diff --git a/sources/ElemDaytimeTCPCuncServ.c b/sources/ElemDaytimeTCPCuncServ.c
new file mode 100644 (file)
index 0000000..e6e9c49
--- /dev/null
@@ -0,0 +1,141 @@
+/****************************************************************
+ *
+ * Program ElemDaytimeTCPCuncServ.c 
+ * Elementary TCP cuncurrent server for daytime service (port 13)
+ *
+ * Author: Simone Piccardi
+ * May. 2001
+ *
+ * Usage: daytimed
+ *
+ * $Id: ElemDaytimeTCPCuncServ.c,v 1.1 2001/05/19 20:47:03 piccardi Exp $ 
+ *
+ ****************************************************************/
+/* 
+ * Include needed headers
+ */
+#include <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>      /* include standard I/O library */
+#include <time.h>
+
+#define MAXLINE 80
+#define BACKLOG 10
+/* Program begin */
+void usage(void);
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    int i;
+    struct sockaddr_in serv_add, client;
+    char buffer[MAXLINE];
+    socklen_t len;
+    time_t timeval;
+    pid_t pid;
+    int logging=0;
+    /*
+     * Input section: decode parameters passed in the calling 
+     * Use getopt function
+     */
+    opterr = 0;         /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hv")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(0);
+           break;
+       case '?':   /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+           return(0);
+           break;
+       case 'v':
+           logging = 1;
+           break;
+       default:    /* should not reached */
+           usage();
+           return(0);
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    /* create socket */
+    if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+       perror("Socket creation error");
+       exit(-1);
+    }
+    /* initialize address */
+    memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+    serv_add.sin_family = AF_INET;                  /* address type is INET */
+    serv_add.sin_port = htons(13);                  /* daytime port is 13 */
+    serv_add.sin_addr.s_addr = htonl(INADDR_ANY);   /* connect from anywhere */
+    /* bind socket */
+    if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+       perror("bind error");
+       exit(-1);
+    }
+    /* listen on socket */
+    if (listen(list_fd, BACKLOG) < 0 ) {
+       perror("listen error");
+       exit(-1);
+    }
+    /* write daytime to client */
+    while (1) {
+       if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len)) 
+            <0 ) {
+           perror("accept error");
+           exit(-1);
+       }
+       /* fork to handle connection */
+       if ( (pid = fork()) < 0 ){
+           perror("fork error");
+           exit(-1);
+       }
+       if (pid == 0) {                 /* child */
+           close(list_fd);
+           timeval = time(NULL);
+           snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+           if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+               perror("write error");
+               exit(-1);
+           }
+           if (logging) {
+               inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+               printf("Request from host %s, port %d\n", buffer,
+                      ntohs(client.sin_port));
+           }
+           close(conn_fd);
+           exit(0);
+       } else {                        /* parent */
+           close(conn_fd);
+       }
+    }
+    /* normal exit, never reached */
+    exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+    printf("Simple daytime server\n");
+    printf("Usage:\n");
+    printf("  daytimed [-hv] \n");
+    printf("  -h          print this help\n");
+    printf("  -v          print request source on stdout\n");
+    exit(1);
+}
+
index fdf99ec7ed944821a2d49e712b50832c5c6aeda4..9f6b9be36a4a79059be1896967af279b293e736d 100644 (file)
@@ -1,14 +1,14 @@
 /****************************************************************
  *
  * Program daytime_tcp_server.c: 
- * Simple TCP server for daytime service (port 13)
+ * Elementary TCP server for daytime service (port 13)
  *
  * Author: Simone Piccardi
  * Apr. 2001
  *
  * Usage: daytimed
  *
- * $Id: SimpleDaytimeTCPServer.c,v 1.1 2001/04/04 23:09:57 piccardi Exp $ 
+ * $Id: SimpleDaytimeTCPServer.c,v 1.2 2001/05/19 20:47:03 piccardi Exp $ 
  *
  ****************************************************************/
 /*