Revisioni varie, e fatta la figura degli stati del TCP
authorSimone Piccardi <piccardi@gnulinux.it>
Sat, 26 Apr 2003 22:38:19 +0000 (22:38 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sat, 26 Apr 2003 22:38:19 +0000 (22:38 +0000)
elemtcp.tex
gapil.tex
netlayer.tex
network.tex
trasplayer.tex

index 0872bdba051fdf5c51f23739de7144d257bbc6f7..314a5388aeefa3742668cc7b71f65a76cb4d7970 100644 (file)
@@ -22,7 +22,7 @@ client, fornendo poi alcuni esempi di applicazione elementare.
 \section{Il funzionamento di una connessione TCP}
 \label{sec:TCP_connession}
 
-Prima di entrare nei dettagli delles singole funzioni usate nelle applicazioni
+Prima di entrare nei dettagli delle singole funzioni usate nelle applicazioni
 che utilizzano i socket TCP, è fondamentale spiegare alcune delle basi del
 funzionamento del protocollo, poiché questa conoscenza è essenziale per
 comprendere il comportamento di dette funzioni per questo tipo di socket, ed
@@ -48,7 +48,7 @@ Il processo che porta a creare una connessione TCP 
   serie di flag usati per gestire la connessione, come SYN, ACK, URG, FIN,
   alcuni di essi, come SYN (che sta per \textit{syncronize}) corrispondono a
   funzioni particolari del protocollo e danno il nome al segmento, (per
-  maggiori dettagli vedere \capref{cha:tcp_protocol}).}  di dati che vengono
+  maggiori dettagli vedere \secref{sec:tcp_protocol}).}  di dati che vengono
 scambiati) che porta alla creazione di una connessione è la seguente:
  
 \begin{enumerate}
@@ -133,7 +133,7 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni:
   connessione corrente. È possibile leggere e scrivere questo valore
   attraverso l'opzione del socket \const{TCP\_MAXSEG}.
   
-\item \textit{window scale option}, %come spiegato in \capref{cha:tcp_protocol}
+\item \textit{window scale option}, %come spiegato in \secref{sec:tcp_protocol}
   il protocollo TCP implementa il controllo di flusso attraverso una
   \textsl{finestra annunciata} (\textit{advertized window}) con la quale
   ciascun capo della comunicazione dichiara quanto spazio disponibile ha in
@@ -244,17 +244,17 @@ client, ci sono alcuni servizi, il principale dei quali 
 \subsection{Un esempio di connessione}
 \label{sec:TCP_conn_dia}
 
-Le operazioni del TCP nella creazione e conclusione di una connessione sono
-specificate attraverso il diagramma di transizione degli stati riportato in
-\figref{fig:TCP_conn_example}. TCP prevede l'esistenza di 11 diversi stati
-per un socket ed un insieme di regole per le transizioni da uno stato
-all'altro basate sullo stato corrente e sul tipo di segmento ricevuto; i nomi
-degli stati sono gli stessi che vengono riportati del comando \cmd{netstat}
-nel campo \textit{State}.
+Come abbiamo visto le operazioni del TCP nella creazione e conclusione di una
+connessione sono piuttosto complesse, ed abbiamo esaminato soltanto quelle
+relative ad un andamento normale.  In \secref{sec:TCP_states} vedremo con
+maggiori dettagli che una connessione può assumere vari stati, che ne
+caratterizzano il funzionamento, e che sono quelli che vengono riportati dal
+comando \cmd{netstat}, per ciascun socket TCP aperto, nel campo
+\textit{State}.
 
-Non possiamo affrontare una descrizione completa del funzionamento del
+Non possiamo affrontare qui una descrizione completa del funzionamento del
 protocollo; un approfondimento sugli aspetti principali si trova in
-\capref{cha:tcp_protocol}, ma per una trattazione esauriente il miglior
+\secref{sec:tcp_protocol}, ma per una trattazione completa il miglior
 riferimento resta \cite{TCPIll1}. 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).
@@ -904,7 +904,7 @@ della prima connessione completa.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=10cm]{img/tcp_listen_backlog}  
+  \includegraphics[width=11cm]{img/tcp_listen_backlog}  
   \caption{Schema di funzionamento delle code delle connessioni complete ed
     incomplete.}
   \label{fig:TCP_listen_backlog}
@@ -920,7 +920,7 @@ implementazioni.
 In Linux il significato di questo valore è cambiato a partire dal kernel 2.2
 per prevenire l'attacco chiamato \textit{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
+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 e la coda delle connessioni incomplete viene saturata, impedendo di
 fatto ulteriori connessioni.
@@ -937,14 +937,14 @@ ignorato e non esiste pi
 di \param{backlog} viene troncato ad un massimo di \const{SOMAXCONN} se è
 superiore a detta costante (che di default vale 128).
 
-La scelta storica per il valore di questo parametro è di 5, e alcuni vecchi
+La scelta storica per il valore di questo parametro era di 5, e alcuni vecchi
 kernel non supportavano neanche valori superiori, ma la situazione corrente è
 molto cambiata per via della presenza di server web che devono gestire un gran
 numero di connessioni per cui un tale valore non è più adeguato. Non esiste
 comunque una risposta univoca per la scelta del valore, per questo non
 conviene specificarlo con una costante (il cui cambiamento richiederebbe la
 ricompilazione del server) ma usare piuttosto una variabile di ambiente (vedi
-\secref{sec:proc_environ}).  
+\secref{sec:proc_environ}).
 
 Stevens tratta accuratamente questo argomento in \cite{UNP1}, con esempi presi
 da casi reali su web server, ed in particolare evidenzia come non sia più vero
@@ -1058,13 +1058,116 @@ devono scrivere programmi portabili.
 
 Il meccanismo di funzionamento di \func{accept} è 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 \func{accept}, che
+ascolto, detto per questo \textit{listening socket}, che resta per tutto il
+tempo nello stato \texttt{LISTEN}, mentre le connessioni vengono gestite dai
+nuovi socket, detti \textit{connected socket}, ritornati da \func{accept}, che
 si trovano automaticamente nello stato \texttt{ESTABLISHED}, e vengono
-utilizzati fino alla chiusura della connessione, che avviene su di essi.  Si
-può riconoscere questo schema anche nell'esempio elementare in
-\figref{fig:TCP_serv_code} dove per ogni connessione il socket creato da
-\func{accept} viene chiuso dopo l'invio dei dati.
+utilizzati per lo scambio dei dati, che avviene su di essi, fino alla chiusura
+della connessione.  Si può riconoscere questo schema anche nell'esempio
+elementare di \figref{fig:TCP_serv_code}, dove per ogni connessione il socket
+creato da \func{accept} viene chiuso dopo l'invio dei dati.
+
+
+\subsection{Le funzioni \func{getsockname} e \func{getpeername}}
+\label{sec:TCP_get_names}
+
+Oltre a tutte quelle viste finora, dedicate all'utilizzo dei socket, esistono
+alcune funzioni ausiliarie che possono essere usate per recuperare alcune
+informazioni relative ai socket ed alle connessioni ad essi associate. Le due
+funzioni più elementari sono queste, che vengono usate per ottenere i dati
+relativi alla socket pair associata ad un certo socket.
+
+La prima funzione è \funcd{getsockname} e serve ad ottenere l'indirizzo locale
+associato ad un socket; il suo prototipo è:
+\begin{prototype}{sys/socket.h}
+  {int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)}
+  Legge l'indirizzo locale di un socket.
+
+\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+  errore. I codici di errore restituiti in \var{errno} sono i seguenti:
+  \begin{errlist}
+  \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor
+    valido.
+  \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket.
+  \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per
+    eseguire l'operazione.
+  \item[\errcode{EFAULT}] l'indirizzo \param{name} non è valido.
+  \end{errlist}}
+\end{prototype}
+
+La funzione restituisce la struttura degli indirizzi del socket \param{sockfd}
+nella struttura indicata dal puntatore \param{name} la cui lunghezza è
+specificata tramite l'argomento \param{namlen}. Quest'ultimo viene passato
+come indirizzo per avere indietro anche il numero di byte effettivamente
+scritti nella struttura puntata da \param{name}. Si tenga presente che se si è
+utilizzato un buffer troppo piccolo per \param{name} l'indirizzo risulterà
+troncato.
+
+
+La funzione si usa tutte le volte che si vuole avere l'indirizzo locale di un
+socket; ad esempio può essere usata da un client (che usualmente non chiama
+\func{bind}) per ottenere numero IP e porta locale associati al socket
+restituito da una \func{connect}, o da un server che ha chiamato \func{bind}
+su un socket usando 0 come porta locale per ottenere il numero di porta
+effimera assegnato dal kernel.
+
+Inoltre quando un server esegue una \func{bind} su un indirizzo generico, se
+chiamata dopo il completamento di una connessione sul socket restituito da
+\func{accept}, restituisce l'indirizzo locale che il kernel ha assegnato a
+quella connessione.
+
+Tutte le volte che si vuole avere l'indirizzo remoto di un socket si usa la
+funzione \funcd{getpeername}, il cui prototipo è:
+\begin{prototype}{sys/socket.h}
+  {int getpeername(int sockfd, struct sockaddr * name, socklen\_t * namelen)}
+  Legge l'indirizzo remoto di un socket.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+    errore. I codici di errore restituiti in \var{errno} sono i seguenti:
+  \begin{errlist}
+  \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor
+    valido.
+  \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket.
+  \item[\errcode{ENOTCONN}] il socket non è connesso.
+  \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per
+    eseguire l'operazione.
+  \item[\errcode{EFAULT}] l'argomento \param{name} punta al di fuori dello
+    spazio di indirizzi del processo.
+  \end{errlist}}
+\end{prototype}
+
+La funzione è identica a \func{getsockname}, ed usa la stessa sintassi, ma
+restituisce l'indirizzo remoto del socket, cioè quello associato all'altro
+capo della connessione.  Ci si può chiedere a cosa serva questa funzione dato
+che dal lato client l'indirizzo remoto è sempre noto quando si esegue la
+\func{connect} mentre dal lato server si possono usare, come vedremo in
+\figref{fig:TCP_cunc_serv_code}, i valori di ritorno di \func{accept}.
+
+Il fatto è che in generale quest'ultimo caso non è sempre possibile.  In
+particolare questo avviene quando il server, invece di gestire la connessione
+direttamente in un processo figlio, come vedremo nell'esempio di server
+concorrente di \ref{sec:TCP_cunc_daytime}, lancia per ciascuna connessione un
+altro programma, usando \func{exec}.\footnote{questa ad esempio è la modalità
+  con cui opera il \textsl{super-server} \cmd{inetd}, che può gestire tutta
+  una serie di servizi diversi, eseguendo su ogni connessione ricevuta sulle
+  porte tenute sotto controllo, il relativo server.}
+
+In questo caso benché il processo figlio abbia una immagine della memoria che
+è copia di quella del processo padre (e contiene quindi anche la struttura
+ritornata da \func{accept}), all'esecuzione di \func{exec} verrà caricata in
+memoria l'immagine del programma eseguito, che a questo punto perde ogni
+riferimento ai valori tornati da \func{accept}.  Il socket descriptor però
+resta aperto, e se si è seguita una opportuna convenzione per rendere noto al
+programma eseguito qual'è il socket connesso, \footnote{ad esempio il solito
+  \cmd{inetd} fa sempre in modo che i file descriptor 0, 1 e 2 corrispondano
+  al socket connesso.} quest'ultimo potrà usare la funzione \func{getpeername}
+per determinare l'indirizzo remoto del client.
+
+Infine è da chiarire (si legga la pagina di manuale) che, come per
+\func{accept}, il terzo parametro, che è specificato dallo standard POSIX.1g
+come di tipo \code{socklen\_t *} in realtà deve sempre corrispondere ad un
+\ctyp{int *} come prima dello standard perché tutte le implementazioni dei
+socket BSD fanno questa assunzione.
 
 
 \subsection{La funzione \func{close}}
@@ -1123,7 +1226,7 @@ Infatti con i socket 
 possano restituire in input o scrivere in output un numero di byte minore di
 quello richiesto. Come già accennato in \secref{sec:file_read} questo è un
 comportamento normale per l'I/O su file, ma con i normali file di dati il
-problema si avverte solo quando si incontra la fine del file, in generale non
+problema si avverte solo quando si incontra la fine del file. In generale non
 è così, e con i socket questo è particolarmente evidente.
 
 Quando ci si trova ad affrontare questo comportamento tutto quello che si deve
@@ -1147,7 +1250,7 @@ sono disponibili: 
 Per questo motivo, seguendo l'esempio di R. W. Stevens in \cite{UNP1}, si sono
 definite due funzioni, \func{FullRead} e \func{FullWrite}, che eseguono
 lettura e scrittura tenendo conto di questa caratteristica, ed in grado di
-ritornare dopo avere letto o scritto esattamente il numero di byte
+ritornare solo dopo avere letto o scritto esattamente il numero di byte
 specificato; il sorgente è riportato rispettivamente in
 \figref{fig:sock_FullRead_code} e \figref{fig:sock_FullWrite_code} ed è
 disponibile fra i sorgenti allegati alla guida nei file \file{FullRead.c} e
@@ -1173,22 +1276,21 @@ l'errore viene ritornato al programma chiamante, interrompendo il ciclo.
 
 Nel caso della lettura, se il numero di byte letti è zero, significa che si è
 arrivati alla fine del file (per i socket questo significa in genere che
-l'altro capo è stato chiuso, e non è quindi più possibile leggere niente) e
+l'altro capo è stato chiuso, e quindi non sarà più possibile leggere niente) e
 pertanto si ritorna senza aver concluso la lettura di tutti i byte richiesti.
 
 
 \subsection{Un primo esempio di client}
 \label{sec:TCP_cli_sample}
 
-Il primo esempio di applicazione delle funzioni viste finora (sia in
-\capref{cha:socket_intro} che in \secref{sec:TCP_functions}) è relativo alla
+Il primo esempio di applicazione delle funzioni viste finora è relativo alla
 creazione di un client elementare per il servizio \textit{daytime}, un
 servizio standard che restituisce l'ora locale della macchina a cui si
-effettua la richiesta, e che è assegnato alla porta 13. 
+effettua la richiesta, e che è assegnato alla porta 13.
 
 In \figref{fig:TCP_cli_code} è riportata la sezione principale del codice del
 nostro client. Il sorgente completo del programma
-(\file{ElemDaytimeTCPClient.c}, che comprende il trattamento delle opzioni e
+(\file{ElemDaytimeTCPClient.c}, che comprende il trattamento delle opzioni ed
 una funzione per stampare un messaggio di aiuto) è allegato alla guida nella
 sezione dei codici sorgente e può essere compilato su una qualunque macchina
 GNU/Linux.
@@ -1207,19 +1309,19 @@ Il programma anzitutto (\texttt{\small 1--5}) include gli header necessari;
 dopo la dichiarazione delle variabili (\texttt{\small 9--12}) si è omessa
 tutta la parte relativa al trattamento degli argomenti passati dalla linea di
 comando (effettuata con le apposite funzioni illustrate in
-\capref{sec:proc_opt_handling}).
+\secref{sec:proc_opt_handling}).
 
-Il primo passo (\texttt{\small 14--18}) è creare un \textit{socket} TCP
-(quindi di famiglia \const{AF\_INET} e di tipo \const{SOCK\_STREAM}). La
-funzione \func{socket} ritorna il descrittore che viene usato per identificare
-il socket in tutte le chiamate successive. Nel caso la chiamata fallisca si
+Il primo passo (\texttt{\small 14--18}) è creare un socket TCP (quindi di tipo
+\const{SOCK\_STREAM} e di famiglia \const{AF\_INET}). La funzione
+\func{socket} ritorna il descrittore che viene usato per identificare il
+socket in tutte le chiamate successive. Nel caso la chiamata fallisca si
 stampa un errore (\texttt{\small 16}) con la funzione \func{perror} e si esce
 (\texttt{\small 16}) con un codice di errore.
 
 Il passo seguente (\texttt{\small 19--27}) è quello di costruire un'apposita
 struttura \struct{sockaddr\_in} in cui sarà inserito l'indirizzo del server ed
 il numero della porta del servizio. Il primo passo (\texttt{\small 20}) è
-inizializzare tutto a zero, per poi inserire il tipo di protocollo
+inizializzare tutto a zero, per poi inserire il tipo di indirizzo
 (\texttt{\small 21}) e la porta (\texttt{\small 22}), usando per quest'ultima
 la funzione \func{htons} per convertire il formato dell'intero usato dal
 computer a quello usato nella rete, infine \texttt{\small 23--27} si può
@@ -1239,7 +1341,7 @@ Completata con successo la connessione il passo successivo (\texttt{\small
   34--40}) è leggere la data dal socket; il protocollo prevede che il server
 invii sempre una stringa alfanumerica di 26 caratteri, nella forma giorno
 della settimana, mese, ora minuto e secondo, anno, seguita dai caratteri di
-teminazione \verb|\r\n|, cioè qualcosa del tipo:
+terminazione \verb|\r\n|, cioè qualcosa del tipo:
 \begin{verbatim}
 Wed Apr 4 00:53:00 2001\r\n
 \end{verbatim}
@@ -1301,16 +1403,16 @@ esempi.
 
 Come per il client si includono (\texttt{\small 1--9}) gli header necessari a
 cui è aggiunto quello per trattare i tempi, e si definiscono (\texttt{\small
-  14--18}) alcune costanti e le variabili necessarie in seguito, come nel caso
+  14--18}) alcune costanti e le variabili necessarie in seguito. Come nel caso
 precedente si sono omesse le parti relative al trattamento delle opzioni da
 riga di comando.
 
 La creazione del socket (\texttt{\small 20--24}) è analoga al caso precedente,
 come pure l'inizializzazione (\texttt{\small 25--29}) della struttura
-\struct{sockaddr\_in}, anche in questo caso (\texttt{\small 28}) si usa la
+\struct{sockaddr\_in}.  Anche in questo caso (\texttt{\small 28}) si usa la
 porta standard del servizio daytime, ma come indirizzo IP si usa
 (\texttt{\small 27}) il valore predefinito \const{INET\_ANY}, che corrisponde
-ad un indirizzo generico.
+all'indirizzo generico.
 
 Si effettua poi (\texttt{\small 30--34}) la chiamata alla funzione \func{bind}
 che permette di associare la precedente struttura al socket, in modo che
@@ -1322,24 +1424,24 @@ programma.
 Il passo successivo (\texttt{\small 35--39}) è quello di mettere ``in
 ascolto'' il socket; questo viene fatto (\texttt{\small 36}) con la funzione
 \func{listen} che dice al kernel di accettare connessioni per il socket che
-abbiamo creatp; la funzione indica inoltre, con il secondo parametro, il
+abbiamo creato; la funzione indica inoltre, con il secondo parametro, il
 numero massimo di connessioni che il kernel accetterà di mettere in coda per
 il suddetto socket. Di nuovo in caso di errore si stampa (\texttt{\small 37})
 un messaggio, e si esce (\texttt{\small 38}) immediatamente.
 
 La chiamata a \func{listen} completa la preparazione del socket per l'ascolto
 (che viene chiamato anche \textit{listening descriptor}) a questo punto si può
-procedere con il ciclo (\texttt{\small 40--53}) principale che viene eseguito
-indefinitamente. Il primo passo è porsi (\texttt{\small 42}) in attesa di
+procedere con il ciclo principale (\texttt{\small 40--53}) che viene eseguito
+indefinitamente. Il primo passo (\texttt{\small 42}) è porsi in attesa di
 connessioni con la chiamata alla funzione \func{accept}, come in precedenza in
 caso di errore si stampa (\texttt{\small 43}) un messaggio, e si esce
 (\texttt{\small 44}).
 
-Il provesso resterà in stato di \textit{sleep} fin quando non arriva e viene
+Il processo resterà in stato di \textit{sleep} fin quando non arriva e viene
 accettata una connessione da un client; quando questo avviene \func{accept}
-ritorna un secondo descrittore di socket, che viene chiamato \textit{connected
-  descriptor}, e che è quello che verrà usato dalla successiva chiamata alla
-\func{write} per scrivere la risposta al client.
+ritorna, restituendo un secondo descrittore, che viene chiamato
+\textit{connected descriptor}, e che è quello che verrà usato dalla successiva
+chiamata alla \func{write} per scrivere la risposta al client.
 
 Il ciclo quindi proseguirà determinando (\texttt{\small 46}) il tempo corrente
 con una chiamata a \texttt{time}, con il quale si potrà opportunamente
@@ -1349,13 +1451,13 @@ trasmissione il nuovo socket viene chiuso (\texttt{\small 52}).  A questo
 punto il ciclo si chiude ricominciando da capo in modo da poter ripetere
 l'invio della data in risposta ad una successiva connessione.
 
-È importante notare che questo server è estremamente elementare, infatti a
+È importante notare che questo server è estremamente elementare, infatti, a
 parte il fatto di poter essere usato solo con indirizzi IPv4, esso è in grado
 di rispondere ad un solo un client alla volta: è cioè, come dicevamo, un
-\textsl{server iterativo}. Inoltre esso è scritto per essere lanciato da linea
-di comando, se lo si volesse utilizzare come demone occorrerebbero le
-opportune modifiche\footnote{come una chiamata a \func{daemon} prima
-  dell'inizio del ciclo principale.} per tener conto di quanto illustrato in
+\textsl{server iterativo}. Inoltre è scritto per essere lanciato da linea di
+comando, se lo si volesse utilizzare come demone occorrerebbero le opportune
+modifiche\footnote{come una chiamata a \func{daemon} prima dell'inizio del
+  ciclo principale.} per tener conto di quanto illustrato in
 \secref{sec:sess_daemon}. Si noti anche che non si è inserita nessuna forma di
 gestione della terminazione del processo, dato che tutti i file descriptor
 vengono chiusi automaticamente alla sua uscita, e che, non generando figli,
@@ -1372,19 +1474,18 @@ scambio di dati pi
 bloccare un server nel servizio di un client per volta; per questo si ricorre
 alle capacità di multitasking del sistema.
 
-Come già visto per i server basati sui meccanismi di intercomunicazione locale
-visti in \capref{cha:IPC}, il modo più immediato per creare un server
-concorrente è quello di usare la funzione \func{fork} per creare ad ogni
-richiesta da parte di un client un processo figlio che si incarichi della
-gestione della comunicazione. Si è allora riscritto il server \texttt{daytime}
-dell'esempio precedente in forma concorrente, inserendo anche una opzione per
-la stampa degli indirizzi delle connessioni ricevute.
+Come accennato anche in \secref{sec:proc_gen} una delle modalità più comuni di
+funzionamento da parte dei server è quella di usare la funzione \func{fork}
+per creare, ad ogni richiesta da parte di un client, un processo figlio che si
+incarichi della gestione della comunicazione.  Si è allora riscritto il server
+\texttt{daytime} dell'esempio precedente in forma concorrente, inserendo anche
+una opzione per la stampa degli indirizzi delle connessioni ricevute.
 
-In \figref{fig:TCP_cunc_serv_code} è mostrato un estratto del codice, in cui si
-sono tralasciati il trattamento delle opzioni e le parti rimaste invariate
+In \figref{fig:TCP_cunc_serv_code} è mostrato un estratto del codice, in cui
+si sono tralasciati il trattamento delle opzioni e le parti rimaste invariate
 rispetto al precedente esempio (cioè tutta la parte riguardante l'apertura
-passiva del socket). Al solito il sorgente completo del server
-\file{ElemDaytimeTCPCuncServ.c} è allegato insieme ai sorgenti degli altri
+passiva del socket). Al solito il sorgente completo del server, nel file
+\file{ElemDaytimeTCPCuncServ.c}, è allegato insieme ai sorgenti degli altri
 esempi.
 
 \begin{figure}[!htb]
@@ -1400,150 +1501,70 @@ esempi.
 
 Stavolta (\texttt{\small 21--25}) la funzione \func{accept} è chiamata
 fornendo una struttura di indirizzi in cui saranno ritornati l'indirizzo IP e
-la porta da cui il client effettua la connessione, che più avanti
+la porta da cui il client effettua la connessione, che in un secondo tempo,
 (\texttt{\small 39--43}), se il logging è abilitato, stamperemo sullo standard
 output.
 
 Quando \func{accept} ritorna il server chiama la funzione \func{fork}
 (\texttt{\small 26--30}) per creare il processo figlio che effettuerà
 (\texttt{\small 31--45}) tutte le operazioni relative a quella connessione,
-mentre il padre resterà in attesa di ulteriori connessioni.
+mentre il padre proseguirà l'esecuzione del ciclo principale in attesa di
+ulteriori connessioni.
 
 Si noti come il figlio operi solo sul socket connesso, chiudendo
 immediatamente (\texttt{\small 32}) il socket \var{list\_fd}; mentre il padre
-continua ad operare solo sul socket in ascolto chiudendo \var{sock\_fd} dopo
-(\texttt{\small 47}) ciascuna \func{accept}. Per quanto abbiamo detto in
-\secref{sec:TCP_func_close} queste due chiusure non causano l'innesco della
-sequenza di chiusura perché il numero di riferimenti al file descriptor non si
-è annullato.
+continua ad operare solo sul socket in ascolto chiudendo (\texttt{\small 47})
+\var{sock\_fd} al ritorno dalla \func{fork}. Per quanto abbiamo detto in
+\secref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa
+l'innesco della sequenza di chiusura perché il numero di riferimenti al file
+descriptor non si è annullato.
 
 Infatti subito dopo la creazione del socket \var{list\_fd} ha una referenza, e
 lo stesso vale per \var{sock\_fd} dopo il ritorno di \func{accept}, ma dopo la
-fork i descrittori vengono duplicati nel padre e nel figlio per cui entrambi i
-socket si trovano con due referenze. Questo fa si che quando il padre chiude
-\var{sock\_fd} esso resta con una referenza da parte del figlio, e sarà
-definitivamente chiuso solo quando quest'ultimo, dopo aver completato le sue
-operazioni, chiamerà la funzione \func{close}.
-
-In realtà per il figlio non sarebbero necessarie nessuna delle due chiamate a
-\func{close} in quanto nella \func{exit} tutti i file ed i socket vengono
-chiusi. Tuttavia si è preferito effettuare la chiusura esplicitamente per
-avere una maggiore chiarezza del codice ed evitare possibili errori.
-
-Si noti come sia essenziale che il padre chiuda ogni volta il socket connesso
-dopo la \func{accept}; se così non fosse nessuno di questi socket sarebbe
-effettivamente chiuso dato che alla chiusura da parte del figlio resterebbe
-ancora un riferimento. Si avrebbero così due effetti, il padre potrebbe
-esaurire i descrittori disponibili (che sono un numero limitato per ogni
-processo) e soprattutto nessuna delle connessioni con i client verrebbe
-chiusa.
-
-Si noti come anche in questo caso non si sia gestita né la terminazione del
-processo né il suo uso come demone, che tra l'altro sarenne stato
-incompatibile con l'uso della opzione di logging che stampa gli indirizzi
-delle connessioni sullo standard output. Un altro aspetto tralasciato è la
-gestione della terminazione dei processi figli, torneremo su questo più avanti
-quando tratteremo alcuni esempi di server più complessi.
-
-
-\subsection{Le funzioni \func{getsockname} e \func{getpeername}}
-\label{sec:TCP_get_names}
-
-Queste due funzioni vengono usate per ottenere i dati relativi alla socket
-pair associata ad un certo socket; la prima è \funcd{getsockname} e
-restituisce l'indirizzo locale; il suo prototipo è:
-\begin{prototype}{sys/socket.h}
-  {int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)}
-  Legge l'indirizzo locale del socket \param{sockfd} nella struttura
-  \param{name}.
-
-\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
-  errore. I codici di errore restituiti in \var{errno} sono i seguenti:
-  \begin{errlist}
-  \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor
-    valido.
-  \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket.
-  \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per
-    eseguire l'operazione.
-  \item[\errcode{EFAULT}] l'argomento \param{name} punta al di fuori dello
-    spazio di indirizzi del processo.
-  \end{errlist}}
-\end{prototype}
-
-La funzione si usa tutte le volte che si vuole avere l'indirizzo locale di un
-socket; ad esempio può essere usata da un client (che usualmente non chiama
-\func{bind}) per ottenere numero IP e porta locale associati al socket
-restituito da una \func{connect}, o da un server che ha chiamato \func{bind}
-su un socket usando 0 come porta locale per ottenere il numero di porta
-effimera assegnato dal kernel.
-
-Inoltre quando un server esegue una \func{bind} su un indirizzo generico, se
-chiamata dopo il completamento di una connessione sul socket restituito da
-\func{accept}, restituisce l'indirizzo locale che il kernel ha assegnato a
-quella connessione.
-
-Tutte le volte che si vuole avere l'indirizzo remoto di un socket si usa la
-funzione \funcd{getpeername}, il cui prototipo è:
-\begin{prototype}{sys/socket.h}
-  {int getpeername(int sockfd, struct sockaddr * name, socklen\_t * namelen)}
-  Legge l'indirizzo remoto del socket \param{sockfd} nella struttura
-  \param{name}.
-  
-  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
-    errore. I codici di errore restituiti in \var{errno} sono i seguenti:
-  \begin{errlist}
-  \item[\errcode{EBADF}] l'argomento \param{sockfd} non è un file descriptor
-    valido.
-  \item[\errcode{ENOTSOCK}] l'argomento \param{sockfd} non è un socket.
-  \item[\errcode{ENOTCONN}] il socket non è connesso.
-  \item[\errcode{ENOBUFS}] non ci sono risorse sufficienti nel sistema per
-    eseguire l'operazione.
-  \item[\errcode{EFAULT}] l'argomento \param{name} punta al di fuori dello
-    spazio di indirizzi del processo.
-  \end{errlist}}
-\end{prototype}
-
-Ci si può chiedere a cosa serva questa funzione dato che dal lato client
-l'indirizzo remoto è sempre noto quando si esegue la \func{connect} mentre
-dal lato server si possono usare, come si è fatto nell'esempio precedente, i
-valori di ritorno di \func{accept}.
-
-In generale però questa ultima possibilità è sempre possibile. In particolare
-questo avviene quando il server invece di far gestire la connessione
-direttamente a un processo figlio, come nell'esempio precedente, lancia un
-opportuno programma per ciascuna connessione usando \func{exec} (questa ad
-esempio è la modalità con cui opera il \textsl{super-server} \cmd{inetd}
-che gestisce tutta una serie di servizi lanciando per ogni connessione
-l'opportuno server).
-
-In questo caso benché il processo figlio abbia una immagine della memoria che
-è copia di quella del processo padre (e contiene quindi anche la struttura
-ritornata da \func{accept}), all'esecuzione di \func{exec} viene caricata
-in memoria l'immagine del programma eseguito che a questo punto perde ogni
-riferimento. Il socket descriptor però resta aperto. Allora se una opportuna
-convenzione è seguita per rendere noto al programma eseguito qual'è il socket
-connesso (\cmd{inetd} ad esempio fa sempre in modo che i file descriptor 0,
-1 e 2 corrispondano al socket connesso) quest'ultimo potrà usare la funzione
-\func{getpeername} per determinare l'indirizzo remoto del client.
-
-Infine è da chiarire (si legga la pagina di manuale) che, come per
-\func{accept}, il terzo parametro, che è specificato dallo standard POSIX.1g
-come di tipo \code{socklen\_t *} in realtà deve sempre corrispondere ad un
-\ctyp{int *} come prima dello standard perché tutte le implementazioni dei
-socket BSD fanno questa assunzione.
-
-
-
-
-
-
-
-
-
-
-
-
-
+\func{fork} i descrittori vengono duplicati nel padre e nel figlio per cui
+entrambi i socket si trovano con due referenze. Questo fa si che quando il
+padre chiude \var{sock\_fd} esso resta con una referenza da parte del figlio,
+e sarà definitivamente chiuso solo quando quest'ultimo, dopo aver completato
+le sue operazioni, chiamerà (\texttt{\small 44}) la funzione \func{close}.
+
+In realtà per il figlio non sarebbe necessaria nessuna chiamata a
+\func{close}, in quanto con la \func{exit} finale (\texttt{\small 45}) tutti i
+file descriptor, quindi anche quelli associati ai socket, vengono
+automaticamente chiusi.  Tuttavia si è preferito effettuare esplicitamente le
+chiusure per avere una maggiore chiarezza del codice, e per evitare eventuali
+errori, prevenendo ad esempio un uso involontario del \textit{listening
+  descriptor}.
+
+Si noti invece come sia essenziale che il padre chiuda ogni volta il socket
+connesso dopo la \func{fork}; se così non fosse nessuno di questi socket
+sarebbe effettivamente chiuso dato che alla chiusura da parte del figlio
+resterebbe ancora un riferimento nel padre. Si avrebbero così due effetti: il
+padre potrebbe esaurire i descrittori disponibili (che sono un numero limitato
+per ogni processo) e soprattutto nessuna delle connessioni con i client
+verrebbe chiusa.
+
+Come per ogni server iterativo il lavoro di risposta viene eseguito
+interamente dal processo figlio. Questo si incarica (\texttt{\small 33}) di
+chiamare \func{time} per leggere il tempo corrente, e di stamparlo
+(\texttt{\small 34}) sulla stringa contenuta in \var{buffer} con l'uso di
+\func{snprintf} e \func{ctime}. Poi la stringa viene scritta (\texttt{\small
+  35--38}) sul socket, controllando che non ci siano errori. Anche in questo
+caso si è evitato il ricorso a \func{FullWrite} in quanto la stringa è
+estremamente breve e verrà senz'altro scritta in un singolo segmento.
+
+Inoltre nel caso sia stato abilitato il \textit{logging} delle connessioni, si
+provvede anche (\texttt{\small 39--42}) a stampare sullo standard output
+l'indirizzo e la porta da cui il client ha effettuato la connessione, usando
+i valori contenuti nelle strutture restituite da \func{accept}, eseguendo le
+opportune conversioni con \func{inet\_ntop} e \func{atohs}.
+
+Ancora una volta l'esempio è estremamente semplificato, si noti come di nuovo
+non si sia gestita né la terminazione del processo né il suo uso come demone,
+che tra l'altro sarebbe stato incompatibile con l'uso della opzione di logging
+che stampa gli indirizzi delle connessioni sullo standard output. Un altro
+aspetto tralasciato è la gestione della terminazione dei processi figli,
+torneremo su questo più avanti quando tratteremo alcuni esempi di server più
+complessi.
 
 
 %%% Local Variables: 
index 972a96bcbde50680778bae6f5858105fe77ce8c5..dae2d68a5caff764ce8e8a5cce69b67b36a2a1f0 100644 (file)
--- a/gapil.tex
+++ b/gapil.tex
@@ -91,9 +91,9 @@
 \end{quote}
 \clearemptydoublepage
 
-\ifx\hcode\undefined\else
+%\ifx\hcode\undefined\else
 \tableofcontents
-\fi
+%\fi
 
 \clearemptydoublepage
 \include{macro}
index 98e7747c61f4c66571dcb9f0148ad5fc3fc0ad0a..2934e6382bc9af8f29d1ef41494f28610237c8c4 100644 (file)
@@ -864,7 +864,7 @@ che IPv6 siano supportati sull'host di origine).
 \label{tab:IP_ipv6_map}
 \end{table}
 
-Un secondo tipo di indirizzi di compatibilità sono gli \textit{IPv4
+Un secondo tipo di indirizzi di compatibilità sono gli \textsl{IPv4
   compatibili IPv6} (vedi \tabref{tab:IP_ipv6_comp}) usati nella transizione
 da IPv4 a IPv6: quando un nodo che supporta sia IPv6 che IPv4 non ha un router
 IPv6 deve usare nel DNS un indirizzo di questo tipo, ogni pacchetto IPv6
index 1d2a02b1a93d85f1984c2009263a41d440b8800d..2d9186ea3a779a173ca26529ef6ea3bf622a7127 100644 (file)
@@ -568,7 +568,7 @@ grandi linee nei seguenti punti:
 \end{itemize}
 
 Maggiori dettagli riguardo a caratteristiche, notazioni e funzionamento del
-protocollo IP sono forniti nell'appendice \capref{cha:ip_protocol}.
+protocollo IP sono forniti nell'appendice \secref{sec:ip_protocol}.
 
  
 \subsection{User Datagram Protocol (UDP)}
@@ -680,7 +680,7 @@ del controllo di flusso e della gestione della sequenzialit
 effettuato per entrambe le direzioni di comunicazione.
 
 %% Una descrizione più accurata del protocollo è fornita in appendice
-%% \capref{cha:tcp_protocol}.
+%% \secref{sec:tcp_protocol}.
 
 \subsection{Limiti e dimensioni riguardanti la trasmissione dei dati}
 \label{sec:net_lim_dim}
@@ -714,7 +714,7 @@ dimensioni eccedono la MTU viene eseguita la cosiddetta
 \textit{frammentazione}, i pacchetti cioè vengono suddivisi\footnote{questo
   accade sia per IPv4 che per IPv6, anche se i pacchetti frammentati sono
   gestiti con modalità diverse, IPv4 usa un flag nell'header, IPv6 una
-  opportuna opzione, si veda \secref{cha:ip_protocol}.}) in blocchi più
+  opportuna opzione, si veda \secref{sec:ipv6_protocol}.}) in blocchi più
 piccoli che possono essere trasmessi attraverso l'interfaccia.
 
 \begin{table}[!htb]
index 12c66cd0c999feffc81aae3ca60ebe5120cf63ad..8770f9312633659f75e601c4f967a2e3054d388d 100644 (file)
@@ -8,8 +8,48 @@
 %% license is included in the section entitled "GNU Free Documentation
 %% License".
 %%
-\chapter{Il protocollo TCP}
-\label{cha:tcp_protocol}
+\chapter{Il livello di trasporto}
+\label{cha:transport_layer}
+
+In questa appendice tratteremo i vari protocolli relativi al livello di
+trasporto.\footnote{al solito per la definizione dei livelli si faccia
+  riferimento alle spiegazioni fornite in \ref{sec:net_protocols}.} In
+particolare gran parte del capitolo sarà dedicato al più importante di questi,
+il TCP, che è pure il più complesso ed utilizzato su internet.
+
+
+\section{Il protocollo TCP}
+\label{sec:tcp_protocol}
+
+In questa sezione prenderemo in esame i vari aspetti del protocollo TCP, il
+protocollo più comunemente usato dalle applicazioni di rete.
+
+
+
+\subsection{Gli stati del TCP}
+\label{sec:TCP_states}
+
+In \secref{sec:TCP_connession} abbiamo descritto in dettaglio le modalità con
+cui il protocollo TCP avvia e conclude una connessione, ed abbiamo accennato
+alla presenza dei vari stati del protocollo. In generale infatti il
+funzionamento del protocollo segue una serie di regole, che possono essere
+riassunte nel comportamento di una macchina a stati, il cui diagramma di
+transizione è riportato in \figref{fig:TCP_state_diag}.
+
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=10cm]{img/tcp_state_diagram}  
+  \caption{Il diagramma degli stati del TCP.}
+  \label{fig:TCP_state_diag}
+\end{figure}
+
+Il protocollo prevede l'esistenza di 11 diversi stati per una connessione ed
+un insieme di regole per le transizioni da uno stato all'altro basate sullo
+stato corrente, sull'operazione effettuata dall'applicazione o sul tipo di
+segmento ricevuto; i nomi degli stati mostrati in \figref{fig:TCP_state_diag}
+sono gli stessi che vengono riportati del comando \cmd{netstat} nel campo
+\textit{State}.
 
 
 %%% Local Variables: