From c48d3a056c974898ca18c27a918f2296c18e2c6e Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 24 Aug 2003 22:50:27 +0000 Subject: [PATCH 1/1] Iniziato a rivedere il multiplexing I/O. --- fileadv.tex | 103 +++++++++++++++++++++++++++++-------------------- gapil.tex | 2 +- system.tex | 6 +-- tcpsock.tex | 2 +- tcpsockadv.tex | 72 ++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 46 deletions(-) create mode 100644 tcpsockadv.tex diff --git a/fileadv.tex b/fileadv.tex index 9c09c7e..4415602 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -70,15 +70,15 @@ I/O non bloccante. \label{sec:file_multiplexing} Per superare il problema di dover usare il \textit{polling}\index{polling} per -controllare la possibilità di effettuare operazioni su un file aperto in -modalità non bloccante, sia BSD che System V hanno introdotto delle nuove -funzioni in grado di sospendere l'esecuzione di un processo in attesa che -l'accesso diventi possibile. Il primo ad introdurre questa modalità di -operazione, chiamata usualmente \textit{I/O multiplexing}, è stato -BSD,\footnote{la funzione è apparsa in BSD4.2 e standardizzata in BSD4.4, ma è - stata portata su tutti i sistemi che supportano i - \textit{socket}\index{socket}, compreso le varianti di System V.} con la -funzione \funcd{select}, il cui prototipo è: +controllare la possibilità di effettuare operazioni su un gruppo di file +aperti in modalità non bloccante, sia BSD che System V hanno introdotto delle +nuove funzioni in grado di sospendere l'esecuzione di un processo fin quando +l'accesso ad un dato insieme di file diventi possibile. Il primo ad +introdurre questa modalità di operazione, chiamata usualmente \textit{I/O + multiplexing}, è stato BSD,\footnote{la funzione è apparsa in BSD4.2 e + standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che + supportano i \textit{socket}\index{socket}, compreso le varianti di System + V.} con la funzione \funcd{select}, il cui prototipo è: \begin{functions} \headdecl{sys/time.h} \headdecl{sys/types.h} @@ -135,10 +135,14 @@ opportune macro di preprocessore: In genere un \textit{file descriptor set} può contenere fino ad un massimo di \const{FD\_SETSIZE} file descriptor. Questo valore in origine corrispondeva al limite per il numero massimo di file aperti\footnote{ad esempio in Linux, - fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma + fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da quando, come nelle versioni più recenti del kernel, non c'è più un limite massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file - descriptor set}. + descriptor set}.\footnote{il suo valore, secondo lo standard POSIX + 1003.1-2001, è definito in \file{sys/select.h}, ed è pari a 1024.} Si tenga +presente che i \textit{file descriptor set} devono sempre essere inizializzati +con \macro{FD\_ZERO}; passare a \func{select} un valore non inizializzato può +dar luogo a comportamenti non prevedibili. La funzione richiede di specificare tre insiemi distinti di file descriptor; il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di @@ -147,17 +151,24 @@ possibilit verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su un \textit{socket}\index{socket}, vedi \secref{sec:xxx_urgent}). -La funzione inoltre richiede anche di specificare, tramite l'argomento -\param{n}, un valore massimo del numero dei file descriptor usati -nell'insieme; si può usare il già citato \const{FD\_SETSIZE}, oppure il numero -più alto dei file descriptor usati nei tre insiemi, aumentato di uno. +Dato che in genere non si tengono mai sotto controllo fino a +\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di +specificare qual'è il numero massimo dei file descriptor indicati nei tre +insiemi precedenti. Questo viene fatto per efficienza, per evitare di passare +e far controllare al kernel una quantità di memoria superiore a quella +necessaria. Questo limite viene indicato tramite l'argomento \param{n}, che +deve corrispondere al valore massimo aumentato di uno.\footnote{i file + descriptor infatti sono contati a partire da zero, ed il valore indica il + numero di quelli da tenere sotto controllo; dimenticarsi di aumentare di uno + il valore di \param{n} è un errore comune.} Infine l'argomento \param{timeout}, specifica un tempo massimo di -attesa\footnote{il tempo è valutato come \textit{elapsed time}.} prima che la -funzione ritorni; se impostato a \val{NULL} la funzione attende -indefinitamente. Si può specificare anche un tempo nullo (cioè una struttura -\struct{timeval} con i campi impostati a zero), qualora si voglia -semplicemente controllare lo stato corrente dei file descriptor. +attesa\footnote{il tempo è valutato come \textit{clock time} (vedi + \secref{sec:sys_unix_time}).} prima che la funzione ritorni; se impostato a +\val{NULL} la funzione attende indefinitamente. Si può specificare anche un +tempo nullo (cioè una struttura \struct{timeval} con i campi impostati a +zero), qualora si voglia semplicemente controllare lo stato corrente dei file +descriptor. La funzione restituisce il totale dei file descriptor pronti nei tre insiemi, il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre @@ -167,35 +178,35 @@ operazioni ad esso relative, in modo da poterlo controllare con la macro non vengono toccati. In Linux \func{select} modifica anche il valore di \param{timeout}, -impostandolo al tempo restante; questo è utile quando la funzione viene -interrotta da un segnale, in tal caso infatti si ha un errore di -\errcode{EINTR}, ed occorre rilanciare la funzione; in questo modo non è -necessario ricalcolare tutte le volte il tempo rimanente.\footnote{questo può - causare problemi di portabilità sia quando si trasporta codice scritto su - Linux che legge questo valore, sia quando si usano programmi scritti per - altri sistemi che non dispongono di questa caratteristica e ricalcolano - \param{timeout} tutte le volte. In genere la caratteristica è disponibile - nei sistemi che derivano da System V e non disponibile per quelli che - derivano da BSD.} - -Come accennato l'interfaccia di \func{select} è una estensione di BSD; anche -System V ha introdotto una sua interfaccia per gestire l'\textit{I/O - multiplexing}, basata sulla funzione \funcd{poll},\footnote{la funzione è - prevista dallo standard XPG4, ed è stata introdotta in Linux come system - call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui +impostandolo al tempo restante in caso di interruzione prematura; questo è +utile quando la funzione viene interrotta da un segnale, in tal caso infatti +si ha un errore di \errcode{EINTR}, ed occorre rilanciare la funzione; in +questo modo non è necessario ricalcolare tutte le volte il tempo +rimanente.\footnote{questo può causare problemi di portabilità sia quando si + trasporta codice scritto su Linux che legge questo valore, sia quando si + usano programmi scritti per altri sistemi che non dispongono di questa + caratteristica e ricalcolano \param{timeout} tutte le volte. In genere la + caratteristica è disponibile nei sistemi che derivano da System V e non + disponibile per quelli che derivano da BSD.} + +Come accennato l'interfaccia di \func{select} è una estensione creata nello +sviluppo di BSD; anche System V ha introdotto una sua interfaccia per gestire +l'\textit{I/O multiplexing}, basata sulla funzione \funcd{poll},\footnote{la + funzione è prevista dallo standard XPG4, ed è stata introdotta in Linux come + system call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui prototipo è: \begin{prototype}{sys/poll.h} {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)} - -La funzione attente un cambiamento di stato per uno dei file descriptor -specificati da \param{ufds}. + + La funzione attende un cambiamento di stato per uno dei file descriptor + specificati da \param{ufds}. \bodydesc{La funzione restituisce il numero di file descriptor con attività in caso di successo, o 0 se c'è stato un timeout; in caso di errore viene restituito -1 ed \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno - degli insiemi. + degli insiemi. \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. \end{errlist} ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} @@ -248,7 +259,8 @@ vengono utilizzati solo per \var{revents} come valori in uscita). \const{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali. \\ \const{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad alta priorità. \\ - \const{POLLMSG} & 0x400 & Estensione propria di Linux.\\ + \const{POLLMSG} & 0x400 & Un segnale \const{SIGPOLL} è arrivato alla + cima dello stream.\\ \hline \end{tabular} \caption{Costanti per l'identificazione dei vari bit dei campi @@ -315,6 +327,15 @@ segnale che non sarebbe rilevato; la race condition\index{race condition} diventa superabile disabilitando il segnale prima del test e riabilitandolo poi grazie all'uso di \param{sigmask}. +Dato che l'I/O multiplexing serve a risolvere il problema di dover attendere +la disponibilità di accesso ad un insieme di file, esso viene utilizzato +prevalentemente per programmi in cui l'accesso ad un file descriptor può +essere bloccante. Abbiamo già accennato come questo non avvenga mai per i +normali file su disco; l'uso più comune di queste funzioni infatti è nei +server di rete, in cui esse vengono utilizzate per tenere sotto controllo vari +socket; pertanto ritorneremo su di esse con maggiori dettagli e con qualche +esempio in \secref{sec:TCP_sock_multiplexing}. + \subsection{L'I/O asincrono} diff --git a/gapil.tex b/gapil.tex index 1d18318..62f70cb 100644 --- a/gapil.tex +++ b/gapil.tex @@ -141,7 +141,7 @@ \include{network} \include{socket} \include{tcpsock} -%\include{simpltcp} +\include{tcpsockadv} \appendix \include{netlayer} \include{trasplayer} diff --git a/system.tex b/system.tex index 2427fee..60ca1e9 100644 --- a/system.tex +++ b/system.tex @@ -1643,9 +1643,9 @@ dei tempi di esecuzione dei processi. Per ciascun processo il kernel calcola tre tempi diversi: \begin{description} \item[\textit{clock time}]: il tempo \textsl{reale} (viene chiamato anche - \textit{wall clock time}) passato dall'avvio del processo. Chiaramente tale - tempo dipende anche dal carico del sistema e da quanti altri processi - stavano girando nello stesso periodo. + \textit{wall clock time} o \textit{elapsed time}) passato dall'avvio del + processo. Chiaramente tale tempo dipende anche dal carico del sistema e da + quanti altri processi stavano girando nello stesso periodo. \item[\textit{user time}]: il tempo che la CPU ha impiegato nell'esecuzione delle istruzioni del processo in user space. \item[\textit{system time}]: il tempo che la CPU ha impiegato nel kernel per diff --git a/tcpsock.tex b/tcpsock.tex index 6d23c10..eba896e 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -2384,7 +2384,7 @@ definitiva della connessione anche nel client, dove non comparir nell'output di \cmd{netstat}. Come abbiamo accennato in \secref{sec:TCP_conn_term} e come vedremo più avanti -in \secref{sec:TCP_xxx_shutdown}} la chiusura di un solo capo di un socket è +in \secref{sec:TCP_xxx_shutdown} la chiusura di un solo capo di un socket è una operazione lecita, per cui la nostra scrittura avrà comunque successo (come si può constatare lanciando usando \cmd{strace}\footnote{il comando \cmd{strace} è un comando di debug molto utile che prende come parametro un diff --git a/tcpsockadv.tex b/tcpsockadv.tex new file mode 100644 index 0000000..3ac5348 --- /dev/null +++ b/tcpsockadv.tex @@ -0,0 +1,72 @@ +%% tcpsockadv.tex +%% +%% Copyright (C) 2003 Simone Piccardi. Permission is granted to +%% copy, distribute and/or modify this document under the terms of the GNU Free +%% Documentation License, Version 1.1 or any later version published by the +%% Free Software Foundation; with the Invariant Sections being "Prefazione", +%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the +%% license is included in the section entitled "GNU Free Documentation +%% License". +%% +\chapter{Socket TCP avanzati} +\label{cha:TCP_advanced} + +Esamineremo in questo capitolo le funzionalità più evolute della gestione dei +socket TCP. + + + +\section{Socket multiplexing} +\label{sec:TCP_sock_mutiplexing} + +Affronteremo in questa sezione l'utilizzo dei socket + + + +\section{Le opzioni dei socket} +\label{sec:TCP_sock_options} + +Dato che la maggior parte delle opzioni dei socket sono relative ai socket +TCP, ed hanno poi significato analogo quando usate con altri socket, +tratteremo qui l'argomento in generale. + + + +\section{I dati \textit{out-of-band}} +\label{sec:TCP_outofband} + +Una caratteristica speciale dei socket TCP è quella della presenza dei +cosiddetti dati \textit{out-of-band} + + + +\subsection{La funzione \func{shutdown}} +\label{sec:TCP_shutdown} + +Come spiegato in \secref{sec:TCP_conn_term} il procedimento di chiusura di un +socket TCP prevede che da entrambe le parti venga emesso un segmento FIN. È +pertanto del tutto normale dal punto di vista del protocollo che uno dei due +capi chiuda la connessione, quando l'altro capo la lascia +aperta.\footnote{abbiamo incontrato questa situazione nei vari scenari critici + di \secref{sec:TCP_echo_critical}.} + +È pertanto possibile avere una situazione in cui un capo della connessione non +avendo più nulla da scrivere, possa chiudere il socket, segnalando così +l'avvenuta terminazione della trasmissione (l'altro capo riceverà infatti un +end-of-file in lettura) mentre dall'altra parte si potrà proseguire la +trasmissione dei dati scrivendo sul socket che da quel lato è ancora aperto. +Questa è quella situazione in cui si dice che il socket è \textit{half + closed}. + +Il problema che si pone è che se la chiusura del socket è effettuata con la +funzione \func{close}, come spiegato in \secref{sec:TCP_func_close}, si perde +ogni possibilità di poter rileggere quanto l'altro capo può continuare a +scrivere. Per poter permettere allora + + + + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: -- 2.30.2