% conoscere il numero di chi si vuole chiamare. La funzione \func{accept} è
% quando si risponde al telefono.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=10cm]{img/three_way_handshake}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=10cm]{img/three_way_handshake}
\caption{Il \textit{three way handshake} del TCP.}
\label{fig:TCP_TWH}
\end{figure}
fig.~\ref{fig:TCP_close} si è rappresentato graficamente lo sequenza di
scambio dei segmenti che conclude la connessione.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=10cm]{img/tcp_close}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=10cm]{img/tcp_close}
\caption{La chiusura di una connessione TCP.}
\label{fig:TCP_close}
\end{figure}
pacchetti che avviene per una un esempio di connessione, insieme ai vari stati
che il protocollo viene ad assumere per i due lati, server e client.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=9cm]{img/tcp_connection}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=9cm]{img/tcp_connection}
\caption{Schema dello scambio di pacchetti per un esempio di connessione.}
\label{fig:TCP_conn_example}
\end{figure}
fig.~\ref{fig:TCP_port_alloc} sono riportate quelle di BSD e Linux.
\begin{figure}[!htb]
- \centering
- \includegraphics[width=13cm]{img/port_alloc}
+ \centering \includegraphics[width=13cm]{img/port_alloc}
\caption{Allocazione dei numeri di porta.}
\label{fig:TCP_port_alloc}
\end{figure}
\const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è
inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_}
(riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo
-\itindex{endianess} l'\textit{endianess} della macchina, ed anche se esse
+\itindex{endianness} l'\textit{endianness} della macchina, ed anche se esse
possono essere invarianti rispetto all'ordinamento dei bit, è comunque buona
norma usare sempre la funzione \func{htonl}.
secondi per un numero di volte che può essere stabilito dall'utente. Questo
può essere fatto a livello globale con una opportuna
\func{sysctl},\footnote{o più semplicemente scrivendo il valore voluto in
- \procfile{/proc/sys/net/ipv4/tcp\_syn\_retries}, vedi
+ \sysctlfile{net/ipv4/tcp\_syn\_retries}, vedi
sez.~\ref{sec:sock_ipv4_sysctl}.} e a livello di singolo socket con
l'opzione \const{TCP\_SYNCNT} (vedi sez.~\ref{sec:sock_tcp_udp_options}). Il
valore predefinito per la ripetizione dell'invio è di 5 volte, che comporta
vuota, il processo viene posto in attesa e risvegliato all'arrivo della prima
connessione completa.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=11cm]{img/tcp_listen_backlog}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=11cm]{img/tcp_listen_backlog}
\caption{Schema di funzionamento delle code delle connessioni complete ed
incomplete.}
\label{fig:TCP_listen_backlog}
della coda delle connessioni incomplete può essere ancora controllata usando
la funzione \func{sysctl} con il parametro \const{NET\_TCP\_MAX\_SYN\_BACKLOG}
o scrivendola direttamente in
-\procfile{/proc/sys/net/ipv4/tcp\_max\_syn\_backlog}. Quando si attiva la
+\sysctlfile{net/ipv4/tcp\_max\_syn\_backlog}. Quando si attiva la
protezione dei syncookies però (con l'opzione da compilare nel kernel e da
-attivare usando \procfile{/proc/sys/net/ipv4/tcp\_syncookies}) questo valore
+attivare usando \sysctlfile{net/ipv4/tcp\_syncookies}) questo valore
viene ignorato e non esiste più un valore massimo. In ogni caso in Linux il
valore di \param{backlog} viene troncato ad un massimo di \const{SOMAXCONN} se
è superiore a detta costante (che di default vale 128).\footnote{il valore di
generale non è così, e con i socket questo è particolarmente evidente.
-\begin{figure}[htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/FullRead.c}
\end{minipage}
\normalsize
disponibile fra i sorgenti allegati alla guida nei file \file{FullRead.c} e
\file{FullWrite.c}.
-\begin{figure}[htb]
+\begin{figure}[!htbp]
\centering
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/FullWrite.c}
\end{minipage}
\normalsize
sezione dei codici sorgente e può essere compilato su una qualunque macchina
GNU/Linux.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_daytime.c}
\end{minipage}
\normalsize
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_iter_daytimed.c}
\end{minipage}
\normalsize
client per volta; per questo si ricorre alle capacità di multitasking del
sistema.
-Come accennato anche in sez.~\ref{sec:proc_gen} una delle modalità più comuni
-di funzionamento da parte dei server è quella di usare la funzione \func{fork}
+Come spiegato in sez.~\ref{sec:proc_fork} una delle modalità più comuni di
+funzionamento da parte dei server è quella di usare la funzione \func{fork}
per creare, ad ogni richiesta da parte di un client, un processo figlio che si
incarichi della gestione della comunicazione. Si è allora riscritto il server
\textit{daytime} dell'esempio precedente in forma concorrente, inserendo anche
server, nel file \texttt{TCP\_cunc\_daytimed.c}, è allegato insieme ai
sorgenti degli altri esempi.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_cunc_daytimed.c}
\end{minipage}
\normalsize
sez.~\ref{sec:TCP_daytime_client}), e la prima parte (\texttt{\small 10--27})
è sostanzialmente identica, a parte l'uso di una porta diversa.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6 cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_echo_first.c}
\end{minipage}
\normalsize
stringa e per poter usare (\texttt{\small 9}) la funzione \func{fputs} per
scriverli su \file{stdout}.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ClientEcho_first.c}
\end{minipage}
\normalsize
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_echod_first.c}
\end{minipage}
\normalsize
(\texttt{\small 5}) semplicemente la funzione \func{perror} per stampare sullo
standard error.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/PrintErr.c}
\end{minipage}
\normalsize
dati di cui è richiesta la scrittura vengano trasmessi con una singola
\func{write}.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ServEcho_first.c}
\end{minipage}
\normalsize
restituendo un puntatore nullo che causa l'uscita dal ciclo di \code{while},
così la funzione \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
+ come parte del processo di terminazione tutti i file descriptor vengono chiusi
(si ricordi quanto detto in sez.~\ref{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
Tutto questo riguarda la connessione, c'è però da tenere conto dell'effetto
del procedimento di chiusura del processo figlio nel server (si veda quanto
esaminato in sez.~\ref{sec:proc_termination}). In questo caso avremo l'invio
-del segnale \const{SIGCHLD} al padre, ma dato che non si è installato un
+del segnale \signal{SIGCHLD} al padre, ma dato che non si è installato un
gestore e che l'azione predefinita per questo segnale è quella di essere
ignorato, non avendo predisposto la ricezione dello stato di terminazione,
-otterremo che il processo figlio entrerà nello stato di \index{zombie} zombie
-(si riveda quanto illustrato in sez.~\ref{sec:sig_sigchld}), come risulterà
-ripetendo il comando \cmd{ps}:
+otterremo che il processo figlio entrerà nello stato di \itindex{zombie}
+\textit{zombie} (si riveda quanto illustrato in sez.~\ref{sec:sig_sigchld}),
+come risulterà ripetendo il comando \cmd{ps}:
\begin{verbatim}
2356 pts/0 S 0:00 ./echod
2359 pts/0 Z 0:00 [echod <defunct>]
\end{verbatim}
-Dato che non è il caso di lasciare processi \index{zombie} zombie, occorrerà
-ricevere opportunamente lo stato di terminazione del processo (si veda
-sez.~\ref{sec:proc_wait}), cosa che faremo utilizzando \const{SIGCHLD} secondo
-quanto illustrato in sez.~\ref{sec:sig_sigchld}. Una prima modifica al nostro
-server è pertanto quella di inserire la gestione della terminazione dei
+Dato che non è il caso di lasciare processi \itindex{zombie} \textit{zombie},
+occorrerà ricevere opportunamente lo stato di terminazione del processo (si
+veda sez.~\ref{sec:proc_wait}), cosa che faremo utilizzando \signal{SIGCHLD}
+secondo quanto illustrato in sez.~\ref{sec:sig_sigchld}. Una prima modifica al
+nostro server è pertanto quella di inserire la gestione della terminazione dei
processi figli attraverso l'uso di un gestore. Per questo useremo la funzione
\code{Signal} (che abbiamo illustrato in fig.~\ref{fig:sig_Signal_code}), per
installare il gestore che riceve i segnali dei processi figli terminati già
Vediamo allora cosa comporta tutto questo nel nostro caso: quando si chiude il
client, il processo figlio che gestisce la connessione terminerà, ed il padre,
-per evitare la creazione di zombie, riceverà il segnale \const{SIGCHLD}
-eseguendo il relativo gestore. Al ritorno del gestore però l'esecuzione nel
-padre ripartirà subito con il ritorno della funzione \func{accept} (a meno di
-un caso fortuito in cui il segnale arriva durante l'esecuzione del programma
-in risposta ad una connessione) con un errore di \errcode{EINTR}. Non avendo
-previsto questa eventualità il programma considera questo un errore fatale
-terminando a sua volta con un messaggio del tipo:
+per evitare la creazione di \itindex{zombie} \textit{zombie}, riceverà il
+segnale \signal{SIGCHLD} eseguendo il relativo gestore. Al ritorno del gestore
+però l'esecuzione nel padre ripartirà subito con il ritorno della funzione
+\func{accept} (a meno di un caso fortuito in cui il segnale arriva durante
+l'esecuzione del programma in risposta ad una connessione) con un errore di
+\errcode{EINTR}. Non avendo previsto questa eventualità il programma considera
+questo un errore fatale terminando a sua volta con un messaggio del tipo:
\begin{verbatim}
[root@gont sources]# ./echod -i
accept error: Interrupted system call
allegati.} come mostrato in fig.~\ref{fig:sig_SignalRestart_code}, ed
installeremo il gestore usando quest'ultima.
-\begin{figure}[!htb]
- \footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/SignalRestart.c}
\end{minipage}
\normalsize
La prima modifica effettuata è stata quella di introdurre una nuova opzione a
riga di comando, \texttt{-c}, che permette di richiedere il comportamento
-compatibile nella gestione di \const{SIGCHLD} al posto della semantica BSD
+compatibile nella gestione di \signal{SIGCHLD} al posto della semantica BSD
impostando la variabile \var{compat} ad un valore non nullo. Questa è
preimpostata al valore nullo, cosicché se non si usa questa opzione il
comportamento di default del server è di usare la semantica BSD.
gestione di tutte queste opzioni, che può essere trovata nel sorgente del
programma.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/TCP_echod_second.c}
\end{minipage}
\normalsize
Vediamo allora come è cambiato il nostro server; una volta definite le
variabili e trattate le opzioni il primo passo (\texttt{\small 9--13}) è
-verificare la semantica scelta per la gestione di \const{SIGCHLD}, a seconda
+verificare la semantica scelta per la gestione di \signal{SIGCHLD}, a seconda
del valore di \var{compat} (\texttt{\small 9}) si installa il gestore con la
funzione \func{Signal} (\texttt{\small 10}) o con \texttt{SignalRestart}
(\texttt{\small 12}), essendo quest'ultimo il valore di default.
Si è potuto lasciare inalterata tutta la sezione di creazione del socket
perché nel server l'unica chiamata ad una system call lenta, che può essere
-interrotta dall'arrivo di \const{SIGCHLD}, è quella ad \func{accept}, che è
+interrotta dall'arrivo di \signal{SIGCHLD}, è quella ad \func{accept}, che è
l'unica funzione che può mettere il processo padre in stato di sleep nel
periodo in cui un figlio può terminare; si noti infatti come le altre
\index{system~call~lente} \textit{slow system call}\footnote{si ricordi la
distinzione fatta in sez.~\ref{sec:sig_gen_beha}.} o sono chiamate prima di
entrare nel ciclo principale, quando ancora non esistono processi figli, o
-sono chiamate dai figli stessi e non risentono di \const{SIGCHLD}.
+sono chiamate dai figli stessi e non risentono di \signal{SIGCHLD}.
Per questo l'unica modifica sostanziale nel ciclo principale (\texttt{\small
23--42}), rispetto precedente versione di fig.~\ref{fig:TCP_ServEcho_first},
un controllo in caso di errore; il codice della nuova versione è mostrato in
fig.~\ref{fig:TCP_ServEcho_second}.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ServEcho_second.c}
\end{minipage}
\normalsize
l'invio di un segmento RST, prima che nel server sia stata chiamata la
funzione \func{accept}.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=10cm]{img/tcp_client_early_abort}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=10cm]{img/tcp_client_early_abort}
\caption{Un possibile caso di terminazione precoce della connessione.}
\label{fig:TCP_early_abort}
\end{figure}
Questo significa che, oltre alla interruzione da parte di un segnale, che
abbiamo trattato in sez.~\ref{sec:TCP_child_hand} nel caso particolare di
-\const{SIGCHLD}, si possono ricevere altri errori non fatali all'uscita di
+\signal{SIGCHLD}, si possono ricevere altri errori non fatali all'uscita di
\func{accept}, che come nel caso precedente, necessitano semplicemente la
ripetizione della chiamata senza che si debba uscire dal programma. In questo
caso anche la versione modificata del nostro server non sarebbe adatta, in
video.
A questo punto noi procediamo ad interrompere l'esecuzione del server con un
-\texttt{C-c} (cioè con l'invio di \const{SIGTERM}): nel momento in cui
+\texttt{C-c} (cioè con l'invio di \signal{SIGTERM}): nel momento in cui
facciamo questo vengono immediatamente generati altri due pacchetti. La
terminazione del processo infatti comporta la chiusura di tutti i suoi file
descriptor, il che comporta, per il socket che avevamo aperto, l'inizio della
funzioni di lettura e scrittura, i socket sono del tutto analoghi a delle
pipe. Allora, da quanto illustrato in sez.~\ref{sec:ipc_pipes}, sappiamo che
tutte le volte che si cerca di scrivere su una pipe il cui altro capo non è
-aperto il lettura il processo riceve un segnale di \const{SIGPIPE}, e questo è
+aperto il lettura il processo riceve un segnale di \signal{SIGPIPE}, e questo è
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.
modo da controllare gli stati di uscita delle varie chiamate. Si è riportata
la nuova versione della funzione in fig.~\ref{fig:TCP_ClientEcho_second}.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ClientEcho_second.c}
\end{minipage}
\normalsize
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
-\procrelfile{/proc/sys/net/ipv4}{tcp\_retries2} (vedi
+\sysctlrelfile{net/ipv4}{tcp\_retries2} (vedi
sez.~\ref{sec:sock_ipv4_sysctl}). 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
bloccherà e restituirà un valore positivo pari al numero di byte accettati
dal livello di trasporto.
\item il lato in scrittura della connessione è stato chiuso. In questo caso
- una operazione di scrittura sul socket genererà il segnale \const{SIGPIPE}.
+ una operazione di scrittura sul socket genererà il segnale \signal{SIGPIPE}.
\item c'è stato un errore sul socket. In questo caso una operazione di
scrittura non si bloccherà ma restituirà una condizione di errore ed
imposterà opportunamente la variabile \var{errno}. Vedremo in
lettura (nell'ultimo caso anche in scrittura, ma questo non è necessario ai
nostri scopi).
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ClientEcho_third.c}
\end{minipage}
\normalsize
la modalità di chiusura del socket, quest'ultima può prendere soltanto tre
valori:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\macro{SHUT\_RD}] chiude il lato in lettura del socket, non sarà più
+\item[\const{SHUT\_RD}] chiude il lato in lettura del socket, non sarà più
possibile leggere dati da esso, tutti gli eventuali dati trasmessi
dall'altro capo del socket saranno automaticamente scartati dal kernel, che,
in caso di socket TCP, provvederà comunque ad inviare i relativi segmenti di
ACK.
-\item[\macro{SHUT\_WR}] chiude il lato in scrittura del socket, non sarà più
+\item[\const{SHUT\_WR}] chiude il lato in scrittura del socket, non sarà più
possibile scrivere dati su di esso. Nel caso di socket TCP la chiamata causa
l'emissione di un segmento FIN, secondo la procedura chiamata
\itindex{half-close} \textit{half-close}. Tutti i dati presenti nel buffer
di scrittura prima della chiamata saranno inviati, seguiti dalla sequenza di
chiusura illustrata in sez.~\ref{sec:TCP_conn_term}.
-\item[\macro{SHUT\_RDWR}] chiude sia il lato in lettura che quello in
+\item[\const{SHUT\_RDWR}] chiude sia il lato in lettura che quello in
scrittura del socket. È equivalente alla chiamata in sequenza con
- \macro{SHUT\_RD} e \macro{SHUT\_WR}.
+ \const{SHUT\_RD} e \const{SHUT\_WR}.
\end{basedescript}
-Ci si può chiedere quale sia l'utilità di avere introdotto \macro{SHUT\_RDWR}
+Ci si può chiedere quale sia l'utilità di avere introdotto \const{SHUT\_RDWR}
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
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
+\const{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
socket da parte del server il client potrà essere sicuro della ricezione di
tutti i dati e della terminazione effettiva della connessione.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/ClientEcho.c}
\end{minipage}
\normalsize
utilizzerà \func{select} per rilevare la presenza di dati in arrivo su tutti i
file descriptor attivi, operando direttamente su ciascuno di essi.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=13cm]{img/TCPechoMult}
+\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}
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/select_echod.c}
\end{minipage}
\normalsize
\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15.6cm}
+ \begin{minipage}[c]{\codesamplewidth}
\includecodesample{listati/poll_echod.c}
\end{minipage}
\normalsize
% LocalWords: lsof SOCK sys int sockfd const struct sockaddr serv addr socklen
% LocalWords: addrlen errno EBADF descriptor EINVAL ENOTSOCK EACCES EADDRINUSE
% LocalWords: EADDRNOTAVAIL EFAULT ENOTDIR ENOENT ENOMEM ELOOP ENOSR EROFS RPC
-% LocalWords: portmapper htonl tab endianess BROADCAST broadcast any extern fd
+% LocalWords: portmapper htonl tab endianness BROADCAST broadcast any extern fd
% LocalWords: ADRR INIT DGRAM SEQPACKET servaddr ECONNREFUSED ETIMEDOUT EAGAIN
% LocalWords: ENETUNREACH EINPROGRESS EALREADY EAFNOSUPPORT EPERM EISCONN proc
% LocalWords: sysctl filesystem syn retries reset ICMP backlog EOPNOTSUPP RECV