Cambiato il riferimento nelle note di copyright alla nuova sezione invariante
[gapil.git] / othersock.tex
index 7897c6eb27d4e27b92cd990a7674cd422f9c265b..dcf4ee588adb8d23e9ab24aa5d8837166e276e06 100644 (file)
@@ -3,7 +3,7 @@
 %% Copyright (C) 2004 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
 %% Documentation License, Version 1.1 or any later version published by the
 %% Copyright (C) 2004 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
 %% Documentation License, Version 1.1 or any later version published by the
-%% Free Software Foundation; with the Invariant Sections being "Prefazione",
+%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
 %% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
 %% license is included in the section entitled "GNU Free Documentation
 %% License".
 %% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
 %% license is included in the section entitled "GNU Free Documentation
 %% License".
@@ -14,7 +14,7 @@
 Dopo aver trattato in cap.~\ref{cha:TCP_socket} i socket TCP, che costituiscono
 l'esempio più comune dell'interfaccia dei socket, esamineremo in questo
 capitolo gli altri tipi di socket, a partire dai socket UDP, e i socket
 Dopo aver trattato in cap.~\ref{cha:TCP_socket} i socket TCP, che costituiscono
 l'esempio più comune dell'interfaccia dei socket, esamineremo in questo
 capitolo gli altri tipi di socket, a partire dai socket UDP, e i socket
-\textit{Unix domain} già incontrati in \secref{sec:ipc_socketpair}.
+\textit{Unix domain} già incontrati in sez.~\ref{sec:ipc_socketpair}.
 
 
 \section{I socket UDP}
 
 
 \section{I socket UDP}
@@ -264,9 +264,10 @@ I due argomenti \param{from} e \param{fromlen} sono utilizzati per ottenere
 l'indirizzo del mittente del pacchetto che è stato ricevuto, e devono essere
 opportunamente inizializzati con i puntatori alle variabili dove la struttura
 contenente quest'ultimo e la relativa lunghezza saranno scritti (si noti che
 l'indirizzo del mittente del pacchetto che è stato ricevuto, e devono essere
 opportunamente inizializzati con i puntatori alle variabili dove la struttura
 contenente quest'ultimo e la relativa lunghezza saranno scritti (si noti che
-\param{fromlen} è un valore intero ottenuto come \textit{value return
-  argument}).  Se non si è interessati a questa informazione, entrambi gli
-argomenti devono essere inizializzati al valore \const{NULL}.
+\param{fromlen} è un valore intero ottenuto come
+\index{\textit{value~result~argument}}\textit{value result argument}).  Se non
+si è interessati a questa informazione, entrambi gli argomenti devono essere
+inizializzati al valore \const{NULL}.
 
 Una differenza fondamentale del comportamento di queste funzioni rispetto alle
 usuali \func{read} e \func{write} che abbiamo usato con i socket TCP è che in
 
 Una differenza fondamentale del comportamento di queste funzioni rispetto alle
 usuali \func{read} e \func{write} che abbiamo usato con i socket TCP è che in
@@ -498,11 +499,11 @@ possono avere proviamo allora con un servizio leggermente pi
 \begin{figure}[!htb] 
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
 \begin{figure}[!htb] 
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
-    \includecodesample{listati/UDP_echo.c}
+    \includecodesample{listati/UDP_echo_first.c}
   \end{minipage} 
   \normalsize
   \end{minipage} 
   \normalsize
-  \caption{Sezione principale del client per il servizio \textit{echo} su
-    UDP.}
+  \caption{Sezione principale della prima versione client per il servizio
+    \textit{echo} su UDP.}
   \label{fig:UDP_echo_client}
 \end{figure}
 
   \label{fig:UDP_echo_client}
 \end{figure}
 
@@ -519,16 +520,16 @@ per
 \begin{figure}[!htb] 
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
 \begin{figure}[!htb] 
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
-    \includecodesample{listati/UDP_ClientEcho.c}
+    \includecodesample{listati/UDP_ClientEcho_first.c}
   \end{minipage}
   \normalsize
   \caption{Codice della funzione \func{ClientEcho} usata dal client per il
     servizio \textit{echo} su UDP.}
   \end{minipage}
   \normalsize
   \caption{Codice della funzione \func{ClientEcho} usata dal client per il
     servizio \textit{echo} su UDP.}
-  \label{fig:UDP_echo_clientecho}
+  \label{fig:UDP_echo_client_echo}
 \end{figure}
 
 Ovviamente in questo caso il funzionamento della funzione, il cui codice è
 \end{figure}
 
 Ovviamente in questo caso il funzionamento della funzione, il cui codice è
-riportato in fig.~\ref{fig:UDP_echo_clientecho}, è completamente diverso
+riportato in fig.~\ref{fig:UDP_echo_client_echo}, è completamente diverso
 rispetto alla analoga del server TCP, e dato che non esiste una connessione
 questa necessita anche di un terzo argomento, che è l'indirizzo del server cui
 inviare i pacchetti.
 rispetto alla analoga del server TCP, e dato che non esiste una connessione
 questa necessita anche di un terzo argomento, che è l'indirizzo del server cui
 inviare i pacchetti.
@@ -617,25 +618,31 @@ irraggiungibile che ci segnala che la porta in questione non risponde.
 Ci si può chiedere allora perché, benché la situazione di errore sia
 rilevabile, questa non venga segnalata. Il luogo più naturale in cui
 riportarla sarebbe la chiamata di \func{sendto}, in quanto è a causa dell'uso
 Ci si può chiedere allora perché, benché la situazione di errore sia
 rilevabile, questa non venga segnalata. Il luogo più naturale in cui
 riportarla sarebbe la chiamata di \func{sendto}, in quanto è a causa dell'uso
-di indirizzo sbagliato che il pacchetto non può essere inviato; farlo in
+di un indirizzo sbagliato che il pacchetto non può essere inviato; farlo in
 questo punto però è impossibile, dato che l'interfaccia di programmazione
 questo punto però è impossibile, dato che l'interfaccia di programmazione
-richiede che la funzione ritorni non appena il kernel invia il pacchetto, e
-non può bloccarsi in una attesa di una risposta che potrebbe essere molto
-lunga (si noti infatti che il pacchetto ICMP arriva qualche decimo di secondo
-più tardi) o non esserci affatto.  
+richiede che la funzione ritorni non appena il kernel invia il
+pacchetto,\footnote{questo è il classico caso di \textsl{errore asincrono},
+  una situazione cioè in cui la condizione di errore viene rilevata in maniera
+  asincrona rispetto all'operazione che l'ha causata, una eventualità
+  piuttosto comune quando si ha a che fare con la rete, tutti i pacchetti ICMP
+  che segnalano errori rientrano in questa tipologia.} e non può bloccarsi in
+una attesa di una risposta che potrebbe essere molto lunga (si noti infatti
+che il pacchetto ICMP arriva qualche decimo di secondo più tardi) o non
+esserci affatto.
 
 Si potrebbe allora pensare di riportare l'errore nella \func{recvfrom} che è
 
 Si potrebbe allora pensare di riportare l'errore nella \func{recvfrom} che è
-comunque bloccata in attesa di una risposta che nel caso non non arriverà mai.
-La ragione di tutto questo è piuttosto sottile e viene trattata da Stevens in
-\cite{UNP2} con il seguente esempio: si consideri un client che invia tre
-pacchetti a tre diverse macchine, due quali vengono regolarmente ricevuti,
-mentre al terzo, non essendo presente un server sulla relativa macchina, viene
-risposto con un messaggio ICMP come il precedente. Detto messaggio conterrà
-anche le informazioni relative ad indirizzo e porta del pacchetto che ha
-fallito, però tutto quello che il kernel può restituire al programma è un
-codice di errore in \var{errno}, e pertanto è stata fatta la scelta di non
-riportare l'errore, a meno che, come vedremo in sez.~\ref{sec:UDP_connect}, il
-socket non sia connesso.
+comunque bloccata in attesa di una risposta che nel caso non arriverà mai.  La
+ragione per cui non viene fatto è piuttosto sottile e viene spiegata da
+Stevens in \cite{UNP2} con il seguente esempio: si consideri un client che
+invia tre pacchetti a tre diverse macchine, due dei quali vengono regolarmente
+ricevuti, mentre al terzo, non essendo presente un server sulla relativa
+macchina, viene risposto con un messaggio ICMP come il precedente. Detto
+messaggio conterrà anche le informazioni relative ad indirizzo e porta del
+pacchetto che ha fallito, però tutto quello che il kernel può restituire al
+programma è un codice di errore in \var{errno}, con il quale è impossibile di
+distinguere per quale dei pacchetti inviati si è avuto l'errore; per questo è
+stata fatta la scelta di non riportare un errore su un socket UDP, a meno che,
+come vedremo in sez.~\ref{sec:UDP_connect}, questo non sia connesso.
 
 
 
 
 
 
@@ -644,23 +651,106 @@ socket non sia connesso.
 
 Come illustrato in sez.~\ref{sec:UDP_characteristics} essendo i socket UDP
 privi di connessione non è necessario per i client usare \func{connect} prima
 
 Come illustrato in sez.~\ref{sec:UDP_characteristics} essendo i socket UDP
 privi di connessione non è necessario per i client usare \func{connect} prima
-di iniziare una comunicazione con un server.
+di iniziare una comunicazione con un server. Ciò non di meno abbiamo accennato
+come questa possa essere utilizzata per gestire la presenza di errori
+asincroni.
+
+Quando si chiama \func{connect} su di un socket UDP tutto quello che succede è
+che l'indirizzo passato alla funzione viene registrato come indirizzo di
+destinazione del socket. A differenza di quanto avviene con TCP non viene
+scambiato nessun pacchetto, tutto quello che succede è che da quel momento in
+qualunque cosa si scriva sul socket sarà inviata a quell'indirizzo; non sarà
+più necessario usare l'argomento \param{to} di \func{sendto} per specificare
+la destinazione dei pacchetti, che potranno essere inviati e ricevuti usando
+le normali funzioni \func{read} e \func{write}.\footnote{in realtà si può
+  anche continuare ad usare la funzione \func{sendto}, ma in tal caso
+  l'argomento \param{to} deve essere inizializzato a \const{NULL}, e
+  \param{tolen} deve essere inizializzato a zero, pena un errore.}
+
+Una volta che il socket è connesso cambia però anche il comportamento in
+ricezione; prima infatti il kernel avrebbe restituito al socket qualunque
+pacchetto ricevuto con un indirizzo di destinazione corrispondente a quello
+del socket, senza nessun controllo sulla sorgente; una volta che il socket
+viene connesso saranno riportati su di esso solo i pacchetti con un indirizzo
+sorgente corrispondente a quello a cui ci si è connessi.
+
+Infine quando si usa un socket connesso, venendo meno l'ambiguità segnalata
+alla fine di sez.~\ref{sec:UDP_problems}, tutti gli eventuali errori asincroni
+vengono riportati alle funzioni che operano su di esso; pertanto potremo
+riscrivere il nostro client per il servizio \textit{echo} con le modifiche
+illustrate in fig.~\ref{fig:UDP_echo_conn_cli}.
+
+\begin{figure}[!htb] 
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/UDP_echo.c}
+  \end{minipage}
+  \normalsize
+  \caption{Seconda versione del client del servizio \textit{echo} che utilizza
+    socket UDP connessi.}
+  \label{fig:UDP_echo_conn_cli}
+\end{figure}
+
+Ed in questo caso rispetto alla precedente versione, il solo cambiamento è
+l'utilizzo (\texttt{\small 17}) della funzione \func{connect} prima della
+chiamata alla funzione di gestione del protocollo, che a sua volta è stata
+modificata eliminando l'indirizzo passato come parametro e sostituendo le
+chiamata a \func{sendto} e \func{recvfrom} con chiamate a \func{read} e
+\func{write} come illustrato dal nuovo codice riportato in
+fig.~\ref{fig:UDP_echo_conn_echo_client}.
+
+\begin{figure}[!htb] 
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/UDP_ClientEcho.c}
+  \end{minipage}
+  \normalsize
+  \caption{Seconda versione della funzione \func{ClientEcho}.}
+  \label{fig:UDP_echo_conn_echo_client}
+\end{figure}
+
+Utilizzando questa nuova versione del client si può verificare che quando ci
+si rivolge verso un indirizzo inesistente o su cui non è in ascolto un server
+si è in grado rilevare l'errore, se infatti eseguiamo il nuovo programma
+otterremo un qualcosa del tipo:
+\begin{verbatim}
+[piccardi@gont sources]$ ./echo 192.168.1.1
+prova
+Errore in lettura: Connection refused
+\end{verbatim}%$
+
+Ma si noti che a differenza di quanto avveniva con il client TCP qui l'errore
+viene rilevato soltanto dopo che si è tentato di inviare qualcosa, ed in
+corrispondenza al tentativo di lettura della risposta. Questo avviene perché
+con UDP non esiste una connessione, e fintanto che non si invia un pacchetto
+non c'è traffico sulla rete. In questo caso l'errore sarà rilevato alla
+ricezione del pacchetto ICMP \textit{destination unreachable} emesso dalla
+macchina cui ci si è rivolti, e questa volta, essendo il socket UDP connesso,
+il kernel potrà riportare detto errore in user space in maniera non ambigua,
+ed esso apparirà alla successiva lettura sul socket.
+
+Si tenga presente infine che l'uso dei socket connessi non risolve l'altro
+problema del client, e cioè il fatto che in caso di perdita di un pacchetto
+questo resterà bloccato permanentemente in attesa di una risposta. Per
+risolvere questo problema l'unico modo sarebbe quello di impostare un
+\textit{timeout} o riscrivere il client in modo da usare l'I/O non bloccante.
 
 
 
 \section{I socket \textit{Unix domain}}
 \label{sec:unix_socket}
 
 
 
 
 \section{I socket \textit{Unix domain}}
 \label{sec:unix_socket}
 
-Benché i socket Unix domain non siano strettamente attinenti alla rete, in
-quanto definiscono una interfaccia di comunicazione locale alla singola
-macchina, li tratteremo comunque in questa sezione in quanto la loro
-interfaccia è comunque basata sulla più generale interfaccia dei socket.
+Benché i socket Unix domain, come meccanismo di comunicazione fra processi che
+girano sulla stessa macchina, non siano strettamente attinenti alla rete, li
+tratteremo comunque in questa sezione. Nonstante le loro peculiarità infatti,
+l'interfaccia di programmazione che serve ad utilizzarli resta sempre quella
+dei socket.
+
 
 
 \section{Altri socket}
 \label{sec:socket_other}
 
 
 
 \section{Altri socket}
 \label{sec:socket_other}
 
-
 Tratteremo in questa sezione gli altri tipi particolari di socket supportati
 da Linux, come i \textit{raw socket}, con i quali si possono \textsl{forgiare}
 direttamente i pacchetti a tutti i livelli dello stack dei protocolli, o i
 Tratteremo in questa sezione gli altri tipi particolari di socket supportati
 da Linux, come i \textit{raw socket}, con i quali si possono \textsl{forgiare}
 direttamente i pacchetti a tutti i livelli dello stack dei protocolli, o i