X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsock.tex;h=8118b1e49db1067d5ae69627623a2daac271e736;hp=dfa8540bf72873a0369106d839ff6fe9115d0378;hb=beece18eba2dcc2a9b915dab61277df8685a3da6;hpb=9949b501aea36905b12f069e11743b70b3e2df57 diff --git a/tcpsock.tex b/tcpsock.tex index dfa8540..8118b1e 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -1325,9 +1325,10 @@ disponibile fra i sorgenti allegati alla guida nei file \file{FullRead.c} e Come si può notare le due funzioni ripetono la lettura/scrittura in un ciclo fino all'esaurimento del numero di byte richiesti, in caso di errore viene -controllato se questo è \errcode{EINTR} (cioè un'interruzione della system -call dovuta ad un segnale), nel qual caso l'accesso viene ripetuto, altrimenti -l'errore viene ritornato al programma chiamante, interrompendo il ciclo. +controllato se questo è \errcode{EINTR} (cioè un'interruzione della +\textit{system call} dovuta ad un segnale), nel qual caso l'accesso viene +ripetuto, altrimenti l'errore viene ritornato al programma chiamante, +interrompendo il ciclo. Nel caso della lettura, se il numero di byte letti è zero, significa che si è arrivati alla fine del file (per i socket questo significa in genere che @@ -2062,11 +2063,11 @@ all'esempio illustrato in fig.~\ref{fig:TCP_echo_server_first_code}. In questo modo però si introduce un altro problema. Si ricordi infatti che, come spiegato in sez.~\ref{sec:sig_gen_beha}, quando un programma si trova in -stato di \texttt{sleep} durante l'esecuzione di una system call, questa viene -interrotta alla ricezione di un segnale. Per questo motivo, alla fine -dell'esecuzione del gestore del segnale, se questo ritorna, il programma -riprenderà l'esecuzione ritornando dalla system call interrotta con un errore -di \errcode{EINTR}. +stato di \texttt{sleep} durante l'esecuzione di una \textit{system call}, +questa viene interrotta alla ricezione di un segnale. Per questo motivo, alla +fine dell'esecuzione del gestore del segnale, se questo ritorna, il programma +riprenderà l'esecuzione ritornando dalla \textit{system call} interrotta con +un errore di \errcode{EINTR}. Vediamo allora cosa comporta tutto questo nel nostro caso: quando si chiude il client, il processo figlio che gestisce la connessione terminerà, ed il padre, @@ -2083,13 +2084,13 @@ accept error: Interrupted system call \end{verbatim}%# Come accennato in sez.~\ref{sec:sig_gen_beha} le conseguenze di questo -comportamento delle system call possono essere superate in due modi diversi, -il più semplice è quello di modificare il codice di \func{Signal} per -richiedere il riavvio automatico delle system call interrotte secondo la -semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction}; -rispetto a quanto visto in fig.~\ref{fig:sig_Signal_code}. Definiremo allora la -nuova funzione \func{SignalRestart}\footnote{anche questa è definita, insieme - alle altre funzioni riguardanti la gestione dei segnali, nel file +comportamento delle \textit{system call} possono essere superate in due modi +diversi, il più semplice è quello di modificare il codice di \func{Signal} per +richiedere il riavvio automatico delle \textit{system call} interrotte secondo +la semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction}; +rispetto a quanto visto in fig.~\ref{fig:sig_Signal_code}. Definiremo allora +la nuova funzione \func{SignalRestart}\footnote{anche questa è definita, + insieme alle altre funzioni riguardanti la gestione dei segnali, nel file \file{SigHand.c}, il cui contento completo può essere trovato negli esempi allegati.} come mostrato in fig.~\ref{fig:sig_SignalRestart_code}, ed installeremo il gestore usando quest'ultima. @@ -2101,30 +2102,30 @@ installeremo il gestore usando quest'ultima. \end{minipage} \normalsize \caption{La funzione \func{SignalRestart}, che installa un gestore di - segnali in semantica BSD per il riavvio automatico delle system call - interrotte.} + segnali in semantica BSD per il riavvio automatico delle \textit{system + call} interrotte.} \label{fig:sig_SignalRestart_code} \end{figure} Come si può notare questa funzione è identica alla precedente \func{Signal}, -illustrata in fig.~\ref{fig:sig_Signal_code}, solo che in questo caso invece di -inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si +illustrata in fig.~\ref{fig:sig_Signal_code}, solo che in questo caso invece +di inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si inizializza (\texttt{\small 5}) al valore \const{SA\_RESTART}. Usando questa funzione al posto di \func{Signal} nel server non è necessaria nessuna altra -modifica: le system call interrotte saranno automaticamente riavviate, e -l'errore \errcode{EINTR} non si manifesterà più. +modifica: le \textit{system call} interrotte saranno automaticamente +riavviate, e l'errore \errcode{EINTR} non si manifesterà più. La seconda soluzione è più invasiva e richiede di controllare tutte le volte -l'errore restituito dalle varie system call, ripetendo la chiamata qualora -questo corrisponda ad \errcode{EINTR}. Questa soluzione ha però il pregio -della portabilità, infatti lo standard POSIX dice che la funzionalità di -riavvio automatico delle system call, fornita da \const{SA\_RESTART}, è -opzionale, per cui non è detto che essa sia disponibile su qualunque sistema. -Inoltre in certi casi,\footnote{Stevens in \cite{UNP1} accenna che la maggior - parte degli Unix derivati da BSD non fanno ripartire \func{select}; altri - non riavviano neanche \func{accept} e \func{recvfrom}, cosa che invece nel - caso di Linux viene sempre fatta.} anche quando questa è presente, non è -detto possa essere usata con \func{accept}. +l'errore restituito dalle varie \textit{system call}, ripetendo la chiamata +qualora questo corrisponda ad \errcode{EINTR}. Questa soluzione ha però il +pregio della portabilità, infatti lo standard POSIX dice che la funzionalità +di riavvio automatico delle \textit{system call}, fornita da +\const{SA\_RESTART}, è opzionale, per cui non è detto che essa sia disponibile +su qualunque sistema. Inoltre in certi casi,\footnote{Stevens in \cite{UNP1} + accenna che la maggior parte degli Unix derivati da BSD non fanno ripartire + \func{select}; altri non riavviano neanche \func{accept} e \func{recvfrom}, + cosa che invece nel caso di Linux viene sempre fatta.} anche quando questa è +presente, non è detto possa essere usata con \func{accept}. La portabilità nella gestione dei segnali però viene al costo di una @@ -2160,7 +2161,7 @@ programma. \normalsize \caption{La sezione nel codice della seconda versione del server per il servizio \textit{echo} modificata per tener conto dell'interruzione - delle system call.} + delle \textit{system call}.} \label{fig:TCP_echo_server_code_second} \end{figure} @@ -2182,12 +2183,12 @@ eventuale pausa con una condizione (\texttt{\small 21}) sulla variabile numero di secondi da aspettare (il valore preimpostato è nullo). Si è potuto lasciare inalterata tutta la sezione di creazione del socket -perché nel server l'unica chiamata ad una system call lenta, che può essere -interrotta dall'arrivo di \signal{SIGCHLD}, è quella ad \func{accept}, che è -l'unica funzione che può mettere il processo padre in stato di sleep nel +perché nel server l'unica chiamata ad una \textit{system call} lenta, che può +essere interrotta dall'arrivo di \signal{SIGCHLD}, è quella ad \func{accept}, +che è l'unica funzione che può mettere il processo padre in stato di sleep nel periodo in cui un figlio può terminare; si noti infatti come le altre -\index{system~call~lente} \textit{slow system call}\footnote{si ricordi la - distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di +\index{system~call~lente} \textit{system call} lente (si ricordi la +distinzione fatta in sez.~\ref{sec:sig_gen_beha}) o sono chiamate prima di entrare nel ciclo principale, quando ancora non esistono processi figli, o sono chiamate dai figli stessi e non risentono di \signal{SIGCHLD}. @@ -2467,15 +2468,16 @@ avanti in sez.~\ref{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 argomento un - altro comando e ne stampa a video tutte le invocazioni di una system call, - coi relativi argomenti e valori di ritorno, per cui usandolo in questo - contesto potremo verificare che effettivamente la \func{write} ha scritto la - riga, che in effetti è stata pure trasmessa via rete.}), in quanto il nostro -programma non ha a questo punto alcun modo di sapere che dall'altra parte non -c'è più nessuno processo in grado di leggere quanto scriverà. Questo sarà -chiaro solo dopo il tentativo di scrittura, e la ricezione del segmento RST di -risposta che indica che dall'altra parte non si è semplicemente chiuso un capo -del socket, ma è completamente terminato il programma. + altro comando e ne stampa a video tutte le invocazioni di una \textit{system + call}, coi relativi argomenti e valori di ritorno, per cui usandolo in + questo contesto potremo verificare che effettivamente la \func{write} ha + scritto la riga, che in effetti è stata pure trasmessa via rete.}), in +quanto il nostro programma non ha a questo punto alcun modo di sapere che +dall'altra parte non c'è più nessuno processo in grado di leggere quanto +scriverà. Questo sarà chiaro solo dopo il tentativo di scrittura, e la +ricezione del segmento RST di risposta che indica che dall'altra parte non si +è semplicemente chiuso un capo del socket, ma è completamente terminato il +programma. Per questo motivo il nostro client proseguirà leggendo dal socket, e dato che questo è stato chiuso avremo che, come spiegato in