fine revisione di \macro{}, piu' una serie di correzioni nella rilettura.
[gapil.git] / simpltcp.tex
1 %% simpltcp.tex
2 %%
3 %% Copyright (C) 2000-2002 Simone Piccardi.  Permission is granted to
4 %% copy, distribute and/or modify this document under the terms of the GNU Free
5 %% Documentation License, Version 1.1 or any later version published by the
6 %% Free Software Foundation; with the Invariant Sections being "Prefazione",
7 %% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
8 %% license is included in the section entitled "GNU Free Documentation
9 %% License".
10 %%
11 \chapter{Un esempio completo di client/server TCP}
12 \label{cha:simple_TCP_sock}
13
14 In questo capitolo riprenderemo le funzioni trattate nel precedente, usandole
15 per scrivere una prima applicazione client/server che usi i socket TCP per una
16 comunicazione in entrambe le direzioni. 
17
18 Inoltre prenderemo in esame, oltre al comportamento in condizioni normali,
19 anche tutti i possibili scenari particolari (errori, sconnessione della rete,
20 crash del client o del server durante la connessione) che possono avere luogo
21 durante l'impiego di un'applicazione di rete.
22
23
24 \section{Il servizio \texttt{echo}}
25 \label{sec:TCPsimp_echo}
26
27 L'applicazione scelta come esempio sarà un'implementazione elementare, ma
28 completa, del servizio \texttt{echo}. Il servizio \texttt{echo} è uno dei
29 servizi standard solitamente provvisti direttamente dal superserver
30 \cmd{inetd}, ed è definito dall'RFC~862. Come dice il nome il servizio deve
31 rimandare indietro sulla connessione i dati che gli vengono inviati; l'RFC
32 descrive le specifiche sia per TCP che UDP, e per il primo stabilisce che una
33 volta stabilita la connessione ogni dato in ingresso deve essere rimandato in
34 uscita, fintanto che il chiamante non ha chiude la connessione; il servizio
35 opera sulla porta 7.
36
37 Nel nostro caso l'esempio sarà costituito da un client che legge una linea di
38 caratteri dallo standard input e la scrive sul server, il server leggerà la
39 linea dalla connessione e la riscriverà all'indietro; sarà compito del client
40 leggere la risposta del server e stamparla sullo standard output.
41
42 Si è scelto di usare questo servizio, seguendo l'esempio di \cite{UNP1},
43 perché costituisce il prototipo ideale di una generica applicazione di rete in
44 cui un server risponde alle richieste di un client; tutto quello che cambia
45 nel caso si una applicazione più complessa è la elaborazione dell'input del
46 client da parte del server nel fornire le risposte in uscita.
47
48 Partiremo da un'implementazione elementare che dovrà essere rimaneggiata di
49 volta in volta per poter tenere conto di tutte le evenienze che si possono
50 manifestare nella vita reale di un'applicazione di rete, fino ad arrivare ad
51 un'implementazione completa.
52
53 \subsection{La struttura del server}
54 \label{sec:TCPsimp_server_main}
55
56 La prima versione del server, \file{ElemEchoTCPServer.c}, si compone di un
57 corpo principale, costituito dalla funzione \code{main}.  Questa si incarica
58 di creare il socket, metterlo in ascolto di connessioni in arrivo e creare un
59 processo figlio a cui delegare la gestione di ciascuna connessione.  Questa
60 parte, riportata in \figref{fig:TCPsimpl_serv_code}, è analoga a quella vista
61 nel precedente esempio esaminato in \secref{sec:TCPel_cunc_serv}.
62
63 \begin{figure}[!htb]
64   \footnotesize
65   \begin{lstlisting}{}
66 /* Subroutines declaration */
67 void ServEcho(int sockfd);
68 /* Program beginning */
69 int main(int argc, char *argv[])
70 {
71     int list_fd, conn_fd;
72     pid_t pid;
73     struct sockaddr_in serv_add;
74      ...
75     /* create socket */
76     if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
77         perror("Socket creation error");
78         exit(-1);
79     }
80     /* initialize address */
81     memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
82     serv_add.sin_family = AF_INET;                  /* address type is INET */
83     serv_add.sin_port = htons(13);                  /* daytime port is 13 */
84     serv_add.sin_addr.s_addr = htonl(INADDR_ANY);   /* connect from anywhere */
85     /* bind socket */
86     if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
87         perror("bind error");
88         exit(-1);
89     }
90     /* listen on socket */
91     if (listen(list_fd, BACKLOG) < 0 ) {
92         perror("listen error");
93         exit(-1);
94     }
95     /* handle echo to client */
96     while (1) {
97         /* accept connection */
98         if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) {
99             perror("accept error");
100             exit(-1);
101         }
102         /* fork to handle connection */
103         if ( (pid = fork()) < 0 ){
104             perror("fork error");
105             exit(-1);
106         }
107         if (pid == 0) {      /* child */
108             close(list_fd);          /* close listening socket */   
109             SockEcho(conn_fd);       /* handle echo */
110             exit(0);
111         } else {             /* parent */
112             close(conn_fd);          /* close connected socket */
113         }
114     }
115     /* normal exit, never reached */
116     exit(0);
117 }
118   \end{lstlisting}
119   \caption{Codice della funzione \code{main} della prima versione del server
120     per il servizio \texttt{echo}.}
121   \label{fig:TCPsimpl_serv_code}
122 \end{figure}
123
124 La struttura di questa prima versione del server è sostanzialmente identica a
125 quella dell'esempio citato, ed ad esso si applicano le considerazioni fatte in
126 \secref{sec:TCPel_cunc_daytime}. Le uniche differenze rispetto all'esempio in
127 \figref{fig:TCPel_serv_code} sono che in questo caso per il socket in ascolto
128 viene usata la porta 7 e che tutta la gestione della comunicazione è delegata
129 alla funzione \code{ServEcho}.
130 %  Per ogni connessione viene creato un
131 % processo figlio, il quale si incarica di lanciare la funzione
132 % \texttt{SockEcho}.
133
134 Il codice della funzione \code{ServEcho} è invece mostrata in
135 \figref{fig:TCPsimpl_server_elem_sub}, la comunicazione viene gestita
136 all'interno del ciclo (linee \texttt{\small 6--8}).  I dati inviati dal client
137 vengono letti dal socket con una semplice \func{read} (che ritorna solo in
138 presenza di dati in arrivo), la riscrittura viene invece gestita dalla
139 funzione \func{SockWrite} (descritta in \figref{fig:sock_SockWrite_code}) che
140 si incarica di tenere conto automaticamente della possibilità che non tutti i
141 dati di cui è richiesta la scrittura vengano trasmessi con una singola
142 \func{write}.
143
144 \begin{figure}[!htb]
145   \footnotesize
146   \begin{lstlisting}{}
147 void ServEcho(int sockfd) {
148     char buffer[MAXLINE];
149     int nread, nwrite;
150     
151     /* main loop, reading 0 char means client close connection */
152     while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
153         nwrite = SockWrite(sockfd, buffer, nread);
154     }
155     return;
156 }
157   \end{lstlisting}
158   \caption{Codice della prima versione della funzione \code{ServEcho} per la
159     gestione del servizio \texttt{echo}.}
160   \label{fig:TCPsimpl_server_elem_sub}
161 \end{figure}
162
163 Quando il client chiude la connessione il ricevimento del FIN fa ritornare la
164 \func{read} con un numero di byte letti pari a zero, il che causa l'uscita
165 dal ciclo e il ritorno della funzione, che a sua volta causa la terminazione
166 del processo figlio.
167
168
169 \subsection{Il client}
170 \label{sec:TCPsimp_client_main}
171
172 Il codice del client è riportato in \figref{fig:TCPsimpl_client_elem}, anche
173 esso ricalca la struttura del precedente client per il servizio
174 \texttt{daytime} (vedi \secref{sec:net_cli_sample}) ma, come per il server, lo
175 si è diviso in due parti, inserendo la parte relativa alle operazioni
176 specifiche previste per il protocollo \texttt{echo} in una funzione a parte.
177 \begin{figure}[!htb]
178   \footnotesize
179   \begin{lstlisting}{}
180 int main(int argc, char *argv[])
181 {
182 /* 
183  * Variables definition  
184  */
185     int sock_fd, i;
186     struct sockaddr_in serv_add;
187     ...
188     /* create socket */
189     if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
190         perror("Socket creation error");
191         return -1;
192     }
193     /* initialize address */
194     memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
195     serv_add.sin_family = AF_INET;                   /* address type is INET */
196     serv_add.sin_port = htons(7);                    /* echo port is 7 */
197     /* build address using inet_pton */
198     if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
199         perror("Address creation error");
200         return -1;
201     }
202     /* extablish connection */
203     if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
204         perror("Connection error");
205         return -1;
206     }
207     /* read daytime from server */
208     ClientEcho(stdin, sock_fd);
209     /* normal exit */
210     return 0;
211 }
212   \end{lstlisting}
213   \caption{Codice della prima versione del client \texttt{echo}.}
214   \label{fig:TCPsimpl_client_elem}
215 \end{figure}
216
217 La funzione \code{main} si occupa della creazione del socket e della
218 connessione (linee \texttt{\small 10--27}) secondo la stessa modalità spiegata
219 in \secref{sec:net_cli_sample}, il client si connette sulla porta 7
220 all'indirizzo specificato dalla linea di comando (a cui si è aggiunta una
221 elementare gestione delle opzioni non riportata in figura).
222
223 Completata la connessione, al ritrno fiììdi  \func{connect} è ritornata, la
224 funzione \code{ClientEcho}, riportata in
225 \figref{fig:TCPsimpl_client_echo_sub}, si preoccupa di gestire la
226 comunicazione, leggendo una riga alla volta dallo \file{stdin}, scrivendola
227 sul socket e ristampando su \file{stdout} quanto ricevuto in risposta dal
228 server.
229
230 \begin{figure}[!htb]
231   \footnotesize
232   \begin{lstlisting}{}
233 void ClientEcho(FILE * filein, int socket) 
234 {
235     char sendbuff[MAXLINE], recvbuff[MAXLINE];
236     int nread; 
237     while (fgets(sendbuff, MAXLINE, filein) != NULL) {
238         SockWrite(socket, sendbuff, strlen(sendbuff)); 
239         nread = SockRead(socket, recvbuff, strlen(sendbuff));        
240         recvbuff[nread] = 0;
241         fputs(recvbuff, stdout);
242     }
243     return;
244 }
245   \end{lstlisting}
246   \caption{Codice della prima versione della funzione \texttt{ClientEcho} per 
247     la gestione del servizio \texttt{echo}.}
248   \label{fig:TCPsimpl_client_echo_sub}
249 \end{figure}
250
251 La funzione utilizza due buffer per gestire i dati inviati e letti sul socket
252 (\texttt{\small 3}).  La comunicazione viene gestita all'interno di un ciclo
253 (linee \texttt{\small 5--10}), i dati da inviare sulla connessione vengono
254 presi dallo \file{stdin} usando la funzione \func{fgets} che legge una
255 linea di testo (terminata da un \texttt{CR} e fino al massimo di
256 \const{MAXLINE} caratteri) e la salva sul buffer di invio, la funzione
257 \func{SockWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
258 l'invio multiplo qualora una singola \func{write} non basti, come spiegato
259 in \secref{sec:sock_io_behav}).
260
261 I dati che vengono riletti indietro con una \func{SockRead} sul buffer di
262 ricezione e viene inserita la terminazione della stringa (\texttt{\small
263   7--8}) e per poter usare la funzione \func{fputs} per scriverli su
264 \file{stdout}. 
265
266 Un end of file inviato su \file{stdin} causa il ritorno di \func{fgets}
267 con un puntatore nullo e l'uscita dal ciclo, al che la subroutine ritorna ed
268 il client esce.
269
270
271 \section{Il funzionamento del servizio}
272 \label{sec:TCPsimpl_normal_work}
273
274 Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
275 di considerare in dettaglio tutte le problematiche che si possono incontrare
276 nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue
277 modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
278 che avviene nelle varie situazioni limite, da una parte potremo approfondire
279 la comprensione del protocollo TCP/IP e dall'altra ricavare le indicazioni
280 necessarie per essere in grado di scrivere applicazioni robuste, in grado di
281 gestire anche i casi limite.
282
283
284 \subsection{L'avvio e il funzionamento}
285 \label{sec:TCPsimpl_startup}
286
287 Il primo passo è compilare e lanciare il server (da root, per poter usare la
288 porta 7 che è riservata), alla partenza esso eseguirà l'apertura passiva con
289 la sequenza delle chiamate a \func{socket}, \func{bind}, \func{listen} e poi
290 si bloccherà nella \func{accept}. A questo punto si potrà controllarne lo
291 stato con \cmd{netstat}:
292 \begin{verbatim}
293 [piccardi@roke piccardi]$ netstat -at
294 Active Internet connections (servers and established)
295 Proto Recv-Q Send-Q Local Address           Foreign Address         State 
296 ...
297 tcp        0      0 *:echo                  *:*                     LISTEN
298 ...
299 \end{verbatim} %$
300 che ci mostra come il socket sia in ascolto sulla porta richiesta, accettando
301 connessioni da qualunque indirizzo e da qualunque porta e su qualunque
302 interfaccia locale.
303
304 A questo punto si può lanciare il client, esso chiamerà \func{socket} e
305 \func{connect}; una volta completato il three way handshake la connessione è
306 stabilita; la \func{connect} ritornerà nel client\footnote{si noti che è
307   sempre la \func{connect} del client a ritornare per prima, in quanto
308   questo avviene alla ricezione del secondo segmento (l'ACK del server) del
309   three way handshake, la \func{accept} del server ritorna solo dopo
310   un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene
311   ricevuto.} e la \func{accept} nel server, ed usando di nuovo
312 \cmd{netstat} otterremmo che:
313 \begin{verbatim}
314 Active Internet connections (servers and established)
315 Proto Recv-Q Send-Q Local Address           Foreign Address         State
316 tcp        0      0 *:echo                  *:*                     LISTEN
317 tcp        0      0 roke:echo               gont:32981              ESTABLISHED
318 \end{verbatim}
319 mentre per quanto riguarda l'esecuzione dei programmi avremo che:
320 \begin{itemize}
321 \item il client chiama la funzione \code{ClientEcho} che si blocca sulla
322   \func{fgets} dato che non si è ancora scritto nulla sul terminale.
323 \item il server eseguirà una \func{fork} facendo chiamare al processo figlio
324   la funzione \code{ServEcho}, quest'ultima si bloccherà sulla \func{read}
325   dal socket sul quale ancora non sono presenti dati.
326 \item il processo padre del server chiamerà di nuovo \func{accept}
327   bloccandosi fino all'arrivo di un'altra connessione.
328 \end{itemize}
329 e se usiamo il comando \cmd{ps} per esaminare lo stato dei processi otterremo
330 un risultato del tipo:
331 \begin{verbatim}
332 [piccardi@roke piccardi]$ ps ax
333   PID TTY      STAT   TIME COMMAND
334  ...  ...      ...    ...  ...
335  2356 pts/0    S      0:00 ./echod
336  2358 pts/1    S      0:00 ./echo 127.0.0.1
337  2359 pts/0    S      0:00 ./echod
338 \end{verbatim} %$
339 (dove si sono cancellate le righe inutili) da cui si evidenzia la presenza di
340 tre processi, tutti in stato di \textit{sleep} (vedi
341 \tabref{tab:proc_proc_states}).
342
343 Se a questo punto si inizia a scrivere qualcosa sul client non sarà trasmesso
344 niente fin tanto che non si prema il tasto di a capo (si ricordi quanto detto
345 in \secref{sec:file_line_io} a proposito dell'I/O su terminale), solo allora
346 \func{fgets} ritornerà ed il client scriverà quanto immesso sul socket, per
347 poi passare a rileggere quanto gli viene inviato all'indietro dal server, che
348 a sua volta sarà inviato sullo standard output, che nel caso ne provoca
349 l'immediatamente stampa a video.
350
351
352 \subsection{La conclusione normale}
353 \label{sec:TCPsimpl_conclusion}
354
355 Tutto quello che scriveremo sul client sarà rimandato indietro dal server e
356 ristampato a video fintanto che non concluderemo l'immissione dei dati; una
357 sessione tipica sarà allora del tipo: 
358 \begin{verbatim}
359 [piccardi@roke sources]$ ./echo 127.0.0.1
360 Questa e` una prova
361 Questa e` una prova
362 Ho finito
363 Ho finito
364 \end{verbatim} %$
365 che termineremo inviando un EOF dal terminale (usando la combinazione di tasti
366 ctrl-D, che non compare a schermo); se eseguiamo un \cmd{netstat} a questo
367 punto avremo:
368 \begin{verbatim}
369 [piccardi@roke piccardi]$ netstat -at 
370 tcp        0      0 *:echo                  *:*                     LISTEN
371 tcp        0      0 localhost:33032         localhost:echo          TIME_WAIT
372 \end{verbatim} %$
373 con il client che entra in \texttt{TIME\_WAIT}.
374
375 Esaminiamo allora in dettaglio la sequenza di eventi che porta alla
376 terminazione normale della connessione, che ci servirà poi da riferimento
377 quando affronteremo il comportamento in caso di conclusioni anomale:
378
379 \begin{enumerate}
380 \item inviando un carattere di EOF da terminale la \func{fgets} ritorna
381   restituendo un puntatore nullo che causa l'uscita dal ciclo di
382   \code{while}, così la \code{ClientEcho} ritorna.
383 \item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e
384   come parte del processo terminazione tutti i file descriptor vengono chiusi
385   (si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
386   la chiusura del socket di comunicazione; il client allora invierà un FIN al
387   server a cui questo risponderà con un ACK.  A questo punto il client verrà a
388   trovarsi nello stato \texttt{FIN\_WAIT\_2} ed il server nello stato
389   \texttt{CLOSE\_WAIT} (si riveda quanto spiegato in
390   \secref{sec:TCPel_conn_term}).
391 \item quando il server riceve il FIN la \func{read} del processo figlio che
392   gestisce la connessione ritorna restituendo 0 causando così l'uscita dal
393   ciclo e il ritorno di \code{ServEcho}, a questo punto il processo figlio
394   termina chiamando \func{exit}.
395 \item all'uscita del figlio tutti i file descriptor vengono chiusi, la
396   chiusura del socket connesso fa sì che venga effettuata la sequenza finale
397   di chiusura della connessione, viene emesso un FIN dal server che riceverà
398   un ACK dal client, a questo punto la connessione è conclusa e il client
399   resta nello stato \texttt{TIME\_WAIT}.
400
401 \end{enumerate}
402
403
404 \subsection{La gestione dei processi figli}
405 \label{sec:TCPsimpl_child_hand}
406
407 Tutto questo riguarda la connessione, c'è però da tenere conto dell'effetto
408 del procedimento di chiusura del processo figlio nel server (si veda quanto
409 esaminato in \secref{sec:proc_termination}). In questo caso avremo l'invio del
410 segnale \const{SIGCHLD} al padre, ma dato che non si è installato un
411 manipolatore e che l'azione predefinita per questo segnale è quella di essere
412 ignorato, non avendo predisposto la ricezione dello stato di terminazione,
413 otterremo che il processo figlio entrerà nello stato di zombie (si riveda
414 quanto illustrato in \secref{sec:sig_sigchld}), come risulterà ripetendo il
415 comando \cmd{ps}:
416 \begin{verbatim}
417  2356 pts/0    S      0:00 ./echod
418  2359 pts/0    Z      0:00 [echod <defunct>]
419 \end{verbatim}
420
421 Poiché non è possibile lasciare processi zombie che pur inattivi occupano
422 spazio nella tabella dei processi e a lungo andare saturerebbero le risorse
423 del kernel, occorrerà ricevere opportunamente lo stato di terminazione del
424 processo (si veda \secref{sec:proc_wait}), cosa che faremo utilizzando
425 \const{SIGCHLD} secondo quanto illustrato in \secref{sec:sig_sigchld}.
426
427 La prima modifica al nostro server è pertanto quella di inserire la gestione
428 della terminazione dei processi figli attraverso l'uso di un manipolatore.
429 Per questo useremo la funzione \code{Signal}, illustrata in
430 \figref{fig:sig_Signal_code}, per installare il semplice manipolatore che
431 riceve i segnali dei processi figli terminati già visto in 
432 \figref{fig:sig_sigchld_handl}; aggiungendo il seguente codice:
433 \begin{lstlisting}{}
434     ...
435     /* install SIGCHLD handler */
436     Signal(SIGCHLD, sigchld_hand);  /* establish handler */
437     /* create socket */
438     ...
439 \end{lstlisting}
440
441 \noindent
442 all'esempio illustrato in \figref{fig:TCPsimpl_serv_code}, e linkando il tutto
443 alla funzione \code{sigchld\_hand}, si risolverà completamente il problema
444 degli zombie.
445
446
447
448 %%% Local Variables: 
449 %%% mode: latex
450 %%% TeX-master: "gapil"
451 %%% End: