From af65119453850f0d2f50d38769bada5bcb8b729d Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 8 Nov 2003 17:27:11 +0000 Subject: [PATCH] Revisione della sezione su shutdown, iniziato lavoro sulla versione multiplexed del server echo, fatta figura esplicativa. --- biblio.bib | 2 +- html/gapil.html | 8 ++- img/TCPechoMult.dia | Bin 0 -> 1784 bytes tcpsockadv.tex | 127 ++++++++++++++++++++++++++------------------ 4 files changed, 84 insertions(+), 53 deletions(-) create mode 100644 img/TCPechoMult.dia diff --git a/biblio.bib b/biblio.bib index 3b6cf3b..79f88b4 100644 --- a/biblio.bib +++ b/biblio.bib @@ -17,7 +17,7 @@ @Book{TCPIll1, author = {W. Richard Stevens}, editor = {}, - title = {TCP/IP Illustrated, the protocols}, + title = {TCP/IP Illustrated, Volume 1, the protocols}, publisher = {Addison Wesley}, year = {1994}, OPTkey = {}, diff --git a/html/gapil.html b/html/gapil.html index 133db1e..8ce6a23 100644 --- a/html/gapil.html +++ b/html/gapil.html @@ -252,7 +252,7 @@

- Versione corrente: 485 pagine. + Versione corrente: 491 pagine.

@@ -266,10 +266,16 @@ + 8 - novembre - 2003
Corretta tabella sbagliata al + capitolo 5, completata la sezione sull'uso dell'I/O multiplexing + sul lato client ed iniziata la versione server, inserita la + trattazione della funzione shutdown. +

21 - settembre - 2003
Completato il capitolo sui socket elementari, e corretti numerosi errori. Revisione della sezione sull'I/O multiplexing nel capitolo sui file avanzati in vista dell'uso nel capitolo sui socket TCP avanzati. +

6 - aprile - 2003
Grazie all'incredibile lavoro di Mirko Maischberger abbiamo una favolosa versione in HTML, che diff --git a/img/TCPechoMult.dia b/img/TCPechoMult.dia new file mode 100644 index 0000000000000000000000000000000000000000..ed7a737939cbab1adddaf47ce69c9076a50718a1 GIT binary patch literal 1784 zcmV$J*x$Z0fMhIz%%EN=POvL3MR>Uki8;)OuUG@Ndv7{tL!jIC)f`?^SzO*}8Jm?cq?4!#A^*m`@Pe_5lu z_oHXm){9yPYmx4ytky{usx`S?AFLf-r+=19nOcb#cW-}VZ;M-&FSNS9Tm|VOj7w3e z2%_RKi0u(V+CIe;L`noAB?XZZW|MW2$}|XNDQTJ{kqF{Km`pdKt*C4kMCv?_6vAx< z+=o&obz0m9QC6$Q=oy^a-DQ!6^9CSRmJY9a2E&!wvy0ke>dS=WKBC(4TX=RrCj+zdV@kJb}8D{2nsW9u)}@I*?AGOyk9u9N+4bDIru`*YWF zrqexgW=fw$BzB^x=O|&=b8a!RUF-~r&9Ku}wur=PGE35U&%xdG%w^>`KSDV*l(H1z zVkwWwq`jDFlFmiipboMTZB1;;l=AE%xIDoaNjojddccmG+WYFj$E{QD%{-AMmBxDQrgv{iQr;>;Rk za;r^VZFKSOPst_?l?k+bzy^3C+iM*Woq2qDELIbjq5P|@6y>rP@k;D>O2nJh84jT} z-s^dkn8F>aXlJNM4+8T_7FSG)Y)3OGvk}&`N`RQuRMQhwieaeKK$%xXrS;IFouCEe zqf2O&PI?C|4-#51Ub=@?2WYX5(DFc`#h;)B7yp@R+CvK#T23cusq+Vf7SRdD4q8CUj>#62`t*f>N>FE-CzY8!qaL9&tOA%+K2Ghf|l0_S`0LV zXVnm%!G`dx58z2e z3taA1>bS}5tB`|P62~IT!dFw!b$tay5q-jo3Y_n_?T;poCnBEbYQCUzeeu_Cdn3NY!!JQslgmt#IlN1(99ZM=sTw_Q+V8LHU>3$VP0&6{0N zqaR2&xys3pycGf2o$qHeuUXeKZgmkAnZYz8Y)+j0h$gj}UvSlxMl?S~p@`)#GNNg8 zh(F_yCN}TG!Hf+QR9Z|86jTb>+Xa~z=!vuwk@{VTlmaE?Ih9hCgIB3k<>Wn;UW7^w zj`63QcsFkj4qcdJr=U|epOq=-l*7$4m?+s3DlnlE+=Wm%P{TPVRM#%plxtM+o=Gpj zr2H4}G85wl8OuvDAYnv47p5ymx4ca9F;qdnqGfGK$?MDcKYTeKyXN(L<%%!S6C<>X z*>ITZm@*sg)4X3rb;Z@CR1+B?$YqfBQ>t6@*UhB2o*&+N2s+<--2cgXSQqO78h6jF z$JN&3a^z^&!!YAqizkSJ8c?b6u>(@sgYIbi>dw6>y#hz%oo`CcnWof~wK!d}76xNV z#MVV1KQ96imBHXVhjFe`1hU_#?_Vf$F*w6lUIP-})s8p067wb{GZ`v91%Cy7pZoss zM#;mNA?Fr5Hbp3JfHU0QmrTX?N#kVFUfsh5Pl4d3>_;DdB8Ke^Z%A$WW0<}bwW^6e zl`IIWZOPIr4Aj&CqJzVg2^|IpuFw(GO7`gX+)AP;c`G$7j8}E{Q z<8|O03KQk*_(mCVm2Z5T`n-LQ;sw5;^&yV0ZsRra4aN<0V^C)6>87Wf%hL@vr<>Yp a-V1ay+JAoM^AGpDd-EUZn^1c%SpWbPOJw%| literal 0 HcmV?d00001 diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 42367de..d2e58fe 100644 --- a/tcpsockadv.tex +++ b/tcpsockadv.tex @@ -365,7 +365,7 @@ Ci si pu quando questa sembra rendere \funcd{shutdown} del tutto equivalente ad una \func{close}. In realtà non è così, esiste infatti un'altra differenza con \func{close}, più sottile. Finora infatti non ci siamo presi la briga di -sottolineare in maniera esplicita che come per i file e le fifo, anche per i +sottolineare in maniera esplicita che, come per i file e le fifo, anche per i socket possono esserci più riferimenti contemporanei ad uno stesso socket. Per cui si avrebbe potuto avere l'impressione che sia una corrispondenza univoca fra un socket ed il file descriptor con cui vi si accede. Questo non è @@ -377,30 +377,32 @@ fanno riferimento allo stesso socket. Allora se avviene uno di questi casi quello che succederà è che la chiamata a \func{close} darà effettivamente avvio alla sequenza di chiusura di un socket soltanto quando il numero di riferimenti a quest'ultimo diventerà nullo. -Fintanto che ci sono file descriptor che fanno riferimento ad un socket -\func{close} si limiterà a deallocare nel processo corrente il file descriptor -utilizzato, ma il socket resterà pienamente accessibile attraverso gli altri -riferimenti.Se torniamo all'esempio di \figref{fig:TCP_echo_server_first_code} -abbiamo infatti che le due \func{close} (sul socket connesso nel padre e sul -socket in ascolto nel figlio), restando comunque altri riferimenti attivi (al -socket connesso nel figlio e a quello in ascolto nel padre) non effettuano -nessuna chiusura effettiva. - -Questo non avviene affatto se si usa \func{shutdown} al posto di \func{close}, -in questo caso infatti la chiusura del socket viene effettuata immediatamente, -indipendentemente dalla presenza di altri riferimenti attivi, e pertanto sarà -ovviamente efficace anche per tutti gli altri file descriptor con cui si fa +Fintanto che ci sono file descriptor che fanno riferimento ad un socket l'uso +di \func{close} si limiterà a deallocare nel processo corrente il file +descriptor utilizzato, ma il socket resterà pienamente accessibile attraverso +tutti gli altri riferimenti. Se torniamo all'esempio originale del server di +\figref{fig:TCP_echo_server_first_code} abbiamo infatti che ci sono due +\func{close}, una sul socket connesso nel padre, ed una sul socket in ascolto +nel figlio, ma queste non effettuano nessuna chiusura reale di detti socket, +dato che restano altri riferimenti attivi, uno al socket connesso nel figlio +ed uno a quello in ascolto nel padre. + +Questo non avviene affatto se si usa \func{shutdown} con argomento +\macro{SHUT\_RDWR} al posto di \func{close}; in questo caso infatti la +chiusura del socket viene effettuata immediatamente, indipendentemente dalla +presenza di altri riferimenti attivi, e pertanto sarà efficace anche per tutti +gli altri file descriptor con cui, nello stesso o in altri processi, si fa riferimento allo stesso socket. Il caso più comune di uso di \func{shutdown} è comunque quello della chiusura del lato in scrittura, per segnalare all'altro capo della connessione che si è concluso l'invio dei dati, restando comunque in grado di ricevere quanto -ancora questi potrà inviarci. Questo è ad esempio l'uso che ci serve per -rendere finalmente completo il nostro esempio sul servizio echo. Il nostro -client infatti presenta ancora un problema, che nell'uso che finora ne abbiamo -fatto non è emerso, ma che ci aspetta dietro l'angolo non appena usciamo -dall'uso interattivo e proviamo ad eseguirlo redirigendo standard input e -standard output. Così se eseguiamo: +questi potrà ancora inviarci. Questo è ad esempio l'uso che ci serve per +rendere finalmente completo il nostro esempio sul servizio \textit{echo}. Il +nostro client infatti presenta ancora un problema, che nell'uso che finora ne +abbiamo fatto non è emerso, ma che ci aspetta dietro l'angolo non appena +usciamo dall'uso interattivo e proviamo ad eseguirlo redirigendo standard +input e standard output. Così se eseguiamo: \begin{verbatim} [piccardi@gont sources]$ ./echo 192.168.1.1 < ../fileadv.tex > copia \end{verbatim}%$ @@ -413,30 +415,32 @@ dimensione massima pari a \texttt{MAXLINE} per poi scriverlo, alla massima velocità consentitagli dalla rete, sul socket. Dato che la connessione è con una macchina remota occorre un certo tempo perché i pacchetti vi arrivino, vengano processati, e poi tornino indietro. Considerando trascurabile il tempo -di processo, questo tempo, detto RTT (da \textit{Round Trip Time} può essere -stimato con l'uso del comando \cmd{ping}. Ma mantre il pacchetti sono in -transito sulla rete il client continua a leggere e a scrivere fintanto che il -file in ingresso finisce. +di processo, questo tempo è quello impiegato nella trasmissione via rete, che +viene detto RTT (da \textit{Round Trip Time}, e può essere stimato con l'uso +del comando \cmd{ping}. A questo punto, se torniamo al codice mostrato in -\figref{fig:TCP_ClientEcho_third}, notiamo che non appena viene ricevuto un -end-of-file in ingresso il nostro client termina. Nel caso interattivo, in cui -si inviavano brevi stringe una alla volta, c'era sempre il tempo di eseguire -la lettura completa di quanto il server rimandava indietro. In questo caso -però quando il client termina, essendo la comunicazione a piena velocità, ci -saranno ancora pacchetti in transito sulla rete, ma siccome il client esce +\figref{fig:TCP_ClientEcho_third}, possiamo vedere che mentre i pacchetti sono +in transito sulla rete il client continua a leggere e a scrivere fintanto che +il file in ingresso finisce. Però che non appena viene ricevuto un end-of-file +in ingresso il nostro client termina. Nel caso interattivo, in cui si +inviavano brevi stringhe una alla volta, c'era sempre il tempo di eseguire la +lettura completa di quanto il server rimandava indietro. In questo caso +invece, quando il client termina, essendo la comunicazione saturata e a piena +velocità, ci saranno ancora pacchetti in transito sulla rete che devono +arrivare al server e poi tornare indietro, ma siccome il client esce immediatamente dopo la fine del file in ingresso, questi non faranno a tempo a completare il percorso e verranno persi. -Per evitare questo tipo di problema occorre, invece di uscire, usare -\func{shutdown} per effettuare la chiusura del socket in scrittura una volta -completata la lettura del file in ingresso. In questo modo il client segnalerà -al server la chiusura del flusso dei dati, ma potrà continuare a leggere -quanto il server gli sta ancora inviando fino a quando quest'ultimo, -riconosciuta la chiusura del socket in scrittura da parte del client, -effettuerà la chiusura dello stesso a sua volta. Solo alla ricezione della -chiusura del socket da parte del server, si potrà essere sicuri della -ricezione di tutti i dati prima della terminazione della connessione. +Per evitare questo tipo di problema, invece di uscire occorre usare +\func{shutdown} per effettuare la chiusura del lato in scrittura del socket, +una volta completata la lettura del file in ingresso. In questo modo il client +segnalerà al server la chiusura del flusso dei dati, ma potrà continuare a +leggere quanto il server gli sta ancora inviando indietro fino a quando anche +lui, riconosciuta la chiusura del socket in scrittura da parte del client, +effettuerà la chiusura dalla sua parte. Solo alla ricezione della chiusura del +socket da parte del server si potrà essere sicuri della ricezione di tutti i +dati e della terminazione effettiva della connessione. \begin{figure}[!htb] \footnotesize \centering @@ -472,19 +476,20 @@ successiva (\texttt{\small 16}) chiamata a \func{select}. Le maggiori modifiche rispetto alla precedente versione sono invece nella gestione (\texttt{\small 18--22}) del caso in cui la lettura con \func{fgets} -restitisca un valore nullo, indice della fine del file, che prima causava -l'immediato ritorno della funzione. In questo caso prima (\texttt{\small 19}) -si imposta opportunamente \var{eof} ad un valore non nullo, dopo di che -(\texttt{\small 20}) si effettua la chiusura del lato in scrittura del socket -con \func{shutdown}. Infine (\texttt{\small 21}) si usa la macro -\macro{FD\_CLR} per togliere lo standard input dal file descriptor set. +restituisce un valore nullo, indice della fine del file. Questa nella +precedente versione causava l'immediato ritorno della funzione; in questo caso +prima (\texttt{\small 19}) si imposta opportunamente \var{eof} ad un valore +non nullo, dopo di che (\texttt{\small 20}) si effettua la chiusura del lato +in scrittura del socket con \func{shutdown}. Infine (\texttt{\small 21}) si +usa la macro \macro{FD\_CLR} per togliere lo standard input dal file +descriptor set. In questo modo anche se la lettura del file in ingresso è conclusa, la funzione non esce dal ciclo principale (\texttt{\small 11--50}), ma continua ad eseguirlo ripetendo la chiamata a \func{select} per tenere sotto controllo soltanto il socket connesso, dal quale possono arrivare altri dati, che saranno letti (\texttt{\small 31}), ed opportunamente trascritti -(\texttt{\small 44--48}) sullo standard input. +(\texttt{\small 44--48}) sullo standard output. Il ritorno della funzione, e la conseguente terminazione normale del client, viene invece adesso gestito all'interno (\texttt{\small 30--49}) della lettura @@ -495,15 +500,34 @@ diversa a seconda del valore di \var{eof}. Se infatti questa ingresso, vorrà dire che anche il server ha concluso la trasmissione dei dati restanti, e si potrà uscire senza errori, altrimenti si stamperà (\texttt{\small 40--42}) un messaggio di errore per la chiusura precoce della -connesione. +connessione. \subsection{Un server basato sull'I/O multiplexing} \label{sec:TCP_serv_select} -Vediamo ora come con l'utilizzo dell'I/O multiplexing diventi possibile -riscrivere il nostro server \textit{echo} in modo da evitare di dover creare -un nuovo processo tutte le volte che si ha una connessione. +Seguendo di nuovo le orme di Stevens in \cite{UNP1} vediamo ora come con +l'utilizzo dell'I/O multiplexing diventi possibile riscrivere completamente il +nostro server \textit{echo} con una architettura completamente diversa, in +modo da evitare di dover creare un nuovo processo tutte le volte che si ha una +connessione. + +La struttura del nuovo server è illustrata in \figref{fig:TCP_echo_multiplex}, +in questo caso avremo un solo processo che ad ogni nuova connessione da parte +del client sul socket in ascolto inserirà il socket connesso ad essa relativo +in una opportuna tabella, poi utilizzerà \func{select} per rilevare la +presenza di dati in arrivo su ciascun socket connesso, riutilizzandolo per +inviare i dati in risposta. + + +\begin{figure}[htb] + \centering + \includegraphics[width=13cm]{img/TCPechoMult} + \caption{Schema del nuovo server echo basato sull'I/O multiplexing.} + \label{fig:TCP_echo_multiplex} +\end{figure} + + \subsection{Un esempio di I/O multiplexing con \func{poll}} @@ -513,7 +537,8 @@ Abbiamo visto in \secref{sec:TCP_serv_select} come creare un server che utilizzi l'I/O multiplexing attraverso l'impiego della funzione \func{select}, ma in \secref{sec:file_multiplexing} abbiamo visto come la funzione \func{poll} costituisca una alternativa a \func{select} con delle funzionalità -migliori, vediamo allora come reimplementare il server di +migliori, vediamo allora come reimplementare il nostro servizio usando questa +funzione. \section{Le opzioni dei socket} -- 2.30.2