X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsockadv.tex;h=d22c6aa84ab43a5696de32e2346915e11a11424c;hp=24c45d2cbf9d1aa707fec08f248fbb4e5703530e;hb=d25090faca15102552d77c38161a8a34b0bac41e;hpb=fcd431ebcd9f7a65680a669a2740ef5a2586531c diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 24c45d2..d22c6aa 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,29 +131,174 @@ 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.} - - - - -\section{Le opzioni dei socket} -\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, abbiamo -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} - -Una caratteristica speciale dei socket TCP è quella della presenza dei -cosiddetti dati \textit{out-of-band} - + 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}, il codice +completo si trova nel file \file{TCP\_echo\_third.c} dei sorgenti allegati alla +guida. + +In questo caso la funzione comincia (\texttt{\small 8--9}) con l'azzeramento +del file descriptor set \var{fset} e l'impostazione del valore \var{maxfd}, da +passare a \func{select} come massimo per il numero di file descriptor. Per +determinare 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 +all'inizio di ogni ciclo. + +Si noti come la chiamata a \func{select} venga eseguita usando come primo +argomento il valore di \var{maxfd}, precedentemente calcolato, e passando poi +il solo file descriptor set per il controllo dell'attività in lettura, negli +altri argomenti sono passati tutti 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 due file +descriptor presenta attività in lettura, cominciando (\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 e quindi concluso l'utilizzo del client; altrimenti +(\texttt{\small 18--22}) si scrivono i dati appena letti sul socket, +prevedendo una uscita immediata 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à (\texttt{\small 26}) si esegue 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}) significa che +il server ha chiuso la connessione, e di nuovo si esce con stampando prima un +messaggio di avviso, altrimenti (\texttt{\small 35--39}) si effettua la +terminazione della stringa e la si stampa a sullo standard output (uscendo in +caso di errore), per ripetere il ciclo da capo. + +Con questo meccanismo il programma invece di essere bloccato in lettura sullo +standard input resta bloccato sulla \func{select}, che ritorna soltanto quando +viene rilevata attività su uno dei due file descriptor posti sotto controllo. +Questo di norma avviene solo quando si è scritto qualcosa sullo standard +input, o quando si riceve dal socket la risposta a quanto si era appena +scritto. Ma adesso il client diventa capace di accorgersi immediatamente della +terminazione del server; in tal caso infatti il server chiuderà il socket +connesso, ed alla ricezione del FIN la funzione \func{select} ritornerà (come +illustrato in \secref{sec:TCP_sock_select}) segnalando una condizione di end +of file, per cui il nostro client potrà uscire immediatamente. + +Riprendiamo la situazione affrontata in \secref{sec:TCP_server_crash}, +terminando il server durante una connessione, in questo caso quello che +otterremo, una volta scritta una prima riga ed interrotto il server con un +\texttt{C-c}, sarà: +\begin{verbatim} +[piccardi@gont sources]$ ./echo 192.168.1.1 +Prima riga +Prima riga +EOF sul socket +\end{verbatim}%$ +dove l'ultima riga compare immediatamente dopo aver interrotto il server. Il +nostro client infatti è in grado di accorgersi immediatamente che il socket +connesso è stato chiuso ed uscire immediatamente. + +Veniamo allora agli altri scenari di terminazione anomala visti in +\secref{sec:TCP_conn_crash}. Il primo di questi è l'interruzione fisica della +connessione; in questo caso avremo un comportamento analogo al precedente, in +cui si scrive una riga e non si riceve risposta dal server e non succede +niente fino a quando non si riceve un errore di \errcode{EHOSTUNREACH} o +\errcode{ETIMEDOUT} a seconda dei casi. + +La differenza è che stavolta potremo scrivere più righe dopo l'interruzione, +in quanto il nostro client dopo aver inviato i dati non si bloccherà più nella +lettura dal socket, ma nella \func{select}; per questo potrà accettare +ulteriore dati che scriverà di nuovo sul socket, fintanto che c'è spazio sul +buffer di uscita (ecceduto il quale si bloccherà in scrittura). Si ricordi +infatti che il client non ha modo di determinare se la connessione è attiva o +meno (dato che in molte situazioni reali l'inattività può essere temporanea). +Tra l'altro se si ricollega la rete prima della scadenza del timeout, potremo +anche verificare come tutto quello che si era scritto viene poi effettivamente +trasmesso non appena la connessione ridiventa attiva, per cui otterremo +qualcosa del tipo: +\begin{verbatim} +[piccardi@gont sources]$ ./echo 192.168.1.1 +Prima riga +Prima riga +Seconda riga dopo l'interruzione +Terza riga +Quarta riga +Seconda riga dopo l'interruzione +Terza riga +Quarta riga +\end{verbatim} +in cui, una volta riconnessa la rete, tutto quello che abbiamo scritto durante +il periodo di disconnessione restituito indietro e stampato immediatamente. + +Lo stesso comportamento visto in \secref{sec:TCP_server_crash} si riottiene +nel caso di un crollo completo della macchina su cui sta il server. In questo +caso di nuovo il client non è in grado di accorgersi di niente dato che si +suppone che il programma server non venga terminato correttamente, ma si +blocchi tutto senza la possibilità di avere l'emissione di un segmento FIN che +segnala la terminazione della connessione. Di nuovo fintanto che la +connessione non si riattiva )con il riavvio della macchina del server) il +client non è in grado di fare altro che accettare dell'input e tentare di +inviarlo. La differenza in questo caso è che non appena la connessione +ridiventa attiva i dati verranno sì trasmessi, ma essendo state perse tutte le +informazioni relative alle precedenti connessioni ai tentativi di scrittura +del client sarà risposto con un segmento RST che provocherà il ritorno di +\func{select} per la ricezione di un errore di \errcode{ECONNRESET}. \subsection{La funzione \func{shutdown}} @@ -175,7 +322,198 @@ Questa Il problema che si pone è che se la chiusura del socket è effettuata con la funzione \func{close}, come spiegato in \secref{sec:TCP_func_close}, si perde ogni possibilità di poter rileggere quanto l'altro capo può continuare a -scrivere. Per poter permettere allora +scrivere. Per poter permettere allora di segnalare che si è concluso con la +scrittura, continuando al contempo a leggere quanto può provenire dall'altro +capo del socket si può allora usare la funzione \funcd{shutdown}, il cui +prototipo è: +\begin{prototype}{sys/socket.h} +{int shutdown(int sockfd, int how)} + +Chiude un lato della connessione fra due socket. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori: + \begin{errlist} + \item[\errcode{ENOTSOCK}] il file descriptor non corrisponde a un socket. + \item[\errcode{ENOTCONN}] il socket non è connesso. + \end{errlist} + ed inoltre \errval{EBADF}.} +\end{prototype} + +La funzione prende come primo argomento il socket \param{sockfd} su cui si +vuole operare e come secondo argomento un valore intero \param{how} che indica +la modalità di chiusura del socket, quest'ultima può prendere soltanto tre +valori: +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} +\item[\macro{SHUT\_RD}] chiude il lato in lettura del socket, non sarà più + possibile leggere dati da esso, tutti gli eventuali dati trasmessi + dall'altro capo del socket saranno automaticamente scartati dal kernel, che, + in caso di socket TCP, provvederà comunque ad inviare i relativi segmenti di + ACK. +\item[\macro{SHUT\_WR}] chiude il lato in scrittura del socket, non sarà più + possibile scrivere dati su di esso. Nel caso di socket TCP la chiamata causa + l'emissione di un segmento FIN, secondo la procedura chiamata + \textit{half-close}. Tutti i dati presenti nel buffer di scrittura prima + della chiamata saranno inviati, seguiti dalla sequenza di chiusura + illustrata in \secref{sec:TCP_conn_term}. +\item[\macro{SHUT\_RDWR}] chiude sia il lato in lettura che quello in + scrittura del socket. È equivalente alla chiamata in sequenza con + \macro{SHUT\_RD} e \macro{SHUT\_WR}. +\end{basedescript} + +Ci si può chiedere quale sia l'utilità di avere introdotto \macro{SHUT\_RDWR} +quando questa sembra rendere \funcd{shutdown} del tutto equivalente ad una +\func{close}. In realtà non è così, esiste infatti un'altra differenza con +\func{close}, più sottile. Finora infatti non ci siamo presi la briga di +sottolineare in maniera esplicita che come per i file e le fifo, anche per i +socket possono esserci più riferimenti contemporanei ad uno stesso socket. Per +cui si avrebbe potuto avere l'impressione che sia una corrispondenza univoca +fra un socket ed il file descriptor con cui vi si accede. Questo non è +assolutamente vero, (e lo abbiamo già visto nel codice del server di +\figref{fig:TCP_echo_server_first_code}), ed è invece assolutamente normale +che, come per gli altri oggetti, ci possano essere più file descriptor che +fanno riferimento allo stesso socket. + +Allora se avviene uno di questi casi quello che succederà è che la chiamata a +\func{close} darà effettivamente avvio alla sequenza di chiusura di un socket +soltanto quando il numero di riferimenti a quest'ultimo diventerà nullo. +Fintanto che ci sono file descriptor che fanno riferimento ad un socket +\func{close} si limiterà a deallocare nel processo corrente il file descriptor +utilizzato, ma il socket resterà pienamente accessibile attraverso gli altri +riferimenti.Se torniamo all'esempio di \figref{fig:TCP_echo_server_first_code} +abbiamo infatti che le due \func{close} (sul socket connesso nel padre e sul +socket in ascolto nel figlio), restando comunque altri riferimenti attivi (al +socket connesso nel figlio e a quello in ascolto nel padre) non effettuano +nessuna chiusura effettiva. + +Questo non avviene affatto se si usa \func{shutdown} al posto di \func{close}, +in questo caso infatti la chiusura del socket viene effettuata immediatamente, +indipendentemente dalla presenza di altri riferimenti attivi, e pertanto sarà +ovviamente efficace anche per tutti gli altri file descriptor con cui si fa +riferimento allo stesso socket. + +Il caso più comune di uso di \func{shutdown} è comunque quello della chiusura +del lato in scrittura, per segnalare all'altro capo della connessione che si è +concluso l'invio dei dati, restando comunque in grado di ricevere quanto +ancora questi potrà inviarci. Questo è ad esempio l'uso che ci serve per +rendere finalmente completo il nostro esempio sul servizio echo. Il nostro +client infatti presenta ancora un problema, che nell'uso che finora ne abbiamo +fatto non è emerso, ma che ci aspetta dietro l'angolo non appena usciamo +dall'uso interattivo e proviamo ad eseguirlo redirigendo standard input e +standard output. Così se eseguiamo: +\begin{verbatim} +[piccardi@gont sources]$ ./echo 192.168.1.1 < ../fileadv.tex > copia +\end{verbatim}%$ +vedremo che il file \texttt{copia} risulta mancare della parte finale. + +Per capire cosa avviene in questo caso occorre tenere presente come avviene la +comunicazione via rete; quando redirigiamo lo standard input il nostro client +inizierà a leggere il contenuto del file \texttt{../fileadv.tex} a blocchi di +dimensione massima pari a \texttt{MAXLINE} per poi scriverlo, alla massima +velocità consentitagli dalla rete, sul socket. Dato che la connessione è con +una macchina remota occorre un certo tempo perché i pacchetti vi arrivino, +vengano processati, e poi tornino indietro. Considerando trascurabile il tempo +di processo, questo tempo, detto RTT (da \textit{Round Trip Time} può essere +stimato con l'uso del comando \cmd{ping}. Ma mantre il pacchetti sono in +transito sulla rete il client continua a leggere e a scrivere fintanto che il +file in ingresso finisce. + +A questo punto, se torniamo al codice mostrato in +\figref{fig:TCP_ClientEcho_third}, notiamo che non appena viene ricevuto un +end-of-file in ingresso il nostro client termina. Nel caso interattivo, in cui +si inviavano brevi stringe una alla volta, c'era sempre il tempo di eseguire +la lettura completa di quanto il server rimandava indietro. In questo caso +però quando il client termina, essendo la comunicazione a piena velocità, ci +saranno ancora pacchetti in transito sulla rete, ma siccome il client esce +immediatamente dopo la fine del file in ingresso, questi non faranno a tempo a +completare il percorso e verranno persi. + +Per evitare questo tipo di problema occorre, invece di uscire, usare +\func{shutdown} per effettuare la chiusura del socket in scrittura una volta +completata la lettura del file in ingresso. In questo modo il client segnalerà +al server la chiusura del flusso dei dati, ma potrà continuare a leggere +quanto il server gli sta ancora inviando fino a quando quest'ultimo, +riconosciuta la chiusura del socket in scrittura da parte del client, +effettuerà la chiusura dello stesso a sua volta. Solo alla ricezione della +chiusura del socket da parte del server, si potrà essere sicuri della +ricezione di tutti i dati prima della terminazione della connessione. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/ClientEcho.c} + \end{minipage} + \normalsize + \caption{La sezione nel codice della versione finale della funzione + \func{ClientEcho}, che usa \func{shutdown} per una conclusione corretta + della connessione.} + \label{fig:TCP_ClientEcho} +\end{figure} + +Si è allora riportato in \figref{fig:TCP_ClientEcho} la versione finale della +nostra funzione \func{ClientEcho}, in grado di gestire correttamente l'intero +flusso di dati fra client e server. Il codice completo del client, +comprendente la gestione delle opzioni a riga di comando e le istruzioni per +la creazione della connessione, si trova nel file \file{TCP\_echo.c}, +distribuito coi sorgenti allegati alla guida. + +La nuova versione è molto simile alla precedente di +\figref{fig:TCP_ClientEcho_third}; la prima differenza è l'introduzione +(\texttt{\small 7}) della variabile \var{eof}, inizializzata ad un valore +nullo, che serve a mantenere traccia dell'avvenuta conclusione della lettura +del file in ingresso. + +La seconda modifica (\texttt{\small 12--15}) è stata quella di rendere +subordinato ad un valore nullo di \var{eof} l'impostazione del file descriptor +set per l'osservazione dello standard input. Se infatti il valore di \var{eof} +è non nullo significa che si è già raggiunta la fine del file in ingresso ed è +pertanto inutile continuare a tenere sotto controllo lo standard input nella +successiva (\texttt{\small 16}) chiamata a \func{select}. + +Le maggiori modifiche rispetto alla precedente versione sono invece nella +gestione (\texttt{\small 18--22}) del caso in cui la lettura con \func{fgets} +restitisca un valore nullo, indice della fine del file, che prima causava +l'immediato ritorno della funzione. In questo caso prima (\texttt{\small 19}) +si imposta opportunamente \var{eof} ad un valore non nullo, dopo di che +(\texttt{\small 20}) si effettua la chiusura del lato in scrittura del socket +con \func{shutdown}. Infine (\texttt{\small 21}) si usa la macro +\macro{FD\_CLR} per togliere lo standard input dal file descriptor set. + +In questo modo anche se la lettura del file in ingresso è conclusa, la +funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua +ad eseguirlo ripetendo la chiamata a \func{select} per tenere sotto controllo +soltanto il socket connesso, dal quale possono arrivare altri dati, che +saranno letti (\texttt{\small 31}), ed opportunamente trascritti +(\texttt{\small 44--48}) sullo standard input. + +Il ritorno della funzione, e la conseguente terminazione normale del client, +viene invece adesso gestito all'interno (\texttt{\small 30--49}) della lettura +dei dati dal socket; se infatti dalla lettura del socket si riceve una +condizione di end-of-file, la si tratterà (\texttt{\small 36--43}) in maniera +diversa a seconda del valore di \var{eof}. Se infatti questa è diversa da zero +(\texttt{\small 37--39}), essendo stata completata la lettura del file in +ingresso, vorrà dire che anche il server ha concluso la trasmissione dei dati +restanti, e si potrà uscire senza errori, altrimenti si stamperà +(\texttt{\small 40--42}) un messaggio di errore per la chiusura precoce della +connesione. + + + +\section{Le opzioni dei socket} +\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, abbiamo +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_urgent_data} + +Una caratteristica speciale dei socket TCP è quella della presenza dei +cosiddetti dati \textit{out-of-band}