X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsockadv.tex;h=44986525fc3141b95422a22548adb4ede34b939a;hp=24c45d2cbf9d1aa707fec08f248fbb4e5703530e;hb=65cdd0498d1d9473110f86ebddede62c298e60dd;hpb=fcd431ebcd9f7a65680a669a2740ef5a2586531c diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 24c45d2..4498652 100644 --- a/tcpsockadv.tex +++ b/tcpsockadv.tex @@ -12,45 +12,47 @@ \label{cha:TCP_advanced} Esamineremo in questo capitolo le funzionalità più evolute della gestione dei -socket TCP. +socket TCP, come l'uso del I/O multiplexing (trattato in +\secref{sec:file_multiplexing}) con i socket, l'uso delle opzioni dei socket e +la gestione dei dati urgenti e \textit{out-of-band}. -\section{Socket multiplexing} +\section{Socket I/O multiplexing} \label{sec:TCP_sock_multiplexing} Affronteremo in questa sezione l'utilizzo dell'I/O multiplexing, affrontato in \secref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già in -\ref{sec:TCP_server_crash} era emerso il problema relativo al client del +\secref{sec:TCP_server_crash} era emerso il problema relativo al client del servizio echo che non era in grado di accorgersi della terminazione precoce -del server essendo bloccato nella lettura dei dati immessi da tastiera. +del server, essendo bloccato nella lettura dei dati immessi da tastiera. Abbiamo visto in \secref{sec:file_multiplexing} quali sono le funzionalità del sistema che ci permettono di tenere sotto controllo più file descriptor in contemporanea; in quella occasione non abbiamo fatto esempi, in quanto quando -si tratta con file normali questa tipologia di I/O non viene usata, è invece -un caso tipico delle applicazioni di rete quello di dover gestire varie -connessioni da cui possono arrivare dati comuni in maniera asincrona, per cui -riprenderemo l'argomento in questa sezione. - +si tratta con file normali questa tipologia di I/O normalmente non viene +usata, è invece un caso tipico delle applicazioni di rete quello di dover +gestire varie connessioni da cui possono arrivare dati comuni in maniera +asincrona, per cui riprenderemo l'argomento in questa sezione. \subsection{Il comportamento della funzione \func{select} con i socket.} \label{sec:TCP_sock_select} Iniziamo con la prima delle funzioni usate per l'I/O multiplexing, -\func{select}, il suo funzionamento è già stato descritto in dettaglio in +\func{select}; il suo funzionamento è già stato descritto in dettaglio in \secref{sec:file_multiplexing} e non staremo a ripetere quanto detto lì; sappiamo che la funzione ritorna quando uno o più dei file descriptor messi sotto controllo è pronto per la relativa operazione. In quell'occasione non abbiamo però definito cosa si intende per pronto, infatti per dei normali file, o anche per delle pipe, la condizione di essere -pronti per la lettura o la scrittura è ovvia, lo è un po' meno di meno nel -caso dei socket, visto che intervengono tutte le possibili condizioni dovute -alla rete. Occorre allora specificare quali sono le condizioni in cui un -socket risulta \textsl{pronto} quando viene passato come membro di uno dei tre -\textit{file descriptor set} usati da \func{select}. +pronti per la lettura o la scrittura è ovvia; invece lo è molto meno nel caso +dei socket, visto che possono intervenire tutte una serie di possibili +condizioni di errore dovute alla rete. Occorre allora specificare chiaramente +quali sono le condizioni per cui un socket risulta essere ``\textsl{pronto}'' +quando viene passato come membro di uno dei tre \textit{file descriptor set} +usati da \func{select}. Le condizioni che fanno si che la funzione \func{select} ritorni segnalando che un socket (che sarà riportato nel primo insieme di file descriptor) è @@ -80,8 +82,8 @@ pronto per la lettura sono le seguenti: \secref{sec:TCP_conn_early_abort} una connessione può essere abortita dalla ricezione di un segmento RST una volta che è stata completata, allora se questo avviene dopo che \func{select} è ritornata, ma prima - della chiamata ad \func{accept} quest'ultima, in assenza di altre - connessiioni, potrà bloccarsi.} + della chiamata ad \func{accept}, quest'ultima, in assenza di altre + connessioni, potrà bloccarsi.} \end{itemize*} Le condizioni che fanno si che la funzione \func{select} ritorni segnalando @@ -109,14 +111,14 @@ Infine c' che un socket (che sarà riportato nel terzo insieme di file descriptor) ha una condizione di eccezione pendente, e cioè la ricezione sul socket di dati \textsl{fuori banda} (o \textit{out-of-band}), una caratteristica specifica -dei socket TCP su cui torneremo in \secref{sec:TCP_outofband}. +dei socket TCP su cui torneremo in \secref{sec:TCP_urgent_data}. Si noti come nel caso della lettura \func{select} si applichi anche ad -operazioni che non hanno nulla a che fare con l'I/O come il riconoscimento -della presenza di connessioni pronte, in modo da consentire l'utilizzo di -\func{accept} in modalità non bloccante. Si noti infine come in caso di errore -un socket venga sempre riportato come pronto sia per la lettura che per la -scrittura. +operazioni che non hanno nulla a che fare con l'I/O di dati come il +riconoscimento della presenza di connessioni pronte, in modo da consentire +anche l'utilizzo di \func{accept} in modalità non bloccante. Si noti infine +come in caso di errore un socket venga sempre riportato come pronto sia per la +lettura che per la scrittura. Lo scopo dei due valori di soglia per i buffer di ricezione e di invio è quello di consentire maggiore flessibilità nell'uso di \func{select} da parte @@ -129,11 +131,95 @@ quando c' sempre quanti dati invia, mentre non è detto possa conoscere la quantità di dati in ricezione; per cui, nella situazione in cui si conosce almeno un valore minimo, per evitare la penalizzazione dovuta alla ripetizione delle - operazioni di lettura quando per accumulare dati sufficienti, si può - lasciare al kernel il compito di impostare un minimo al di sotto del quale - il file descriptor, pur avendo disponibili dei dati, non viene letto.} - - + operazioni di lettura per accumulare dati sufficienti, si può lasciare al + kernel il compito di impostare un minimo al di sotto del quale il file + descriptor, pur avendo disponibili dei dati, non viene dato per pronto in + lettura.} + + + +\subsection{Un esempio di I/O multiplexing} +\label{sec:TCP_multiplex_example} + +Abbiamo incontrato la problematica tipica che conduce all'uso dell'I/O +multiplexing nella nostra analisi degli errori in +\secref{sec:TCP_conn_early_abort}, quando il nostro client non era in grado di +rendersi conto di errori sulla connessione essendo impegnato nella attesa di +dati in ingresso dallo standard input. + +In questo caso il problema è quello di dover tenere sotto controllo due +diversi file descriptor, lo standard input, da cui viene letto il testo che +vogliamo inviare al server, e il socket connesso con il server su cui detto +testo sarà scritto e dal quale poi si vorrà ricevere la risposta. L'uso +dell'I/O multiplexing consente di tenere sotto controllo entrambi, senza +restare bloccati. + +Nel nostro caso quello che ci interessa è non essere bloccati in lettura sullo +standard input in caso di errori sulla connessione o chiusura della stessa da +parte del server. Entrambi questi casi possono essere rilevati usando +\func{select}, per quanto detto in \secref{sec:TCP_sock_select}, mettendo +sotto osservazione i file descriptor per la condizione di essere pronti in +lettura: sia infatti che si ricevano dati, che la connessione sia chiusa +regolarmente (con la ricezione di un segmento FIN) che si riceva una +condizione di errore (con un segmento RST) il socket connesso sarà pronto in +lettura (nell'ultimo caso anche in scrittura, ma questo non è necessario ai +nostri scopi). + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/ClientEcho_third.c} + \end{minipage} + \normalsize + \caption{La sezione nel codice della terza versione della funzione + \func{ClientEcho} usata dal client per il servizio \textit{echo} + modificata per l'uso di \func{select}.} + \label{fig:TCP_ClientEcho_third} +\end{figure} + +Riprendiamo allora il codice del client, modificandolo per l'uso di +\func{select}. Quello che dobbiamo modificare è la funzione \func{ClientEcho} +di \figref{fig:TCP_ClientEcho_second}, dato che tutto il resto, che riguarda +le modalità in cui viene stabilita la connessione con il server, resta +assolutamente identico. La nostra nuova versione di \func{ClientEcho}, la +terza della serie, è riportata in \figref{fig:TCP_ClientEcho_third}. + +In questo caso la funzione comincia (\texttt{\small 8--9}) con la +cancellazione del file descriptor set \var{fset} e del valore \var{maxfd} da +passare a \func{select} come massimo per il numero dei file descriptor. Per +quest'ultimo si usa la macro \code{max} definita nel nostro file +\file{macro.h} che raccoglie una collezione di macro di preprocessore di varia +utilità. + +La funzione prosegue poi (\texttt{\small 10--41}) con il ciclo principale, che +viene ripetuto indefinitamente. Per ogni ciclo si reinizializza +(\texttt{\small 11--12}) il file descriptor set, impostando i valori per il +file descriptor associato al socket \var{socket} e per lo standard input (il +cui valore si recupera con la funzione \func{fileno}). Questo è necessario in +quanto la successiva (\texttt{\small 13}) chiamata a \func{select} comporta +una modifica dei due bit relativi, che quindi devono essere reimpostati. + +Si noti come la chiamata a \func{select} venga eseguita usando come primo +argomento il valore di \var{maxfd}, precedentemente calcolato, passando poi il +solo file descriptor set per il controllo dell'attività in lettura, gli altri +argomenti sono tutti passati come puntatori nulli non interessando né il +controllo delle altre attività, né l'impostazione di un valore di timeout. + +Al ritorno di \func{select} si provvede a controllare quale dei file +descriptor presneta attività, si comincia (\texttt{\small 14--24}) con il file +descriptor associato allo standard input. In caso di attività (quando cioè +\macro{FD_ISSET} ritorna una valore diverso da zero) si esegue (\texttt{\small + 15}) una \func{fgets} per leggere gli eventuali dati presenti; se non ve ne +sono (e la funzione restituisce pertanto un puntatore nullo) si ritorna +immediatamente (\texttt{\small 16}) dato che questo significa che si è chiuso +lo standard input; altrimenti (\texttt{\small 18--22}) si scrivono i dati sul +socket, uscendo immediatamente in caso di errore di scrittura. + +Controllato lo standard input si passa a controllare (\texttt{\small 25--40}) +il socket connesso, in caso di attività si esegue (\texttt{\small 26}) subito +una \func{read} di cui si controlla il valore di ritorno; se questo è negativo +(\texttt{\small 27--30}) si è avuto un errore e pertanto si esce +immediatamente segnalandolo, se è nullo (\texttt{\small 31--34}) \section{Le opzioni dei socket} @@ -141,13 +227,13 @@ quando c' Dato che la maggior parte delle opzioni dei socket sono relative ai socket TCP, ed hanno poi significato analogo quando usate con altri socket, abbiamo -preferito trattare l'argomento in generale in questa sezione piuttosto che -nel capitolo dedicato alla trattazione generica dei socket. +preferito trattare l'argomento in generale in questa sezione piuttosto che nel +capitolo dedicato alla trattazione generica dei socket. \section{I dati \textit{out-of-band}} -\label{sec:TCP_outofband} +\label{sec:TCP_urgent_data} Una caratteristica speciale dei socket TCP è quella della presenza dei cosiddetti dati \textit{out-of-band}