Aggiunta versione concorrente del server daytime. Iniziata la relativa
[gapil.git] / elemtcp.tex
index d3178839f56981b5b2cb2403be16ae75b37e9d97..fd2d34a23c1951015357132c800a1c5a9e230356 100644 (file)
@@ -1,27 +1,28 @@
 \chapter{Socket TCP elementari}
 \label{cha:elem_TCP_sock}
 
-In questo capitolo inizieremo ad approndire la conoscenza dei socket TCP,
+In questo capitolo iniziamo ad approndire la conoscenza dei socket TCP,
 tratteremo qui dunque il funzionamento delle varie funzioni che si sono usate
 nei due esempi elementari forniti in precedenza (vedi
 \secref{sec:net_cli_sample} e \secref{sec:net_serv_sample}), previa una
 descrizione delle principali caratteristiche del funzionamento di una
 connessione TCP.
 
-La seconda parte del capitolo sarà poi dedicata alla scrittura di una prima
-semplice applicazione client/server completa, che implementi il servizio
-standard \texttt{echo} su TCP.
+Infine riscriveremo il precedente esempio elementare di server
+\texttt{daytime} in una forma appena più evoluta (come server concorrente) e
+con alcune caratteristiche aggiuntive che mettano in luce quanto andremo ad
+illustrare.
 
 \section{Il funzionamento di una connessione TCP}
 \label{sec:TCPel_connession}
 
 Prima di entrare nei dettagli delle funzioni usate nelle applicazioni che
 utilizzano i socket TCP, è fondamentale spiegare alcune basi del funzionamento
-del TCP, la conoscenza del funzionamento del protocollo è infatti essenziale
+del TCP; la conoscenza del funzionamento del protocollo è infatti essenziale
 per capire il modello di programmazione ed il funzionamento delle API.
 
-In particolare ci concentreremo sulle modalità con le quali il protocollo da
-inizio e conclude una connessione; faremo anche un breve accenno al
+In particolare ci concentreremo sulle modalità con le quali il protocollo dà
+inizio e conclude una connessione; faremo inoltre anche un breve accenno al
 significato di alcuni dei vari stati che il protocollo assume durante la vita
 di una connessione, che possono essere osservati per ciascun socket attivo con
 l'uso del programma \texttt{netstat}.
@@ -35,7 +36,7 @@ verifica utilizzando il codice dei due precedenti esempi elementari
 \figref{fig:net_cli_code} e \figref{fig:net_serv_code}) che porta alla
 creazione di una connessione è la seguente:
  
-\begin{itemize}
+\begin{enumerate}
 \item Il server deve essere preparato per accettare le connessioni in arrivo;
   il procedimento si chiama \textsl{apertura passiva} del socket (in inglese
   \textit{passive open}); questo viene fatto chiamando la sequenza di funzioni
@@ -71,7 +72,7 @@ creazione di una connessione 
   \texttt{SYN} del server inviando un \texttt{ACK}. Alla ricezione di
   quest'ultimo la funzione \texttt{accept} del server ritorna e la connessione
   è stabilita.
-\end{itemize} 
+\end{enumerate} 
 
 Il procedimento viene chiamato \textit{three way handshake} dato che per
 realizzarlo devono essere scambiati tre segmenti.  In \nfig\ si è
@@ -186,7 +187,7 @@ seguente:
 \item Dopo un certo tempo anche il secondo processo chiamerà la funzione
   \texttt{close} sul proprio socket, causando l'emissione di un altro segmento
   FIN. 
-  
+
 \item L'altro capo della connessione riceverà il FIN conclusivo e risponderà
   con un ACK.
 \end{enumerate}
@@ -248,21 +249,21 @@ riferimento resta (FIXME citare lo Stevens); qui ci limiteremo a descrivere
 brevemente un semplice esempio di connessione e le transizioni che avvengono
 nei due casi appena citati (creazione e terminazione della connessione).
 
-In assenza di connessione lo stato del TCP è \textsl{CLOSED}; quando una
+In assenza di connessione lo stato del TCP è \texttt{CLOSED}; quando una
 applicazione esegue una apertura attiva il TCP emette un SYN e lo stato
-diventa \textsl{SYN\_SENT}; quando il TCP riceve la risposta del SYN$+$ACK
-emette un ACK e passa allo stato \textsl{ESTABLISHED}; questo è lo stato
+diventa \texttt{SYN\_SENT}; quando il TCP riceve la risposta del SYN$+$ACK
+emette un ACK e passa allo stato \texttt{ESTABLISHED}; questo è lo stato
 finale in cui avviene la gran parte del trasferimento dei dati.
 
 Dal lato server in genere invece il passaggio che si opera con l'apertura
-passiva è quello di portare il socket dallo stato \textsl{CLOSED} allo
-stato \textsl{LISTEN} in cui vengono accettate le connessioni.
+passiva è quello di portare il socket dallo stato \texttt{CLOSED} allo
+stato \texttt{LISTEN} in cui vengono accettate le connessioni.
 
-Dallo stato \textsl{ESTABLISHED} si può uscire in due modi; se un'applicazione
+Dallo stato \texttt{ESTABLISHED} si può uscire in due modi; se un'applicazione
 chiama la \texttt{close} prima di aver ricevuto un end of file (chiusura
-attiva) la transizione è verso lo stato \textsl{FIN\_WAIT\_1}; se invece
-l'applicazione riceve un FIN nello stato \textsl{ESTABLISHED} (chiusura
-passiva) la transizione è verso lo stato \textsl{CLOSE\_WAIT}.
+attiva) la transizione è verso lo stato \texttt{FIN\_WAIT\_1}; se invece
+l'applicazione riceve un FIN nello stato \texttt{ESTABLISHED} (chiusura
+passiva) la transizione è verso lo stato \texttt{CLOSE\_WAIT}.
 
 In \nfig\ è riportato lo schema dello scambio dei pacchetti che avviene per
 una un esempio di connessione, insieme ai vari stati che il protocollo viene
@@ -292,7 +293,7 @@ risposta.
 Infine si ha lo scambio dei quattro segmenti che terminano la connessione
 secondo quanto visto in \secref{sec:TCPel_conn_term}; si noti che il capo della
 connessione che esegue la chiusura attiva entra nello stato
-\textsl{TIME\_WAIT} su cui torneremo fra poco.
+\texttt{TIME\_WAIT} su cui torneremo fra poco.
 
 È da notare come per effettuare uno scambio di due pacchetti (uno di richiesta
 e uno di risposta) il TCP necessiti di ulteriori otto segmenti, se invece si
@@ -339,16 +340,16 @@ pi
 
 Ogni implementazione del TCP deve scegliere un valore per la MSL (l'RFC1122
 raccomanda 2 minuti, linux usa 30 secondi), questo comporta una durata dello
-stato \textsl{TIME\_WAIT} che a seconda delle implementazioni può variare fra
+stato \texttt{TIME\_WAIT} che a seconda delle implementazioni può variare fra
 1 a 4 minuti.
 
 Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due motivi
 principali:
-\begin{itemize}
+\begin{enumerate}
 \item implementare in maniera affidabile la terminazione della connessione
   in entrambe le direzioni.
 \item consentire l'eliminazione dei segmenti duplicati dalla rete. 
-\end{itemize}
+\end{enumerate}
 
 Il punto è che entrambe le ragioni sono importanti, anche se spesso si fa
 riferimento solo alla prima; ma è solo se si tiene conto della seconda che si
@@ -634,11 +635,10 @@ cio
 server per specificare la porta (e gli eventuali indirizzi locali) su cui poi
 ci si porrà in ascolto.
 
-Il prototipo della funzione, definito in \texttt{sys/socket.h}, è il seguente:
+Il prototipo della funzione è il seguente:
 
-\begin{itemize}
-\item \texttt{int bind(int sockfd, const struct sockaddr *serv\_addr,
-    socklen\_t addrlen) }
+\begin{prototype}{sys/socket.h}
+{int bind(int sockfd, const struct sockaddr *serv\_addr, socklen\_t addrlen)}
   
   Il primo argomento è un file descriptor ottenuto da una precedente chiamata
   a \texttt{socket}, mentre il secondo e terzo argomento sono rispettivamente
@@ -648,15 +648,14 @@ Il prototipo della funzione, definito in \texttt{sys/socket.h}, 
   La funzione restituisce zero in caso di successo e -1 per un errore, in caso
   di errore. La variabile \texttt{errno} viene settata secondo i seguenti
   codici di errore:
-  \begin{itemize}
+  \begin{errlist}
   \item \texttt{EBADF} Il file descriptor non è valido.
   \item \texttt{EINVAL} Il socket ha già un indirizzo assegnato.
   \item \texttt{ENOTSOCK} Il file descriptor non è associato ad un socket.
   \item \texttt{EACCESS} Si è cercato di usare un indirizzo riservato senza
     essere root. 
-  \end{itemize}
-
-\end{itemize}
+  \end{errlist}
+\end{prototype}
 
 Con il TCP la chiamata \texttt{bind} permette di specificare l'indirizzo, la
 porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
@@ -715,12 +714,10 @@ di effettuare una assegnazione del tipo:
 \label{sec:TCPel_func_connect}
 
 La funzione \texttt{connect} è usata da un client TCP per stabilire la
-connessione con un server TCP, il prototipo della funzione, definito in
-\texttt{sys/socket.h}, è il seguente:
+connessione con un server TCP, il prototipo della funzione è il seguente:
 
-\begin{itemize}
-\item \texttt{int connect(int sockfd, const struct sockaddr *serv\_addr,
-    socklen\_t addrlen) }
+\begin{prototype}{sys/socket.h}
+{int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t addrlen)}
   
   Il primo argomento è un file descriptor ottenuto da una precedente chiamata
   a \texttt{socket}, mentre il secondo e terzo argomento sono rispettivamente
@@ -730,7 +727,7 @@ connessione con un server TCP, il prototipo della funzione, definito in
   La funzione restituisce zero in caso di successo e -1 per un errore, in caso
   di errore. La variabile \texttt{errno} viene settata secondo i seguenti
   codici di errore:
-  \begin{itemize}
+  \begin{errlist}
   \item \texttt{EBADF} Il file descriptor non è valido.
   \item \texttt{EFAULT} L'indirizzo della struttura di indirizzi è al di fuori
     dello spazio di indirizzi dell'utente.
@@ -751,8 +748,8 @@ connessione con un server TCP, il prototipo della funzione, definito in
   \item \texttt{EACCESS, EPERM} Si è tentato di eseguire una connessione ad un
     indirizzo broacast senza che il socket fosse stato abilitato per il
     broadcast.
-  \end{itemize}
-\end{itemize}
+  \end{errlist}
+\end{prototype}
 
 La struttura dell'indirizzo deve essere inizializzata con l'indirizzo IP e il
 numero di porta del server a cui ci si vuole connettere, come mostrato
@@ -822,23 +819,291 @@ necessario effettuare una \texttt{bind}.
 La funzione \texttt{listen} è usata per usare un socket in modalità passiva,
 cioè, come dice il nome, per metterlo in ascolto di eventuali connessioni; in
 sostanza l'effetto della funzione è di portare il socket dallo stato
-\texttt{CLOSED} a quello \texttt{LISTEN}.
-
-\begin{prototype}{int listen(int sockfd, int backlog)}
+\texttt{CLOSED} a quello \texttt{LISTEN}. In genere si chiama la funzione in
+un server dopo le chiamate a \texttt{socket} e \texttt{bind} e prima della
+chiamata ad \texttt{accept}. Il prototipo della funzione come definito dalla
+man page è:
+
+\begin{prototype}{sys/socket.h}{int listen(int sockfd, int backlog)}
+  La funzione pone il socket specificato da \texttt{sockfd} in modalità
+  passiva e predispone una coda per le connessioni in arrivo di lunghezza pari
+  a \texttt{backlog}. La funzione si può applicare solo a socket di tipo
+  \texttt{SOCK\_STREAM} o \texttt{SOCK\_SEQPACKET}.
+
+  La funzione restituisce 0 in caso di successo e -1 in caso di errore. I
+  codici di errore restituiti in \texttt{errno} sono i seguenti:
   \begin{errlist}
   \item \texttt{EBADF} L'argomento \texttt{sockfd} non è un file descriptor
     valido.
   \item \texttt{ENOTSOCK} L'argomento \texttt{sockfd} non è un socket.
-  \item \texttt{EOPNOTSUPP} The socket is not of a type that supports the lis­
-    ten operation.
+  \item \texttt{EOPNOTSUPP} Il socket è di un tipo che non supporta questa
+    operazione.
   \end{errlist}
 \end{prototype}
 
 
+Il parametro \texttt{backlog} indica il numero massimo di connessioni pendenti
+accettate; se esso viene ecceduto il client riceverà una errore di tipo
+\texttt{ECONNREFUSED}, o se il protocollo, come nel caso del TCP, supporta la
+ritrasmissione, la richiesta sarà ignorata in modo che la connessione possa
+essere ritentata.
+
+Per capire meglio il significato di tutto ciò occorre approfondire la modalità
+con cui il kernel tratta le connessioni in arrivo. Per ogni socket in ascolto
+infatti vengono mantenute due code:
+\begin{enumerate}
+\item Una coda delle connessioni incomplete (\textit{incomplete connection
+    queue} che contiene una entrata per ciascun SYN arrivato per il quale si
+  sta attendendo la conclusione del three-way handshake. Questi socket sono
+  tutti nello stato \texttt{SYN\_RECV}.
+\item Una coda delle connessioni complete (\textit{complete connection queue}
+  che contiene una entrata per ciascuna connessione per le quali il three-way
+  handshake è stato completato ma ancora \texttt{accept} non è ritornata.
+\end{enumerate}
+
+Lo schema di funzionamento è descritto in \nfig, quando arriva un SYN da un
+client il server crea una nuova entrata nella coda delle connessioni
+incomplete, e poi risponde con il SYN$+$ACK. La entrata resterà nella coda
+delle connessioni incomplete fino al ricevimento dell'ACK dal client o fino ad
+un timeout. Nel caso di completamento del three-way handshake l'entrata viene
+sostata nella coda delle connessioni complete. Quando il processo chiama la
+funzione \texttt{accept} (vedi \secref{sec:TCPel_func_accept}) la prima
+entrata nella coda delle connessioni complete è passata al programma, o, se la
+coda è vuota, il processo viene posto in attesa e risvegliato all'arrivo della
+prima connessione completa.
+
+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. 
+
+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
+sull'emissione da parte dell'attaccante di un grande numero di pacchetti SYN
+indirizzati verso una porta forgiati con indirizzo IP fasullo \footnote{con la
+  tecnica che viene detta \textit{ip spoofing}} così che i SYN$+$ACK vanno
+perduti la coda delle connessioni incomplete viene saturata, impedendo di
+fatto le connessioni.
+
+Per ovviare a questo il significato del \texttt{backlog} è stato cambiato a
+significare la lunghezza della coda delle connessioni complete. La lunghezza
+della coda delle connessioni incomplete può essere ancora controllata usando
+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.  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 è
+molto cambiata dagli anni '80 e con server web che possono sopportare diversi
+milioni di connessioni al giorno un tale valore non è più adeguato. Non esiste
+comunque una risposta univoca per la scelta del valore, per questo non
+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 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
+piene è transitoria, e se il client ristrasmette il SYN è probabile che
+passato un po' di tempo possa trovare lo spazio per una nuova connessione. Se
+invece si rispondesse con un RST la \texttt{connect} del client ritornerebbe
+con una condizione di errore, mentre questo è il tipico caso in cui è si può
+lasciare la gestione della connessione alla ritrasmissione prevista dal
+protocollo TCP.
+
 
 \subsection{La funzione \texttt{accept}}
 \label{sec:TCPel_func_accept}
 
+La funzione \texttt{accept} è chiamata da un server TCP per gestire la
+connessione una volta che sia stato completato il three way handshake, la
+funzione restituisce un nuovo socket descriptor su cui si potrà operare per
+effettuare la comunicazione. Se non ci sono connessioni completate il processo
+viene messo in attesa. Il prototipo della funzione è il seguente:
+
+\begin{prototype}{sys/socket.h}
+{int listen(int sockfd, struct sockaddr *addr, socklen\_t *addrlen)} 
+  La funzione estrae la prima connessione relativa al socket \texttt{sockfd}
+  in attesa sulla coda delle connessioni complete, che associa ad nuovo socket
+  con le stesse caratteristiche di \texttt{sockfd} (restituito dalla funzione
+  stessa).  Il socket originale non viene toccato. Nella struttura
+  \texttt{addr} e nella variabile \texttt{addrlen} vengono restituiti
+  indirizzo e relativa lunghezza del client che si è connesso.
+  La funzione restituisce un numero di socket descriptor positivo in caso di
+  successo e -1 in caso di errore, nel qual caso la variabile \texttt{errno}
+  viene settata ai seguenti valori:
+
+  \begin{errlist}
+  \item \texttt{EBADF} L'argomento \texttt{sockfd} non è un file descriptor
+    valido.
+  \item \texttt{ENOTSOCK} L'argomento \texttt{sockfd} non è un socket.
+  \item \texttt{EOPNOTSUPP} Il socket è di un tipo che non supporta questa
+    operazione.    
+  \item \texttt{EAGAIN} or \item \texttt{EWOULDBLOCK} Il socket è stato
+    settato come non bloccante, e non ci sono connessioni in attesa di essere
+    accettate.              
+  \item \texttt{EFAULT} The addr parameter is not in a writable part of the
+    user address space.
+  \item \texttt{EPERM} Firewall rules forbid connection.
+    
+  \item \texttt{ENOBUFS, ENOMEM} Not enough free memory.  This often means
+    that the memory allocation is limited by the socket buffer limits, not by
+    the system memory.
+    Inoltre possono essere restituiti gli errori di rete relativi al nuovo
+    socket come: \texttt{EMFILE}, \texttt{EINVAL}, \texttt{ENOSR},
+    \texttt{ENOBUFS}, \texttt{EPERM}, \texttt{ECONNABORTED},
+    \texttt{ESOCKTNOSUPPORT}, \texttt{EPROTONOSUPPORT}, \texttt{ETIMEDOUT},
+    \texttt{ERESTARTSYS}.
+
+  \end{errlist}
+\end{prototype}
+
+La funzione può essere usata solo con socket che supportino la connessione
+(cioè di tipo \texttt{SOCK\_STREAM}, \texttt{SOCK\_SEQPACKET} o
+\texttt{SOCK\_RDM}). Per alcuni protocolli che richiedono una conferma
+esplicita della connessione, (attualmenente in linux solo DECnet ha questo
+comportamento), la funzione opera solo l'estrazione dalla coda delle
+connessioni, la conferma della connessione viene fatta implicitamente dalla
+prima chiamata ad una \texttt{read} o una \texttt{write} mentre il rifiuto
+della connessione viene fatta con la funzione \texttt{close}.
+
+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
+volta, questo è un comportamento diverso rispetto a quanto accade con BSD e
+deve essere tenuto in conto per scrivere programmi portabili.
+
+I due parametri \texttt{cliaddr} e \texttt{addrlen} (si noti che quest'ultimo
+è passato per indirizzo per avere indietro il valore) sono usati per ottenere
+l'indirizzo del client da cui proviene la connessione. Prima della chiamata
+\texttt{addrlen} deve essere inizializzato alle dimensioni della struttura il
+cui indirizzo è passato come parametro in \texttt{cliaddr}, al ritorno della
+funzione \texttt{addrlen} conterrà il numero di bytes scritti dentro
+\texttt{cliaddr}. Se questa informazione non interessa basterà inizializzare a
+\texttt{NULL} detti puntatori.
+
+Se la funzione ha successo restituisce il descrittore di un nuovo socket
+creato dal kernel (detto \textit{connected socket}) a cui viene associata la
+prima connessione completa (estratta dalla relativa coda, vedi
+\secref{sec:TCPel_func_listen}) che il client TCP ha effettuato verso il
+socket \texttt{sockfd}. Quest'ultimo (detto \textit{listening socket}) è
+quello creato all'inizio e messo in ascolto con \texttt{listen}, e non viene
+toccato dalla funzione.  
+
+Se non ci sono connessioni pendenti da accettare la funzione mette in attesa
+il processo\footnote{a meno che non si sia settato il socket per essere
+  non-bloccante, nel qual caso ritorna con l'errore \texttt{EAGAIN},
+  torneremo su questa modalità di operazione in \secref{sec:xxx_sock_noblock}}
+fintanto che non ne arriva una.
+Questo meccanismo è essenziale per capire il funzionamento di un server, in
+generale infatti c'è sempre un solo socket in ascolto, che resta per tutto il
+tempo nello stato \texttt{LISTEN}, mentre le connessioni vengono gestite dai
+nuovi socket ritornati da \texttt{accept} che sono posti automaticamente nello
+stato \texttt{ESTABLISHED} e utilizzati fino alla chiusura della connessione
+che avviene su di essi.  Si può riconoscere questo schema anche nell'esempio
+elementare in \figref{fig:net_serv_code} dove per ogni connessione il socket
+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} 
 
-\section{Una semplice implementazione del servizio \texttt{echo} su TCP}
-\label{sec:TCPel_echo_example}