X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=tcpsockadv.tex;h=e77e4320ec8878aad850118fa9bf870e1b8f3725;hp=44986525fc3141b95422a22548adb4ede34b939a;hb=4b5c12ae4a519b8282fd3a6dcdbc33ee7dd8c3c7;hpb=65cdd0498d1d9473110f86ebddede62c298e60dd diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 4498652..e77e432 100644 --- a/tcpsockadv.tex +++ b/tcpsockadv.tex @@ -184,10 +184,10 @@ le modalit assolutamente identico. La nostra nuova versione di \func{ClientEcho}, la terza della serie, è riportata in \figref{fig:TCP_ClientEcho_third}. -In questo caso la funzione comincia (\texttt{\small 8--9}) con la -cancellazione del file descriptor set \var{fset} e del valore \var{maxfd} da -passare a \func{select} come massimo per il numero dei file descriptor. Per -quest'ultimo si usa la macro \code{max} definita nel nostro file +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à. @@ -197,47 +197,108 @@ viene ripetuto indefinitamente. Per ogni ciclo si reinizializza 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. +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, passando poi il -solo file descriptor set per il controllo dell'attività in lettura, gli altri -argomenti sono tutti passati come puntatori nulli non interessando né il +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 file -descriptor presneta attività, si comincia (\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; altrimenti (\texttt{\small 18--22}) si scrivono i dati sul -socket, uscendo immediatamente in caso di errore di scrittura. +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à si esegue (\texttt{\small 26}) subito +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}) +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}. -\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} - \subsection{La funzione \func{shutdown}} @@ -265,6 +326,24 @@ scrivere. Per poter permettere allora +\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} + + + %%% Local Variables: %%% mode: latex