Due correzioni dell'indirizzo del CVS.
[gapil.git] / tcpsockadv.tex
index c8e9ec4ace77b08e43c309aaffb01e43d0136737..991fe0494a2590eac0e2ade576fd81e167d1d7df 100644 (file)
@@ -688,7 +688,7 @@ conseguente blocco del server su di una \func{write}.
 Le possibili soluzioni in questo caso sono quelle di ritornare ad eseguire il
 ciclo di risposta alle richieste all'interno di processi separati, utilizzare
 un timeout per le operazioni di scrittura, o eseguire queste ultime in
-modalità non bloccante, cocludendo le operazioni qualora non vadano a buon
+modalità non bloccante, concludendo le operazioni qualora non vadano a buon
 fine.
 
 
@@ -700,8 +700,7 @@ Finora abbiamo trattato le problematiche risolubili con l'I/O multiplexing
 impiegando la funzione \func{select}; questo è quello che avviene nella
 maggior parte dei casi, in quanto essa è nata sotto BSD proprio per affrontare
 queste problematiche con i socket.  Abbiamo però visto in
-\secref{sec:file_multiplexing} come esistono altre funzioni che permettono di
-affrontare lo stesso problema e come la funzione \func{poll} possa costituire
+\secref{sec:file_multiplexing} come la funzione \func{poll} possa costituire
 una alternativa a \func{select}, con alcuni vantaggi.\footnote{non soffrendo
   delle limitazioni dovute all'uso dei \textit{file descriptor set}.}
 
@@ -734,11 +733,107 @@ pertanto:
 Come esempio dell'uso di \func{poll} proviamo allora a reimplementare il
 server \textit{echo} secondo lo schema di \figref{fig:TCP_echo_multiplex}
 usando \func{poll} al posto di \func{select}. In questo caso dovremo fare
-qualche modifica, 
-
+qualche modifica, per tenere conto della diversa sintassi delle due funzioni,
+ma la struttura del programma resta sostanzialmente la stessa.
 
 
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15.6cm}
+    \includecodesample{listati/poll_echod.c}
+  \end{minipage} 
+  \normalsize
+  \caption{La sezione principale del codice della nuova versione di server
+    \textit{echo} basati sull'uso della funzione \func{poll}.}
+  \label{fig:TCP_PollEchod}
+\end{figure}
 
+In \figref{fig:TCP_PollEchod} è riportata la sezione principale della nuova
+versione del server, la versione completa del codice è riportata nel file
+\file{poll\_echod.c} dei sorgenti allegati alla guida. Al solito nella figura
+si sono tralasciate la gestione delle opzioni, la creazione del socket in
+ascolto, la cessione dei privilegi e le operazioni necessarie a far funzionare
+il programma come demone, privilegiando la sezione principale del programma.
+
+Come per il precedente server basato su \func{select} il primo passo
+(\texttt{\small 2--8}) è quello di inizializzare le variabili necessarie. Dato
+che in questo caso dovremo usare un vettore di strutture occorre anzitutto
+(\texttt{\small 2}) allocare la memoria necessaria utilizzando il numero
+massimo \var{n} di socket osservabili, che viene impostato attraverso
+l'opzione \texttt{-n} ed ha un valore di default di 256. 
+
+Dopo di che si preimposta (\texttt{\small 3}) il valore \var{max\_fd} del file
+descriptor aperto con valore più alto a quello del socket in ascolto (al
+momento l'unico), e si provvede (\texttt{\small 4--7}) ad inizializzare le
+strutture, disabilitando (\texttt{\small 5}) l'osservazione con un valore
+negativo del campo \var{fd} ma predisponendo (\texttt{\small 6}) il campo
+\var{events} per l'osservazione dei dati normali con \const{POLLRDNORM}.
+Infine (\texttt{\small 8}) si attiva l'osservazione del socket in ascolto
+inizializzando la corrispondente struttura. Questo metodo comporta, in
+modalità interattiva, lo spreco di tre strutture (quelle relative a standard
+input, output ed error) che non vengono mai utilizzate in quanto la prima è
+sempre quella relativa al socket in ascolto.
+
+Una volta completata l'inizializzazione tutto il lavoro viene svolto
+all'interno del ciclo principale \texttt{\small 10--55}) che ha una struttura
+sostanzialmente identica a quello usato per il precedente esempio basato su
+\func{select}. La prima istruzione (\texttt{\small 11--12}) è quella di
+eseguire \func{poll} all'interno di un ciclo che la ripete qualora venisse
+interrotta da un segnale, da cui si esce soltanto quando la funzione ritorna,
+restituendo nella variabile \var{n} il numero di file descriptor trovati
+attivi.  Qualora invece si sia ottenuto un errore si procede (\texttt{\small
+  13--16}) alla terminazione immediata del processo provvedendo a stampare una
+descrizione dello stesso.
+
+Una volta ottenuta dell'attività su un file descriptor si hanno di nuovo due
+possibilità. La prima possibilità è che ci sia attività sul socket in ascolto,
+indice di una nuova connessione, nel qual caso si controlla (\texttt{\small
+  17}) se il campo \var{revents} della relativa struttura è attivo; se è così
+si provvede (\texttt{\small 18}) a decrementare la variabile \var{n} (che
+assume il significato di numero di file descriptor attivi rimasti da
+controllare) per poi (\texttt{\small 19--23}) effettuare la chiamata ad
+\func{accept}, terminando il processo in caso di errore. Se la chiamata ad
+\func{accept} ha successo si procede attivando (\texttt{\small 24}) la
+struttura relativa al nuovo file descriptor da essa ottenuto, modificando
+(\texttt{\small 24}) infine quando necessario il valore massimo dei file
+descriptor aperti mantenuto in \var{max\_fd}.
+
+La seconda possibilità è che vi sia dell'attività su uno dei socket aperti in
+precedenza, nel qual caso si inizializza (\texttt{\small 27}) l'indice \var{i}
+del vettore delle strutture \struct{pollfd} al valore del socket in ascolto,
+dato che gli ulteriori socket aperti avranno comunque un valore superiore.  Il
+ciclo (\texttt{\small 28--54}) prosegue fintanto che il numero di file
+descriptor attivi, mantenuto nella variabile \var{n}, è diverso da zero. Se
+pertanto ci sono ancora socket attivi da individuare si comincia con
+l'incrementare (\texttt{\small 30}) l'indice e controllare (\texttt{\small
+  31}) se corrisponde ad un file descriptor in uso analizzando il valore del
+campo \var{fd} della relativa struttura e chiudendo immediatamente il ciclo
+qualora non lo sia. Se invece il file descriptor è in uso si verifica
+(\texttt{\small 31}) se c'è stata attività controllando il campo
+\var{revents}. 
+
+Di nuovo se non si verifica la presenza di attività il ciclo si chiude subito,
+altrimenti si provvederà (\texttt{\small 32}) a decrementare il numero \var{n}
+di file descriptor attivi da controllare e ad eseguire (\texttt{\small 33}) la
+lettura, ed in caso di errore (\texttt{\small 34--37}) al solito lo si
+notificherà uscendo immediatamente. Qualora invece si ottenga una condizione
+di end-of-file (\texttt{\small 38--47}) si provvederà a chiudere
+(\texttt{\small 39}) anche il nostro capo del socket e a marcarlo
+(\texttt{\small 40}) nella struttura ad esso associata come inutilizzato.
+Infine dovrà essere ricalcolato (\texttt{\small 41--45}) un eventiale nuovo
+valore di \var{max\_fd}. L'ultimo passo è (\texttt{\small 46}) chiudere il
+ciclo in quanto in questo caso non c'è più niente da riscrivere all'indietro
+sul socket.
+
+Se invece si sono letti dei dati si provvede (\texttt{\small 48}) ad
+effettuarne la riscrittura all'indietro, con il solito controllo ed eventuale
+uscita e notifica in caso si errore (\texttt{\small 49--52}).
+
+Come si può notare la logica del programma è identica a quella vista in
+\figref{fig:TCP_SelectEchod} per l'analogo server basato su \func{select}; la
+sola differenza significativa è che in questo caso non c'è bisogno di
+rigenerare i file descriptor set in quanto l'uscita è indipendente dai dati in
+ingresso. 
 
 
 \section{Le opzioni dei socket}