X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=othersock.tex;h=dcf4ee588adb8d23e9ab24aa5d8837166e276e06;hp=d73aa57b5328364ab5ed84531873f1fb2cccf044;hb=406973e35011347c3812c671511ce738378a525b;hpb=2a09a578f80e369673bd5ac24179c021e903358b diff --git a/othersock.tex b/othersock.tex index d73aa57..dcf4ee5 100644 --- a/othersock.tex +++ b/othersock.tex @@ -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 -%% 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". @@ -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 -\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} @@ -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 -\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 @@ -519,7 +520,7 @@ per \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 @@ -656,8 +657,8 @@ 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 +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 @@ -666,17 +667,18 @@ le normali funzioni \func{read} e \func{write}.\footnote{in realt 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 però cambia anche il comportamento in +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. +sorgente corrispondente a quello a cui ci si è connessi. -Infine quando si è connesso un socket, 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 esse, pertanto con le -modifiche illustrate in fig.~\ref{fig:UDP_echo_conn_cli}. +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 @@ -684,27 +686,71 @@ modifiche illustrate in fig.~\ref{fig:UDP_echo_conn_cli}. \includecodesample{listati/UDP_echo.c} \end{minipage} \normalsize - \caption{Nuova sezione della seconda versione del client del servizio - \textit{echo} che utilizza socket UDP connessi.} + \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} -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} - 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