Aggiunta versione concorrente del server daytime. Iniziata la relativa
[gapil.git] / elemtcp.tex
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}