Inoltre prenderemo in esame, oltre al comportamento in condizioni normali,
anche tutti i possibili scenari particolari (errori, sconnessione della rete,
crash del client o del server durante la connessione) che possono avere luogo
Inoltre prenderemo in esame, oltre al comportamento in condizioni normali,
anche tutti i possibili scenari particolari (errori, sconnessione della rete,
crash del client o del server durante la connessione) che possono avere luogo
completa, del servizio \texttt{echo}. Il servizio \texttt{echo} è uno dei
servizi standard solitamente provvisti direttamente dal superserver
\cmd{inetd}, ed è definito dall'RFC~862. Come dice il nome il servizio deve
completa, del servizio \texttt{echo}. Il servizio \texttt{echo} è uno dei
servizi standard solitamente provvisti direttamente dal superserver
\cmd{inetd}, ed è definito dall'RFC~862. Come dice il nome il servizio deve
applicazione più complessa è la elaborazione dell'input del client da parte
del server nel fornire le risposte in uscita.
applicazione più complessa è la elaborazione dell'input del client da parte
del server nel fornire le risposte in uscita.
-manifestare nella vita reale di una applicazione di rete, fino ad arrivare ad
-una implementazione completa.
+manifestare nella vita reale di un'applicazione di rete, fino ad arrivare ad
+un'implementazione completa.
\subsection{La struttura del server}
\label{sec:TCPsimp_server_main}
La prima versione del server, \file{ElemEchoTCPServer.c}, si compone di un
\subsection{La struttura del server}
\label{sec:TCPsimp_server_main}
La prima versione del server, \file{ElemEchoTCPServer.c}, si compone di un
di creare il socket, metterlo in ascolto di connessioni in arrivo e creare un
processo figlio a cui delegare la gestione di ciascuna connessione. Questa
parte, riportata in \nfig, è analoga a quella vista nel precedente esempio
di creare il socket, metterlo in ascolto di connessioni in arrivo e creare un
processo figlio a cui delegare la gestione di ciascuna connessione. Questa
parte, riportata in \nfig, è analoga a quella vista nel precedente esempio
\secref{sec:TCPel_cunc_daytime}. Le uniche differenze rispetto all'esempio in
\figref{fig:TCPel_serv_code} sono che in questo caso per il socket in
ascolto viene usata la porta 7 e tutta la gestione della comunicazione è
\secref{sec:TCPel_cunc_daytime}. Le uniche differenze rispetto all'esempio in
\figref{fig:TCPel_serv_code} sono che in questo caso per il socket in
ascolto viene usata la porta 7 e tutta la gestione della comunicazione è
% Per ogni connessione viene creato un
% processo figlio, il quale si incarica di lanciare la funzione
% \texttt{SockEcho}.
% Per ogni connessione viene creato un
% processo figlio, il quale si incarica di lanciare la funzione
% \texttt{SockEcho}.
comunicazione viene gestita all'interno del ciclo (linee \texttt{\small
6--8}). I dati inviati dal client vengono letti dal socket con una semplice
\func{read} (che ritorna solo in presenza di dati in arrivo), la riscrittura
comunicazione viene gestita all'interno del ciclo (linee \texttt{\small
6--8}). I dati inviati dal client vengono letti dal socket con una semplice
\func{read} (che ritorna solo in presenza di dati in arrivo), la riscrittura
connessione (linee \texttt{\small 10--27}) secondo la stessa modalità spiegata
in \secref{sec:net_cli_sample}, il client si connette sulla porta 7
all'indirizzo specificato dalla linea di comando (a cui si è aggiunta una
elementare gestione delle opzioni non riportata in figura).
Completata la connessione (quando la funzione \func{connect} ritorna) la
connessione (linee \texttt{\small 10--27}) secondo la stessa modalità spiegata
in \secref{sec:net_cli_sample}, il client si connette sulla porta 7
all'indirizzo specificato dalla linea di comando (a cui si è aggiunta una
elementare gestione delle opzioni non riportata in figura).
Completata la connessione (quando la funzione \func{connect} ritorna) la
comunicazione, leggendo una riga alla volta dallo \file{stdin}, scrivendola
sul socket e ristampando su \file{stdout} quanto ricevuto in risposta dal
server.
comunicazione, leggendo una riga alla volta dallo \file{stdin}, scrivendola
sul socket e ristampando su \file{stdout} quanto ricevuto in risposta dal
server.
La funzione utilizza due buffer per gestire i dati inviati e letti sul socket
(\texttt{\small 3}). La comunicazione viene gestita all'interno di un ciclo
(linee \texttt{\small 5--10}), i dati da inviare sulla connessione vengono
La funzione utilizza due buffer per gestire i dati inviati e letti sul socket
(\texttt{\small 3}). La comunicazione viene gestita all'interno di un ciclo
(linee \texttt{\small 5--10}), i dati da inviare sulla connessione vengono
\func{SockWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
l'invio multiplo qualora una singola \func{write} non basti, come spiegato
in \secref{sec:sock_io_behav}).
\func{SockWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
l'invio multiplo qualora una singola \func{write} non basti, come spiegato
in \secref{sec:sock_io_behav}).
Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
di considerare in dettaglio tutte le problematiche che si possono incontrare
Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
di considerare in dettaglio tutte le problematiche che si possono incontrare
modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
che avviene nelle varie situazioni limite, da una parte potremo approfondire
la comprensione del protocollo TCP/IP e dall'altra ricavare le indicazioni
modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
che avviene nelle varie situazioni limite, da una parte potremo approfondire
la comprensione del protocollo TCP/IP e dall'altra ricavare le indicazioni
\func{fgets} dato che non si è ancora scritto nulla sul terminale.
\item il server eseguirà una \func{fork} facendo chiamare al processo figlio
\func{fgets} dato che non si è ancora scritto nulla sul terminale.
\item il server eseguirà una \func{fork} facendo chiamare al processo figlio
dal socket sul quale ancora non sono presenti dati.
\item il processo padre del server chiamerà di nuovo \func{accept}
bloccandosi fino all'arrivo di un'altra connessione.
dal socket sul quale ancora non sono presenti dati.
\item il processo padre del server chiamerà di nuovo \func{accept}
bloccandosi fino all'arrivo di un'altra connessione.
Esaminiamo allora in dettaglio la sequenza di eventi che porta alla
terminazione normale della connessione, che ci servirà poi da riferimento nei
Esaminiamo allora in dettaglio la sequenza di eventi che porta alla
terminazione normale della connessione, che ci servirà poi da riferimento nei
\begin{enumerate}
\item inviando un carattere di EOF da terminale la \func{fgets} ritorna
restituendo un puntatore nullo che causa l'uscita dal ciclo di
\begin{enumerate}
\item inviando un carattere di EOF da terminale la \func{fgets} ritorna
restituendo un puntatore nullo che causa l'uscita dal ciclo di
- while, così la \func{ClientEcho} ritorna.
-\item al ritorno di \func{ClientEcho} ritorna anche la funzione \func{main}, e
+ while, così la \code{ClientEcho} ritorna.
+\item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e
come parte del processo terminazione tutti i file descriptor vengono chiusi
(si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
la chiusura del socket di comunicazione; il client allora invierà un FIN al
server a cui questo risponderà con un ACK. A questo punto il client verrà a
come parte del processo terminazione tutti i file descriptor vengono chiusi
(si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
la chiusura del socket di comunicazione; il client allora invierà un FIN al
server a cui questo risponderà con un ACK. A questo punto il client verrà a
- trovarsi nello stato \macro{FIN\_WAIT\_2} ed il server nello stato
- \macro{CLOSE\_WAIT} (si riveda quanto spiegato in
+ trovarsi nello stato \texttt{FIN\_WAIT\_2} ed il server nello stato
+ \texttt{CLOSE\_WAIT} (si riveda quanto spiegato in
\secref{sec:TCPel_conn_term}).
\item quando il server riceve il FIN la \func{read} del processo figlio che
gestisce la connessione ritorna restituendo 0 causando così l'uscita dal
\secref{sec:TCPel_conn_term}).
\item quando il server riceve il FIN la \func{read} del processo figlio che
gestisce la connessione ritorna restituendo 0 causando così l'uscita dal
figlio termina chiamando \func{exit}.
\item all'uscita del figlio tutti i file descriptor vengono chiusi, la
chiusura del socket connesso fa sì che venga effettuata la sequenza finale
di chiusura della connessione, viene emesso un FIN dal server che riceverà
un ACK dal client, a questo punto la connessione è conclusa e il client
figlio termina chiamando \func{exit}.
\item all'uscita del figlio tutti i file descriptor vengono chiusi, la
chiusura del socket connesso fa sì che venga effettuata la sequenza finale
di chiusura della connessione, viene emesso un FIN dal server che riceverà
un ACK dal client, a questo punto la connessione è conclusa e il client
segnale, per questo installeremo un manipolatore usando la funzione
\func{Signal} (trattata in dettaglio in \secref{sec:sig_signal}).
segnale, per questo installeremo un manipolatore usando la funzione
\func{Signal} (trattata in dettaglio in \secref{sec:sig_signal}).