Uno dei problemi che si presentano con l'uso di \func{select} è che il suo
comportamento dipende dal valore del file descriptor che si vuole tenere sotto
-controllo. Infatti il kernel riceve solo un valore massimo, e dovrà
-effettuare una scansione su tutto l'intervallo, che può essere anche molto
-ampio, per capire quali sono i file descriptor da tenere sotto controllo,
-anche se sono solo poche unità; e questo ha ovviamente un pessimo risultato
-per le prestazioni; il comportamenento viene della funzione viene così a
-dipendere in maniera innaturale dal valore del file decriptor.
+controllo. Infatti il kernel riceve con \param{n} un valore massimo per tale
+valore, e per capire quali sono i file descriptor da tenere sotto controllo
+dovrà effettuare una scansione su tutto l'intervallo, che può anche essere
+anche molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
+ha ovviamente delle conseguenze ampiamente negative per le prestazioni.
Inoltre c'è anche il problema che il numero massimo dei file che si possono
tenere sotto controllo, la funzione è nata quando il kernel consentiva un
\begin{table}[htb]
\centering
\footnotesize
- \begin{tabular}[c]{|l|c|l|}
+ \begin{tabular}[c]{|l|l|}
\hline
- \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\
+ \textbf{Flag} & \textbf{Significato} \\
\hline
\hline
- \const{POLLIN} & 0x001 & È possibile la lettura immediata.\\
- \const{POLLPRI} & 0x002 & Sono presenti dati urgenti.\\
- \const{POLLOUT} & 0x004 & È possibile la scrittura immediata.\\
+ \const{POLLIN} & È possibile la lettura immediata.\\
+ \const{POLLPRI} & Sono presenti dati urgenti.\\
+ \const{POLLOUT} & È possibile la scrittura immediata.\\
\hline
- \const{POLLERR} & 0x008 & C'è una condizione di errore.\\
- \const{POLLHUP} & 0x010 & Si è verificato un hung-up.\\
- \const{POLLNVAL} & 0x020 & Il file descriptor non è aperto.\\
+ \const{POLLERR} & C'è una condizione di errore.\\
+ \const{POLLHUP} & Si è verificato un hung-up.\\
+ \const{POLLNVAL} & Il file descriptor non è aperto.\\
\hline
- \const{POLLRDNORM}& 0x040 & Sono disponibili in lettura dati normali.\\
- \const{POLLRDBAND}& 0x080 & Sono disponibili in lettura dati ad alta
- priorità. \\
- \const{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali. \\
- \const{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad
- alta priorità. \\
- \const{POLLMSG} & 0x400 & Un segnale \const{SIGPOLL} è arrivato alla
- cima dello stream.\\
+ \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\
+ \const{POLLRDBAND}& Sono disponibili in lettura dati ad alta
+ priorità. \\
+ \const{POLLWRNORM}& È possibile la scrittura di dati normali. \\
+ \const{POLLWRBAND}& È possibile la scrittura di dati ad
+ alta priorità. \\
+ \const{POLLMSG} & Un segnale \const{SIGPOLL} è arrivato alla
+ cima dello stream (non usato).\\
\hline
\end{tabular}
\caption{Costanti per l'identificazione dei vari bit dei campi
<tr>
<td valign="top"> <b> Cap. 10 </b> </td>
<td valign="top"> Sessioni e terminali</td>
- <td valign="top"> Sessioni complete, da revisionare,
+ <td valign="top"> sessioni complete, da revisionare,
terminali quasi completi. </td>
</tr>
<tr>
<tr>
<td valign="top"> <b> Cap. 12 </b> </td>
<td valign="top"> IPC </td>
- <td valign="top"> Pipe, fifo e code, semafori,
+ <td valign="top"> pipe, fifo e code, semafori,
memoria condivisa, tecniche alternative completi, da
revisionare, IPC POSIX quasi completo.
</td>
</tr>
<tr>
- <td valign="top"> <b> Cap. 13-14 </b> </td>
+ <td valign="top"> <b> Cap. 13 </b> </td>
<td valign="top"> Introduzione alla rete</td>
- <td valign="top"> completi, da revisionare </td>
+ <td valign="top"> completo, da revisionare </td>
+ </tr>
+ <tr>
+ <td valign="top"> <b> Cap. 14 </b> </td>
+ <td valign="top"> I socket</td>
+ <td valign="top"> completo, da revisionare. Manca la
+ trattazione di eventuali ulteriori famiglie. </td>
</tr>
<tr>
<td valign="top"> <b> Cap. 15-16 </b> </td>
- <td valign="top"> Socket TCP elementari</td>
- <td valign="top"> Caratteristiche base quasi complete,
- esempio elementare da concludere </td>
+ <td valign="top"> I socket TCP </td>
+ <td valign="top"> socket TCP elementari completo, da
+ revisionare. Socket TCP avanzati appena iniziato,
+ in fase di stesura.
+
+ </td>
+ </tr>
+ <tr>
+ <td valign="top"> <b> Appendici </b> </td>
+ <td valign="top"> I protocolli, gli errori, ecc.</td>
+ <td valign="top"> Materiale messo insieme alla
+ rinfusa, e da rivedere da zero.
+ </td>
</tr>
</tbody>
</table>
<p>
- <b> Versione corrente:</b> 473 pagine.
+ <b> Versione corrente:</b> 485 pagine.
</p>
</td>
</tr>
</b>
</td>
<td bgcolor="lightblue">
+
+ <b>21 - settembre - 2003</b> <br/> Completato il capitolo sui
+ socket elementari, e corretti numerosi errori. Revisione della
+ sezione sull'I/O multiplexing nel capitolo sui file avanzati in
+ vista dell'uso nel capitolo sui socket TCP avanzati.
<p>
<b>6 - aprile - 2003</b> <br/> Grazie all'incredibile lavoro di
Mirko Maischberger abbiamo una favolosa versione in HTML, che
è chiuso il socket dal lato che esegue la chiusura attiva; esistono tuttavia
situazioni in cui si vuole poter sfruttare questa possibilità, usando una
procedura che è chiamata \textit{half-close}; torneremo su questo aspetto e su
-come utilizzarlo in \secref{xxx_shutdown}, quando parleremo della funzione
+come utilizzarlo in \secref{sec:TCP_shutdown}, quando parleremo della funzione
\func{shutdown}.
La emissione del FIN avviene quando il socket viene chiuso, questo però non
sulla rete; questo tempo è limitato perché ogni pacchetto IP può essere
ritrasmesso dai router un numero massimo di volte (detto \textit{hop limit}).
Il numero di ritrasmissioni consentito è indicato dal campo TTL dell'header di
-IP (per maggiori dettagli vedi \secref{sec:IP_xxx}), e viene decrementato ad
-ogni passaggio da un router; quando si annulla il pacchetto viene scartato.
+IP (per maggiori dettagli vedi \secref{sec:ip_protocol}), e viene decrementato
+ad ogni passaggio da un router; quando si annulla il pacchetto viene scartato.
Siccome il numero è ad 8 bit il numero massimo di ``\textsl{salti}'' è di 255,
pertanto anche se il TTL (da \textit{time to live}) non è propriamente un
limite sul tempo di vita, si stima che un pacchetto IP non possa restare nella
in attesa il processo\footnote{a meno che non si sia impostato il socket per
essere non bloccante (vedi \secref{sec:file_noblocking}), nel qual caso
ritorna con l'errore \errcode{EAGAIN}. Torneremo su questa modalità di
- operazione in \secref{sec:xxx_sock_noblock}.} fintanto che non ne arriva
-una.
+ operazione in \secref{sec:TCP_sock_multiplexing}.} fintanto che non ne
+arriva una.
La funzione può essere usata solo con socket che supportino la connessione
(cioè di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET} o
Per attivare immediatamente l'emissione del FIN e la sequenza di chiusura
descritta in \secref{sec:TCP_conn_term}, si può invece usare la funzione
\func{shutdown} su cui torneremo in seguito (vedi
-\secref{sec:TCP_xxx_shutdown}).
+\secref{sec:TCP_shutdown}).
nell'output di \cmd{netstat}.
Come abbiamo accennato in \secref{sec:TCP_conn_term} e come vedremo più avanti
-in \secref{sec:TCP_xxx_shutdown} la chiusura di un solo capo di un socket è
+in \secref{sec:TCP_shutdown} la chiusura di un solo capo di un socket è
una operazione lecita, per cui la nostra scrittura avrà comunque successo
(come si può constatare lanciando usando \cmd{strace}\footnote{il comando
\cmd{strace} è un comando di debug molto utile che prende come parametro un
si vuole che il client sia in grado di accorgersi del crollo del server anche
quando non sta effettuando uno scambio di dati, è possibile usare una
impostazione speciale del socket (ci torneremo in
-\secref{sec:TCP_xxx_sockopt}) che provvede all'esecuzione di questo controllo.
+\secref{sec:TCP_sock_options}) che provvede all'esecuzione di questo
+controllo.
-\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.}
\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.