X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=elemtcp.tex;h=a49c48c5d0dbd8a5354cbc1cd7512eb3b3f2ecd8;hp=b366d5f12b0d08e5a46fb16684486dcfb315c752;hb=520fa6e7cd289a93a0955f3f91848ebd5b424250;hpb=49ae2790472cc2ad1e54ea26d037306598f9c83b diff --git a/elemtcp.tex b/elemtcp.tex index b366d5f..a49c48c 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -1821,8 +1821,8 @@ standard error. La gestione del servizio \textit{echo} viene effettuata interamente nella funzione \code{ServEcho}, il cui codice è mostrato in -\figref{fig:TCP_ServEcho}, e la comunicazione viene gestita all'interno di un -ciclo (\texttt{\small 6--13}). I dati inviati dal client vengono letti +\figref{fig:TCP_ServEcho_first}, e la comunicazione viene gestita all'interno +di un ciclo (\texttt{\small 6--13}). I dati inviati dal client vengono letti (\texttt{\small 6}) dal socket con una semplice \func{read}, di cui non si controlla lo stato di uscita, assumendo che ritorni solo in presenza di dati in arrivo. La riscrittura (\texttt{\small 7}) viene invece gestita dalla @@ -1839,11 +1839,11 @@ dati di cui \normalsize \caption{Codice della prima versione della funzione \code{ServEcho} per la gestione del servizio \textit{echo}.} - \label{fig:TCP_ServEcho} + \label{fig:TCP_ServEcho_first} \end{figure} In caso di errore di scrittura (si ricordi che \func{FullWrite} restituisce un -vamore nullo in caso di successo) si provvede (\texttt{\small 8--10}) a +valore nullo in caso di successo) si provvede (\texttt{\small 8--10}) a stampare il relativo messaggio con \func{PrintErr}. Quando il client chiude la connessione il ricevimento del FIN fa ritornare la \func{read} con un numero di byte letti pari a zero, il che causa l'uscita dal ciclo e il ritorno @@ -2009,13 +2009,13 @@ seguente codice: \includecodesnip{listati/sigchildhand.c} \noindent all'esempio illustrato in \figref{fig:TCP_echo_server_first_code}. -In questo modo però si introduce un altro problema, si ricordi infatti che, +In questo modo però si introduce un altro problema. Si ricordi infatti che, come spiegato in \secref{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 con un errore di -\errcode{EINTR}. +riprenderà l'esecuzione ritornando dalla 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, @@ -2031,16 +2031,17 @@ terminando a sua volta con un messaggio del tipo: accept error: Interrupted system call \end{verbatim}%# - Come accennato in \secref{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 \figref{fig:sig_Signal_code}. Definiremo allora la -nuova funzione \func{SignalRestart} come mostrato in -\figref{fig:sig_SignalRestart_code}, ed installeremo il gestore usando -quest'ultima. +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 \figref{fig:sig_SignalRestart_code}, ed +installeremo il gestore usando quest'ultima. \begin{figure}[!htb] \footnotesize \centering @@ -2055,12 +2056,12 @@ quest'ultima. \end{figure} Come si può notare questa funzione è identica alla precedente \func{Signal}, -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ù. +illustrata in \figref{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ù. La seconda soluzione è più invasiva e richiede di controllare tutte le volte l'errore restituito dalle varie system call, ripetendo la chiamata qualora @@ -2069,51 +2070,98 @@ della portabilit 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}, ed - alcuni non fanno ripartire neanche \func{accept} e \func{recvfrom}; nel caso - di Linux questa è disponibile.} anche quando questa è presente, non è detto -possa essere usata con \func{accept}. La portabilità però viene al costo di -una riscrittura parziale del server, secondo quanto mostrato in -\figref{fig:TCP_echo_server_code}, dove si è riportata la sezione di codice -modificata per la seconda versione del programma. + 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 +riscrittura parziale del server, la nuova versione di questo, in cui si sono +introdotte una serie di nuove opzioni che ci saranno utili per il debug, è +mostrata in \figref{fig:TCP_echo_server_code_second}, dove si sono riportate +la sezioni di codice modificate nella seconda versione del programma, il +sorgente completo di quest'ultimo si trova nel file +\file{TCP\_echod\_second.c} dei sorgenti allegati alla guida. + +La prima modifica effettuata è stata quella di introdurre una nuova opzione a +riga di comando, \texttt{-c}, che permette di richiedere il comportamento +compatibile nella gestione di \const{SIGCHLD} al posto della semantica BSD +impostando la variabile \var{compat} ad un valore non nullo. Questa è +preimpostata al valore nullo, cosicché se non si usa questa opzione il +comportamento di default del server è di usare la semantica BSD. + +Una seconda opzione aggiunta è quella di inserire un tempo di attesa fisso +specificato in secondi fra il ritorno della funzione \func{listen} e la +chiamata di \func{accept}, specificabile con l'opzione \texttt{-w}, che +permette di impostare la variabile \var{waiting}. Infine si è introdotta una +opzione \texttt{-d} per abilitare il debugging che imposta ad un valore non +nullo la variabile \var{debugging}. Al solito si è omessa da +\figref{fig:TCP_echo_server_code_second} la sezione di codice relativa alla +gestione di tutte queste opzioni, che può essere trovata nel sorgente del +programma. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15.6cm} - \includecodesample{listati/TCP_echod.c} + \includecodesample{listati/TCP_echod_second.c} \end{minipage} \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.} - \label{fig:TCP_echo_server_code} + \label{fig:TCP_echo_server_code_second} \end{figure} -In realtà l'unica chiamata critica che può essere interrotta nel server è -quella ad \func{accept}, dato che questa è l'unica che può mettere il processo -padre in stato di sleep.\footnote{si noti infatti che le altre \textit{slow - system call} o sono chiamate prima di entrare nel ciclo principale, quando - ancora non esistono processi figli, o sono chiamate dai figli stessi.} Per -questo l'unica modifica sostanziale nella nuova versione del server, rispetto -alla versione precedente vista in \figref{fig:TCP_ServEcho}, è nella sezione -(\texttt{\small 9--14}) in cui si effettua la chiamata di \func{accept}. -Quest'ultima viene effettuata (\texttt{\small 9--10}) all'interno di un ciclo -di \code{while}\footnote{la sintassi del C relativa a questo ciclo può non - essere del tutto chiara. In questo caso infatti si è usato un ciclo vuoto - che non esegue nessuna istruzione, in questo modo quello che viene ripetuto - con il ciclo è soltanto il codice che esprime la condizione all'interno del - \code{while}.} che la ripete indefinitamente qualora in caso di errore il -valore di \var{errno} sia \errcode{EINTR}. Negli altri casi si esce in caso di -errore effettivo (\texttt{\small 11--14}), altrimenti il programma prosegue. +Vediamo allora come è cambiato il nostro server; una volta definite le +variabili e trattate le opzioni il primo passo (\texttt{\small 9--13}) è +verificare la semantica scelta per la gestione di \const{SIGCHLD}, a seconda +del valore di \var{compat} (\texttt{\small 9}) si installa il gestore con la +funzione \func{Signal} (\texttt{\small 10}) o con \texttt{SignalRestart} +(\texttt{\small 12}), essendo quest'ultimo il valore di default. + +Tutta la sezione seguente, che crea il socket, cede i privilegi di +amministratore ed eventualmente lancia il programma come demone, è rimasta +invariata e pertanto è stata omessa in +\figref{fig:TCP_echo_server_code_second}; l'unica modifica effettuata prima +dell'entrata nel ciclo principale è stata quella di aver introdotto, subito +dopo la chiamata (\texttt{\small 17--20}) alla funzione \func{listen}, una +eventuale pausa con una condizione (\texttt{\small 21}) sulla variabile +\var{waiting}, che viene inizializzata, con l'opzione \code{-w Nsec}, al +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 critica, che può essere +interrotta dall'arrivo di \const{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 +\textit{slow system call}\footnote{si ricordi la distinzione fatta in + \secref{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 \const{SIGCHLD}. + +Per questo l'unica modifica sostanziale nel ciclo principale (\texttt{\small + 23--42}), rispetto precedente versione di \figref{fig:TCP_ServEcho_first}, è +nella sezione (\texttt{\small 26--30}) in cui si effettua la chiamata di +\func{accept}. Quest'ultima viene effettuata (\texttt{\small 26--27}) +all'interno di un ciclo di \code{while}\footnote{la sintassi del C relativa a + questo ciclo può non essere del tutto chiara. In questo caso infatti si è + usato un ciclo vuoto che non esegue nessuna istruzione, in questo modo + quello che viene ripetuto con il ciclo è soltanto il codice che esprime la + condizione all'interno del \code{while}.} che la ripete indefinitamente +qualora in caso di errore il valore di \var{errno} sia \errcode{EINTR}. Negli +altri casi si esce in caso di errore effettivo (\texttt{\small 27--29}), +altrimenti il programma prosegue. Si noti che in questa nuova versione si è aggiunta una ulteriore sezione -(\texttt{\small 15--28}) per il debugging, che stampa l'indirizzo da cui si è -avuta la connessione, e la gestione (\texttt{\small 5}) di una nuova opzione, -specificabile con \code{-w Nsec}, che inizializza la variabile \var{waiting} -al numero di secondi da aspettare. Questa opzione permette di specificare un -tempo di attesa prima di passare alla chiamata \func{accept}, il cui scopo -sarà più chiaro facendo riferimento al primo degli scenari critici di -\secref{sec:TCP_echo_critical}. +(\texttt{\small 31--39}) di aiuto per il debug del programma, che eseguita con +un controllo (\texttt{\small 31}) sul valore della variabile \var{debugging} +impostato dall'opzione \texttt{-d}. Qualora questo sia nullo, come +preimpostato, non accade nulla. altrimenti (\texttt{\small 32}) l'indirizzo +ricevuto da \var{accept} viene convertito in una stringa che poi +(\texttt{\small 33--38}) viene opportunamente stampata o sullo schermo o nei +log. + @@ -2178,14 +2226,18 @@ ritorno di \func{accept}, sono \errcode{ENETDOWN}, \errcode{EPROTO}, \errcode{EHOSTUNREACH}, \errcode{EOPNOTSUPP} e \errcode{ENETUNREACH}. Si tenga presente che questo tipo di terminazione non è riproducibile -terminando il client prima della chiamata ad \func{accept}; in tal caso -infatti il socket associato alla connessione viene semplicemente chiuso, +terminando il client prima della chiamata ad \func{accept}, come si potrebbe +fare usando l'opzione \texttt{-w} per introdurre una pausa dopo il lancio del +demone, in modo da poter avere il tempo per lanciare e terminare una +connessione usando il programma client. In tal caso infatti, alla terminazione +del client, il socket associato alla connessione viene semplicemente chiuso, attraverso la sequenza vista in \secref{sec:TCP_conn_term}, per cui la \func{accept} ritornerà senza errori, e si avrà semplicemente un end-of-file -al primo accesso al socket. Nel caso di Linux inoltre anche l'invio da parte -del client di un segmento di RST non provoca nessun errore al ritorno di -\funcd{accept} quanto un errore di \errcode{ECONNRESET} al primo tentativo di -accesso al socket. +al primo accesso al socket. Nel caso di Linux inoltre, anche qualora si +modifichi il client per fargli gestire l'invio di un segmento di RST alla +chiusura dal socket (come suggerito da Stevens in \cite{UNP1}), non si ha +nessun errore al ritorno di \funcd{accept} quanto un errore di +\errcode{ECONNRESET} al primo tentativo di accesso al socket. @@ -2204,15 +2256,6 @@ della chiusura del socket. - -Nella funzione si è anche inserita (\texttt{\small 16--24}) la possibilità di -inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d} -che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui -la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 20}) o -direttamente sullo standard output (\texttt{\small 22}). - - - %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil"