X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsockadv.tex;h=24c45d2cbf9d1aa707fec08f248fbb4e5703530e;hp=81c37eb5bc981d8f912ea56cdb414f7e10634040;hb=fcd431ebcd9f7a65680a669a2740ef5a2586531c;hpb=b99370b46df36884995d94ed00de41aa51b4e027 diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 81c37eb..24c45d2 100644 --- a/tcpsockadv.tex +++ b/tcpsockadv.tex @@ -35,25 +35,103 @@ riprenderemo l'argomento in questa sezione. -\subsection{La funzione \func{select} con i socket.} +\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 -\secref{sec:file_multiplexing}; e sappiamo che la funzione ritorna quando uno -o più dei file descriptor messi sotto controllo è pronto per la relativa -operazione. +\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 se 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}. - +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}. + +Le condizioni che fanno si che la funzione \func{select} ritorni segnalando +che un socket (che sarà riportato nel primo insieme di file descriptor) è +pronto per la lettura sono le seguenti: +\begin{itemize*} +\item nel buffer di ricezione del socket sono arrivati dei dati in quantità + sufficiente a superare il valore di una \textsl{soglia di basso livello} (il + cosiddetto \textit{low watermark}). Questo valore è espresso in numero di + byte e può essere impostato con l'opzione del socket \const{SO\_RCVLOWAT} + (tratteremo le opzioni dei socket in \secref{sec:TCP_sock_options}); il suo + valore di default è 1 per i socket TCP e UDP. In questo caso una operazione + di lettura avrà successo e leggerà un numero di byte maggiore di zero. +\item il lato in lettura della connessione è stato chiuso; si è cioè ricevuto + un segmento FIN (si ricordi quanto illustrato in \secref{sec:TCP_conn_term}) + sulla connessione. In questo caso una operazione di lettura avrà successo, + ma non risulteranno presenti dati (in sostanza \func{read} ritornerà con un + valore nullo) per indicare la condizione di end-of-file. +\item c'è stato un errore sul socket. In questo caso una operazione di lettura + non si bloccherà ma restituirà una condizione di errore (ad esempio + \func{read} restituirà -1) e imposterà la variabile \var{errno} al relativo + valore. Vedremo in \secref{sec:TCP_sock_options} come sia possibile estrarre + e cancellare errori pendenti su un socket usando l'opzione + \const{SO\_ERROR}. +\item quando si sta utilizzando un \textit{listening socket} ed ci sono delle + connessioni completate. In questo caso la funzione \func{accept} non si + bloccherà.\footnote{in realtà questo non è sempre vero, come accennato in + \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.} +\end{itemize*} + +Le condizioni che fanno si che la funzione \func{select} ritorni segnalando +che un socket (che sarà riportato nel secondo insieme di file descriptor) è +pronto per la scrittura sono le seguenti: +\begin{itemize*} +\item nel buffer di invio è disponibile una quantità di spazio superiore al + valore della \textsl{soglia di basso livello} in scrittura ed inoltre o il + socket è già connesso o non necessita (ad esempio è UDP) di connessione. Il + valore della soglia è espresso in numero di byte e può essere impostato con + l'opzione del socket \const{SO\_SNDLOWAT}; il suo valore di default è 2048 + per i socket TCP e UDP. In questo caso una operazione di scrittura non si + bloccherà e restituirà un valore positivo pari al numero di byte accettati + dal livello di trasporto. +\item il lato in scrittura della connessione è stato chiuso. In questo caso + una operazione di scrittura sul socket genererà il segnale \const{SIGPIPE}. +\item c'è stato un errore sul socket. In questo caso una operazione di + scrittura non si bloccherà ma restituirà una condizione di errore ed + imposterà opportunamente la variabile \var{errno}. Vedremo in + \secref{sec:TCP_sock_options} come sia possibile estrarre e cancellare + errori pendenti su un socket usando l'opzione \const{SO\_ERROR}. +\end{itemize*} + +Infine c'è una sola condizione che fa si che \func{select} ritorni segnalando +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}. + +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. + +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 +dei programmi, se infatti si sa che una applicazione non è in grado di fare +niente fintanto che non può ricevere o inviare una certa quantità di dati, si +possono utilizzare questi valori per far si che \func{select} ritorni solo +quando c'è la certezza di avere dati a sufficienza.\footnote{questo tipo di + controllo è utile di norma solo per la lettura, in quanto in genere le + operazioni di scrittura sono già controllate dall'applicazione, che sà + 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.} @@ -62,8 +140,9 @@ un socket risulta \textsl{pronto}. \label{sec:TCP_sock_options} Dato che la maggior parte delle opzioni dei socket sono relative ai socket -TCP, ed hanno poi significato analogo quando usate con altri socket, -tratteremo qui l'argomento in generale. +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.