\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}.
connessione con un server TCP, il prototipo della funzione è il seguente:
\begin{prototype}{sys/socket.h}
-{int connect(int sockfd, const struct sockaddr *serv\_addr, socklen\_t addrlen)}
+{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
protocollo TCP.
-
\subsection{La funzione \texttt{accept}}
\label{sec:TCPel_func_accept}
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 completa relativa al socket
- \texttt{sockfd} in attesa sulla coda delle connessioni complete che associa
- 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.
+{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}
\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}
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 rientro della
+cui indirizzo è passato come parametro in \texttt{cliaddr}, al ritorno della
funzione \texttt{addrlen} conterrà il numero di bytes scritti dentro
-\texttt{cliaddr}.
-
-Se la funzione ha successo restituisce un nuovo socket descriptor, detto
-\textit{connected socket}, su cui è agganciata la connessione che il client
-TCP ha effettuato verso il socket \texttt{sockfd}. Quest'ultimo, che viene
-chiamato invece \textit{listening socket}, deve essere stato creato in
-precedenza e messo in ascolto con \texttt{listen}, e non viene toccato dalla
-funzione.
-
-Questa distinzione è essenziale per capire
+\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}
-\section{Una semplice implementazione del servizio \texttt{echo} su TCP}
-\label{sec:TCPel_echo_example}
-Veniamo ora ad una applicazione