Versione finale del client ECHO su TCP, con esempio di uso della funzione
[gapil.git] / tcpsock.tex
index 20f143ea39dd8ed8dfef6e3f818cbd0d3aa2f32b..2ce01cd4077019840c5e25af732821598b373217 100644 (file)
@@ -8,7 +8,7 @@
 %% license is included in the section entitled "GNU Free Documentation
 %% License".
 %%
-\chapter{Socket TCP}
+\chapter{Socket TCP elementari}
 \label{cha:TCP_socket}
 
 In questo capitolo iniziamo ad approfondire la conoscenza dei socket TCP,
@@ -221,7 +221,7 @@ chiusura attiva.  Nella sequenza indicata i dati verrebbero persi, dato che si
 è 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
@@ -339,8 +339,8 @@ La MSL 
 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
@@ -1034,8 +1034,8 @@ funzione.  Se non ci sono connessioni pendenti da accettare la funzione mette
 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
@@ -1083,7 +1083,7 @@ relativi alla socket pair associata ad un certo socket.
 La prima funzione è \funcd{getsockname} e serve ad ottenere l'indirizzo locale
 associato ad un socket; il suo prototipo è:
 \begin{prototype}{sys/socket.h}
-  {int getsockname(int sockfd, struct sockaddr * name, socklen\_t * namelen)}
+  {int getsockname(int sockfd, struct sockaddr *name, socklen\_t *namelen)}
   Legge l'indirizzo locale di un socket.
 
 \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
@@ -1201,7 +1201,8 @@ si aspetta in una qualunque applicazione client/server.
 
 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:xxx_shutdown}).
+\func{shutdown} su cui torneremo in seguito (vedi
+\secref{sec:TCP_shutdown}).
 
 
 
@@ -1693,7 +1694,7 @@ scriverli su \file{stdout}.
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
-    \includecodesample{listati/ClientEcho.c}
+    \includecodesample{listati/ClientEcho_first.c}
   \end{minipage} 
   \normalsize
   \caption{Codice della prima versione della funzione \texttt{ClientEcho} per 
@@ -2081,8 +2082,8 @@ 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.
+codice 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
@@ -2236,7 +2237,7 @@ attraverso la sequenza vista in \secref{sec:TCP_conn_term}, per cui la
 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
+nessun errore al ritorno di \funcd{accept}, quanto un errore di
 \errcode{ECONNRESET} al primo tentativo di accesso al socket.
 
 
@@ -2244,7 +2245,7 @@ nessun errore al ritorno di \funcd{accept} quanto un errore di
 \subsection{La terminazione precoce del server}
 \label{sec:TCP_server_crash}
 
-Un secondo caso critico è quello in cui si ha una terminazione prococe del
+Un secondo caso critico è quello in cui si ha una terminazione precoce del
 server, ad esempio perché il programma ha un crash. In tal caso si suppone che
 il processo termini per un errore fatale, cosa che potremo simulare
 inviandogli un segnale di terminazione. La conclusione del processo comporta
@@ -2273,9 +2274,9 @@ errore.
 
 Per capire meglio cosa è successo conviene analizzare il flusso dei pacchetti
 utilizzando un analizzatore di traffico come \cmd{tcpdump}. Il comando
-permette di selezionare, nel treffico di rete generato su una macchina, i
+permette di selezionare, nel traffico di rete generato su una macchina, i
 pacchetti che interessano, stampando a video (o salvando su disco) il loro
-conteuto. Non staremo qui ad entrare nei dettagli dell'uso del programma, che
+contenuto. Non staremo qui ad entrare nei dettagli dell'uso del programma, che
 sono spiegati dalla pagina di manuale; per l'uso che vogliamo farne quello che
 ci interessa è, posizionandosi sulla macchina che fa da client, selezionare
 tutti i pacchetti che sono diretti o provengono dalla macchina che fa da
@@ -2324,7 +2325,7 @@ compattezza.  Il campo \texttt{win} in ogni riga indica la \textit{advertising
   window} di cui parlavamo in \secref{sec:TCP_TCP_opt}. Allora si può
 verificare dall'output del comando come venga appunto realizzata la sequenza
 di pacchetti descritta in \secref{sec:TCP_conn_cre}: prima viene inviato dal
-clinet un primo pacchetto con il SYN che inizia la connessione, a cui il
+client un primo pacchetto con il SYN che inizia la connessione, a cui il
 server risponde dando il ricevuto con un secondo pacchetto, che a sua volta
 porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto.
 
@@ -2348,9 +2349,20 @@ descriptor, il che comporta, per il socket che avevamo aperto, l'inizio della
 sequenza di chiusura illustrata in \secref{sec:TCP_conn_term}.  Questo
 significa che dal server partirà un FIN, che è appunto il primo dei due
 pacchetti, contraddistinto dalla lettera \texttt{F}, cui seguirà al solito un
-ACK da parte del client.  A questo punto la connessione dalla parte del server
-è chiusa, ed infatti se usiamo \cmd{netstat} per controllarne lo stato sul
-client, otterremo che essa è andata nello stato \texttt{CLOSE\_WAIT}:
+ACK da parte del client.  
+
+A questo punto la connessione dalla parte del server è chiusa, ed infatti se
+usiamo \cmd{netstat} per controllarne lo stato otterremo che sul server si ha:
+\begin{verbatim}
+anarres:/home/piccardi# netstat -ant
+Active Internet connections (servers and established)
+Proto Recv-Q Send-Q Local Address           Foreign Address         State
+...      ...    ... ...                     ...                     ...
+tcp        0      0 192.168.1.141:7         192.168.1.2:34626       FIN_WAIT2
+\end{verbatim}
+cioè essa è andata nello stato \texttt{FIN\_WAIT2}, che indica l'avvenuta
+emissione del segmento FIN, mentre sul client otterremo che essa è andata
+nello stato \texttt{CLOSE\_WAIT}:
 \begin{verbatim}
 [root@gont gapil]# netstat -ant
 Active Internet connections (servers and established)
@@ -2368,19 +2380,31 @@ pacchetti riportati da \cmd{tcpdump}: il primo, inviato dal client contenente
 i 25 caratteri della riga appena letta, e ad esso la macchina server
 risponderà, non essendoci più niente in ascolto sulla porta 7, con un segmento
 di RST, contraddistinto dalla lettera \texttt{R}, che causa la conclusione
-definitiva della connessione anche nel client, dove non comparrà più
+definitiva della connessione anche nel client, dove non comparirà più
 nell'output di \cmd{netstat}.
 
-Non avendo controllato lo stato di uscita della nostra funzione di scrittura
-(si riveda il codice illustrato in \secref{fig:TCP_client_echo_sub}) che a
-questo punto riporterebbe un errore, il client proseguirà leggendo dal socket,
-e dato che questo è stato chiuso avremo che, come spiegato in
-\secref{sec:TCP_conn_term}, la funzione \func{read} ritorna normalmente con un
-valore nullo. Questo comporta che la seguente chiamata a \func{fputs} non ha
-effetto (viene stampata una stringa nulla) ed il client si blocca di nuovo
-nella successiva chiamata a \func{fgets}. Per questo diventa possibile
-inserire una terza riga e solo dopo averlo fatto si avrà la terminazione del
-programma.
+Come abbiamo accennato in \secref{sec:TCP_conn_term} e come vedremo più avanti
+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
+  altro comando e ne stampa a video tutte le invocazioni di una system call,
+  coi relativi parametri 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 \secref{sec:TCP_conn_term},
+la funzione \func{read} ritorna normalmente con un valore nullo. Questo
+comporta che la seguente chiamata a \func{fputs} non ha effetto (viene
+stampata una stringa nulla) ed il client si blocca di nuovo nella successiva
+chiamata a \func{fgets}. Per questo diventa possibile inserire una terza riga
+e solo dopo averlo fatto si avrà la terminazione del programma.
 
 Per capire come questa avvenga comunque, non avendo inserito nel codice nessun
 controllo di errore, occorre ricordare che, a parte la bidirezionalità del
@@ -2393,6 +2417,248 @@ esattamente quello che avviene in questo caso, e siccome non abbiamo un
 gestore per questo segnale, viene eseguita l'azione preimpostata, che è quella
 di terminare il processo.
 
+Per gestire in maniera più corretta questo tipo di evento dovremo allora
+modificare il nostro client perché sia in grado di trattare le varie tipologie
+di errore, per questo dovremo riscrivere la funzione \func{ClientEcho}, in
+modo da controllare gli stati di uscita delle varie chiamate. Si è riportata
+la nuova versione della funzione in \figref{fig:TCP_ClientEcho_second}.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/ClientEcho_second.c}
+  \end{minipage} 
+  \normalsize
+  \caption{La sezione nel codice della seconda versione della funzione
+    \func{ClientEcho} usata dal client per il servizio \textit{echo}
+    modificata per tener conto degli eventuali errori.}
+  \label{fig:TCP_ClientEcho_second}
+\end{figure}
+
+Come si può vedere in questo caso si controlla il valore di ritorno di tutte
+le funzioni, ed inoltre si verifica la presenza di un eventuale end of file in
+caso di lettura. Con questa modifica il nostro client echo diventa in grado di
+accorgersi della chiusura del socket da parte del server, per cui ripetendo la
+sequenza di operazioni precedenti stavolta otterremo che:
+\begin{verbatim}
+[piccardi@gont sources]$ ./echo 192.168.1.141
+Prima riga
+Prima riga
+Seconda riga dopo il C-c
+EOF sul socket
+\end{verbatim}%$
+ma di nuovo si tenga presente che non c'è modo di accorgersi della chiusura
+del socket fin quando non si esegue la scrittura della seconda riga; il
+protocollo infatti prevede che ci debba essere una scrittura prima di ricevere
+un RST che confermi la chiusura del file, e solo alle successive scritture si
+potrà ottenere un errore.
+
+Questa caratteristica dei socket ci mette di fronte ad un altro problema
+relativo al nostro client, e che cioè esso non è in grado di accorgersi di
+nulla fintanto che è bloccato nella lettura del terminale fatta con
+\func{gets}. In questo caso il problema è minimo, ma esso riemergerà più
+avanti, ed è quello che si deve affrontare tutte le volte quando si ha a che
+fare con la necessità di lavorare con più descrittori, nel qual caso diventa
+si pone la questione di come fare a non restare bloccati su un socket quando
+altri potrebbero essere liberi. Vedremo come affrontare questa problematica in
+\secref{sec:TCP_sock_multiplexing}.
+
+\subsection{Altri scenari di terminazione della connessione}
+\label{sec:TCP_conn_crash}
+
+La terminazione del server è solo uno dei possibili scenari di terminazione
+della connessione, un altro caso è ad esempio quello in cui si ha un crollo
+della rete, cosa che potremo simulare facilmente staccando il cavo di rete.
+Un'altra condizione è quella di un blocco della macchina completo della su cui
+gira il server che deve essere riavviata, cosa che potremo simulare sia
+premendo il bottone di reset,\footnote{un normale shutdown non va bene; in tal
+  caso infatti il sistema provvede a terminare tutti i processi, per cui la
+  situazione sarebbe sostanzialmente identica alla precedente.} che, in
+maniera più gentile, riavviando la macchina dopo aver interrotto la
+connessione di rete.
+
+Cominciamo ad analizzare il primo caso, il crollo della rete. Ripetiamo la
+nostra sessione di lavoro precedente, lanciamo il client, scriviamo una prima
+riga, poi stacchiamo il cavo e scriviamo una seconda riga. Il risultato che
+otterremo è:
+\begin{verbatim}
+[piccardi@gont sources]$ ./echo 192.168.1.141
+Prima riga
+Prima riga
+Seconda riga dopo l'interruzione
+Errore in lettura: No route to host
+\end{verbatim}%$
+
+Quello che succede in questo è che il programma, dopo aver scritto la seconda
+riga, resta bloccato per un tempo molto lungo, prima di dare l'errore
+\errcode{EHOSTUNREACH}.  Se andiamo ad osservare con \cmd{strace} cosa accade
+nel periodo in cui il programma è bloccato vedremo che stavolta, a differenza
+del caso precedente, il programma è bloccato nella lettura dal socket.
+
+Se poi, come nel caso precedente, usiamo l'accortezza di analizzare il
+traffico di rete fra client e server con \cmd{tcpdump}, otterremo il seguente
+risultato:
+\begin{verbatim}
+[root@gont sources]# tcpdump src 192.168.1.141 or dst 192.168.1.141 -N -t
+tcpdump: listening on eth0
+gont.34685 > anarres.echo: S 1943495663:1943495663(0) win 5840
+anarres.echo > gont.34685: S 1215783131:1215783131(0) ack 1943495664 win 5792 
+gont.34685 > anarres.echo: . ack 1 win 5840
+gont.34685 > anarres.echo: P 1:12(11) ack 1 win 5840 
+anarres.echo > gont.34685: . ack 12 win 5792 
+anarres.echo > gont.34685: P 1:12(11) ack 12 win 5792 
+gont.34685 > anarres.echo: . ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34685 > anarres.echo: P 12:45(33) ack 12 win 5840 
+arp who-has anarres tell gont
+arp who-has anarres tell gont
+arp who-has anarres tell gont
+arp who-has anarres tell gont
+arp who-has anarres tell gont
+arp who-has anarres tell gont
+...
+\end{verbatim}
+
+In questo caso l'andamento dei primi sette pacchetti è esattamente lo stesso
+di prima. Solo che stavolta, non appena inviata la seconda riga, il programma
+si bloccherà nella successiva chiamata a \func{read}, non ottendo nessuna
+risposta. Quello che succede è che nel frattempo il kernel provvede, come
+richiesto dal protocollo TCP, a tentare la ritrasmissione della nostra riga un
+certo numero di volte, con tempi di attesa crescente fra un tentativo ed il
+successivo, per tentare di ristabilire la connessione.
+
+Il risultato finale qui dipende dall'implementazione dello stack TCP, e nel
+caso di Linux anche dall'impostazione di alcuni dei parametri di sistema che
+si trovano in \file{/proc/sys/net/ipv4}, che ne controllano il comportamento:
+in questo caso in particolare da \file{tcp\_retries2}. Questo parametro
+infatti specifica il numero di volte che deve essere ritentata la
+ritrasmissione di un pacchetto nel mezzo di una connessione prima di riportare
+un errore di timeout.  Il valore preimpostato è pari a 15, il che
+comporterebbe 15 tentativi di ritrasmissione, ma nel nostro caso le cose sono
+andate diversamente, dato che le ritrasmissioni registrate da \cmd{tcpdump}
+sono solo 8; inoltre l'errore riportato all'uscita del client non è stato
+\errcode{ETIMEDOUT}, come dovrebbe essere in questo caso, ma
+\errcode{EHOSTUNREACH}.
+
+Per capire l'accaduto continuiamo ad analizzare l'output di \cmd{tcpdump}:
+esso ci mostra che a un certo punto i tentativi di ritrasmissione del
+pacchetto sono cessati, per essere sostituiti da una serie di richieste di
+protocollo ARP in cui il client richiede l'indirizzo del server.
+
+Come abbiamo accennato in \secref{sec:net_tcpip_general} ARP è il protocollo
+che si incarica di trovare le corrispondenze corrispondenze fra indirizzo IP e
+indirizzo hardware sulla scheda di rete. È evidente allora che nel nostro
+caso, essendo client e server sulla stessa rete, è scaduta la voce nella
+\textit{ARP cache}\footnote{la \textit{ARP chache} è una tabella mantenuta
+  internamente dal kernel che contiene tutte le corrispondenze fra indirizzi
+  IP e indirizzi fisici, ottenute appunto attraverso il protocollo ARP; le
+  voci della tabella hanno un tempo di vita limitato, passato il quale scadono
+  e devono essere nuovamente richieste.} relativa ad \texttt{anarres}, ed il
+nostro client ha iniziato ad effettuare richieste ARP sulla rete per sapere
+l'IP di quest'ultimo, che essendo scollegato non poteva rispondere. Anche per
+questo tipo di richieste esiste un timeout, per cui dopo un certo numero di
+tentativi il meccanismo si è interrotto, e l'errore riportato al programma a
+questo punto è stato \errcode{EHOSTUNREACH}, in quanto non si era più in grado
+di contattare il server.
+
+Un altro errore possibile in questo tipo di situazione, che si può avere
+quando la macchina è su una rete remota, è \errcode{ENETUNREACH}; esso viene
+riportato alla ricezione di un pacchetto ICMP di \textit{destination
+  unreachable} da parte del router che individua l'interruzione della
+connessione. Di nuovo anche qui il risultato finale dipende da quale è il
+meccanismo più veloce ad accorgersi del problema.
+
+Se però agiamo sui parametri del kernel, e scriviamo in \file{tcp\_retries2}
+un valore di tentativi più basso, possiamo evitare la scadenza della
+\textit{ARP cache} e vedere cosa succede. Così se ad esempio richiediamo 4
+tentativi di ritrasmissione, l'analisi di \cmd{tcpdump} ci riporterà il
+seguente scambio di pacchetti:
+\begin{verbatim}
+[root@gont gapil]# tcpdump src 192.168.1.141 or dst 192.168.1.141 -N -t
+tcpdump: listening on eth0
+gont.34752 > anarres.echo: S 3646972152:3646972152(0) win 5840
+anarres.echo > gont.34752: S 2735190336:2735190336(0) ack 3646972153 win 5792 
+gont.34752 > anarres.echo: . ack 1 win 5840 
+gont.34752 > anarres.echo: P 1:12(11) ack 1 win 5840
+anarres.echo > gont.34752: . ack 12 win 5792 
+anarres.echo > gont.34752: P 1:12(11) ack 12 win 5792 
+gont.34752 > anarres.echo: . ack 12 win 5840 
+gont.34752 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34752 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34752 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34752 > anarres.echo: P 12:45(33) ack 12 win 5840 
+gont.34752 > anarres.echo: P 12:45(33) ack 12 win 5840 
+\end{verbatim}
+e come si vede in questo caso i tentativi di ritrasmissione del pacchetto
+iniziale sono proprio 4 (per un totale di 5 voci con quello trasmesso la prima
+volta), ed in effetti, dopo un tempo molto più breve rispetto a prima ed in
+corrispondenza dell'invio dell'ultimo tentativo, quello che otterremo come
+errore all'uscita del client sarà diverso, e cioè:
+\begin{verbatim}
+[piccardi@gont sources]$ ./echo 192.168.1.141
+Prima riga
+Prima riga
+Seconda riga dopo l'interruzione
+Errore in lettura: Connection timed out
+\end{verbatim}%$
+che corrisponde appunto, come ci aspettavamo, alla ricezione di un
+\errcode{ETIMEDOUT}.
+
+Analizziamo ora il secondo scenario, in cui si ha un crollo della macchina che
+fa da server. Al solito lanciamo il nostro client, scriviamo una prima riga
+per verificare che sia tutto a posto, poi stacchiamo il cavo e riavviamo il
+server. A questo punto, ritornato attivo il server, scriviamo una seconda
+riga. Quello che otterremo in questo caso è:
+\begin{verbatim}
+[piccardi@gont sources]$ ./echo 192.168.1.141
+Prima riga
+Prima riga
+Seconda riga dopo l'interruzione
+Errore in lettura Connection reset by peer
+\end{verbatim}%$
+e l'errore ricevuti da \func{read} stavolta è \errcode{ECONNRESET}. Se al
+solito riportiamo l'analisi dei pacchetti effettuata con \cmd{tcpdump},
+avremo:
+\begin{verbatim}
+[root@gont gapil]# tcpdump src 192.168.1.141 or dst 192.168.1.141 -N -t
+tcpdump: listening on eth0
+gont.34756 > anarres.echo: S 904864257:904864257(0) win 5840 
+anarres.echo > gont.34756: S 4254564871:4254564871(0) ack 904864258 win 5792
+gont.34756 > anarres.echo: . ack 1 win 5840 
+gont.34756 > anarres.echo: P 1:12(11) ack 1 win 5840
+anarres.echo > gont.34756: . ack 12 win 5792 
+anarres.echo > gont.34756: P 1:12(11) ack 12 win 5792
+gont.34756 > anarres.echo: . ack 12 win 5840 
+gont.34756 > anarres.echo: P 12:45(33) ack 12 win 5840
+anarres.echo > gont.34756: R 4254564883:4254564883(0) win 0 
+\end{verbatim}
+
+Ancora una volta i primi sette pacchetti sono gli stessi; ma in questo caso
+quello che succede dopo lo scambio iniziale è che, non avendo inviato nulla
+durante il periodo in cui si è riavviato il server, il client è del tutto
+ignaro dell'accaduto per cui quando effettuerà una scrittura, dato che la
+macchina server è stata riavviata e che tutti gli stati relativi alle
+precedenti connessioni sono completamente persi, anche in presenza di una
+nuova istanza del server echo non sarà possibile consegnare i dati in arrivo,
+per cui alla loro ricezione il kernel risponderà con un segmento di RST.
+
+Il client da parte sua, dato che neanche in questo caso non è stato emesso un
+FIN, dopo aver scritto verrà bloccato nella successiva chiamata a \func{read},
+che però adesso ritornerà immediatamente alla ricezione del segmento RST,
+riportando appunto come errore \errcode{ECONNRESET}. Occorre precisare che se
+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_sock_options}) che provvede all'esecuzione di questo
+controllo.