From: Simone Piccardi Date: Sun, 14 Sep 2003 22:52:53 +0000 (+0000) Subject: Ampliata select e rivisto il paragrafo su I/I multiplexing, iniziato il X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=6b41b67f440246432014cb846a8a3d6b718f3074;p=gapil.git Ampliata select e rivisto il paragrafo su I/I multiplexing, iniziato il relativo paragrafo per i socket TCP --- diff --git a/fileadv.tex b/fileadv.tex index 4415602..ce32874 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -162,20 +162,21 @@ deve corrispondere al valore massimo aumentato di uno.\footnote{i file 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{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 -insiemi viene sovrascritto per indicare quale file descriptor è pronto per le -operazioni ad esso relative, in modo da poterlo controllare con la macro -\const{FD\_ISSET}. In caso di errore la funzione restituisce -1 e gli insiemi -non vengono toccati. +Infine l'argomento \param{timeout}, specifica un tempo massimo di attesa 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 numero di file descriptor pronti,\footnote{questo è + il comportamento previsto dallo standard, ma la standardizzazione della + funzione è recente, ed esistono ancora alcune versioni di Unix che non si + comportano in questo modo.} e ciascun insieme viene sovrascritto per +indicare i file descriptor pronti per le operazioni ad esso relative, in modo +da poterli controllare con \const{FD\_ISSET}. Se invece si ha un timeout +viene restituito un valore nullo e gli insiemi non vengono modificati. In +caso di errore la funzione restituisce -1, ed i valori dei tre insiemi sono +indefiniti e non si può fare nessun affidamento sul loro contenuto. In Linux \func{select} modifica anche il valore di \param{timeout}, impostandolo al tempo restante in caso di interruzione prematura; questo è @@ -189,12 +190,27 @@ rimanente.\footnote{questo pu 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 è: +Uno dei problemi che si presentano con l'uso di \func{select} è che il suo +comportamento dipende dal valore del file descriptor che si vuole tenere sotto +controllo. Infatti il kernel riceve solo un valore massimo, e dovrà +effettuare una scansione su tutto l'intervallo, che può essere anche molto +ampio, per capire quali sono i file descriptor da tenere sotto controllo, +anche se sono solo poche unità; e questo ha ovviamente un pessimo risultato +per le prestazioni; il comportamenento viene della funzione viene così a +dipendere in maniera innaturale dal valore del file decriptor. + +Inoltre c'è anche il problema che il numero massimo dei file che si possono +tenere sotto controllo, la funzione è nata quando il kernel consentiva un +numero massimo di 1024 file descriptor per processo, adesso che il numero può +essere arbitario si viene a creare una dipendenza del tutto artificiale dalle +dimensioni della struttura \type{fd\_set}, che può necessitare di essere +estesa, con ulteriori perdite di prestazioni. +Per questo System V, invece di utilizzare l'interfaccia di \func{select}, che +è una estensione creata nello sviluppo di BSD, 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)} @@ -277,10 +293,10 @@ condizioni specificate tramite \var{events} pu una condizione di errore. Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O - multiplexing}, che è stata introdotto con le ultime revisioni dello standard -(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni -ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che -sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione + multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX +1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni ad esso +relative vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i +precedenti, ed aggiunge a \func{select} una nuova funzione \funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc} 2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le @@ -415,15 +431,11 @@ rispetto a quelle usate normalmente. In generale questa interfaccia è completamente astratta e può essere implementata sia direttamente nel kernel, che in user space attraverso l'uso -di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie - 2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema - di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O - asincrono (effettuato a partire dal 2.5.32).} esiste una sola versione -stabile di questa interfaccia, quella delle \acr{glibc}, che è realizzata -completamente in user space, ed accessibile linkando i programmi con la -libreria \file{librt}. Esistono comunque vari progetti sperimentali (come il -KAIO della SGI, o i patch di Benjamin La Haise) che prevedono un supporto -diretto da parte del kernel. +di thread. Al momento esiste una sola versione stabile di questa interfaccia, +quella delle \acr{glibc}, che è realizzata completamente in user space, ed +accessibile linkando i programmi con la libreria \file{librt}. Nei kernel +della nuova serie è stato anche introdotta (a partire dal 2.5.32) un nuovo +layer per l'I/O asincrono. Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per @@ -445,18 +457,17 @@ disponibilit \end{figure} Le operazioni di I/O asincrono possono essere effettuate solo su un file già -aperto; il file deve inoltre supportare la funzione \func{lseek}, -pertanto terminali e pipe sono esclusi. Non c'è limite al numero di operazioni -contemporanee effettuabili su un singolo file. - -Ogni operazione deve inizializzare opportunamente un \textit{control block}. -Il file descriptor su cui operare deve essere specificato tramite il campo -\var{aio\_fildes}; dato che più operazioni possono essere eseguita in maniera -asincrona, il concetto di posizione corrente sul file viene a mancare; -pertanto si deve sempre specificare nel campo \var{aio\_offset} la posizione -sul file da cui i dati saranno letti o scritti. Nel campo \var{aio\_buf} deve -essere specificato l'indirizzo del buffer usato per l'I/O, ed in -\var{aio\_nbytes} la lunghezza del blocco di dati da trasferire. +aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto +terminali e pipe sono esclusi. Non c'è limite al numero di operazioni +contemporanee effettuabili su un singolo file. Ogni operazione deve +inizializzare opportunamente un \textit{control block}. Il file descriptor su +cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato +che più operazioni possono essere eseguita in maniera asincrona, il concetto +di posizione corrente sul file viene a mancare; pertanto si deve sempre +specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati +saranno letti o scritti. Nel campo \var{aio\_buf} deve essere specificato +l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza +del blocco di dati da trasferire. Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni di I/O.\footnote{in generale perché ciò sia possibile occorre che la @@ -464,13 +475,11 @@ di I/O.\footnote{in generale perch le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a partire da quella del processo chiamante (vedi \secref{sec:proc_priority}), -cui viene sottratto il valore di questo campo. - -Il campo \var{aio\_lio\_opcode} è usato soltanto dalla funzione -\func{lio\_listio}, che, come vedremo più avanti, permette di eseguire con una -sola chiamata una serie di operazioni, usando un vettore di \textit{control - block}. Tramite questo campo si specifica quale è la natura di ciascuna di -esse. +cui viene sottratto il valore di questo campo. Il campo +\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che, +come vedremo, permette di eseguire con una sola chiamata una serie di +operazioni, usando un vettore di \textit{control block}. Tramite questo campo +si specifica quale è la natura di ciascuna di esse. \begin{figure}[!htb] \footnotesize \centering @@ -541,11 +550,11 @@ Si tenga inoltre presente che deallocare la memoria indirizzata da \param{aiocbp} o modificarne i valori prima della conclusione di una operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la -richiesta. Questo comporta che occorre evitare di usare per \param{aiocbp} +richiesta. Questo comporta che non si devono usare per \param{aiocbp} variabili automatiche e che non si deve riutilizzare la stessa struttura per -un ulteriore operazione fintanto che la precedente non sia stata ultimata. In -generale per ogni operazione di I/O asincrono si deve utilizzare una diversa -struttura \struct{aiocb}. +un'altra operazione fintanto che la precedente non sia stata ultimata. In +generale per ogni operazione si deve utilizzare una diversa struttura +\struct{aiocb}. Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o \func{aio\_write} non implica che le operazioni siano state effettivamente @@ -575,8 +584,8 @@ del caso, i codici di errore delle system call \func{read}, \func{write} e \func{fsync}. Una volta che si sia certi che le operazioni siano state concluse (cioè dopo -che una chiamata ad \func{aio\_error} non ha restituito \errcode{EINPROGRESS}, -si potrà usare la seconda funzione dell'interfaccia, \funcd{aio\_return}, che +che una chiamata ad \func{aio\_error} non ha restituito +\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che permette di verificare il completamento delle operazioni di I/O asincrono; il suo prototipo è: \begin{prototype}{aio.h} @@ -603,7 +612,7 @@ asincrono non verrebbero liberate, rischiando di arrivare ad un loro esaurimento. Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a -disposizione un'altra operazione, quella di sincronizzazione dell'I/O, essa è +disposizione un'altra operazione, quella di sincronizzazione dell'I/O, compiuta dalla funzione \func{aio\_fsync}, che ha lo stesso effetto della analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo è: @@ -724,6 +733,9 @@ lettura o scrittura; il suo prototipo \begin{errlist} \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro \param{timeout}. + \item[\errcode{EINVAL}] Si è passato un valore di \param{mode} non valido + o un numero di operazioni \param{nent} maggiore di + \const{AIO\_LISTIO\_MAX}. \item[\errcode{ENOSYS}] La funzione non è implementata. \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. \end{errlist} @@ -847,7 +859,7 @@ memoria, quanto di memoria mappata su file. \begin{figure}[htb] \centering - \includegraphics[width=9.5cm]{img/mmap_layout} + \includegraphics[width=7.cm]{img/mmap_layout} \caption{Disposizione della memoria di un processo quando si esegue la mappatura in memoria di un file.} \label{fig:file_mmap_layout} @@ -866,13 +878,12 @@ virtuale, la sezione di memoria mappata su cui si opera sar o scritta sul file una pagina alla volta e solo per le parti effettivamente usate, il tutto in maniera completamente trasparente al processo; l'accesso alle pagine non ancora caricate avverrà allo stesso modo con cui vengono -caricate in memoria le pagine che sono state salvate sullo swap. - -Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un -file vengono salvate automaticamente, così come le pagine dei programmi -vengono scritte sulla swap; questo consente di accedere ai file su dimensioni -il cui solo limite è quello dello spazio di indirizzi disponibile, e non della -memoria su cui possono esserne lette delle porzioni. +caricate in memoria le pagine che sono state salvate sullo swap. Infine in +situazioni in cui la memoria è scarsa, le pagine che mappano un file vengono +salvate automaticamente, così come le pagine dei programmi vengono scritte +sulla swap; questo consente di accedere ai file su dimensioni il cui solo +limite è quello dello spazio di indirizzi disponibile, e non della memoria su +cui possono esserne lette delle porzioni. L'interfaccia prevede varie funzioni per la gestione del \textit{memory mapped I/O}, la prima di queste è \funcd{mmap}, che serve ad eseguire la mappatura @@ -893,12 +904,11 @@ in memoria di un file; il suo prototipo \begin{errlist} \item[\errcode{EBADF}] Il file descriptor non è valido, e non si è usato \const{MAP\_ANONYMOUS}. - \item[\errcode{EACCES}] Il file descriptor non si riferisce ad un file - regolare, o si è richiesto \const{MAP\_PRIVATE} ma \param{fd} non è - aperto in lettura, o si è richiesto \const{MAP\_SHARED} e impostato - \const{PROT\_WRITE} ed \param{fd} non è aperto in lettura/scrittura, o - si è impostato \const{PROT\_WRITE} ed \param{fd} è in - \textit{append-only}. + \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare, + o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura, + o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed + \param{fd} non è aperto in lettura/scrittura, o si è impostato + \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}. \item[\errcode{EINVAL}] I valori di \param{start}, \param{length} o \param{offset} non sono validi (o troppo grandi o non allineati sulla dimensione delle pagine). @@ -1068,7 +1078,7 @@ quella della mappatura in memoria. \begin{figure}[htb] \centering - \includegraphics[width=13cm]{img/mmap_exceed} + \includegraphics[width=10cm]{img/mmap_exceed} \caption{Schema della mappatura in memoria di file di dimensioni inferiori alla lunghezza richiesta.} \label{fig:file_mmap_exceed} @@ -1257,10 +1267,11 @@ sistemi unix-like mantenere il nome \textit{advisory locking}.} in quanto sono i singoli processi, e non il sistema, che si incaricano di asserire e verificare se esistono delle condizioni di blocco per l'accesso ai file. Questo significa -che le funzioni \func{read} o \func{write} non risentono affatto della -presenza di un eventuale \textit{lock}, e che sta ai vari processi controllare -esplicitamente lo stato dei file condivisi prima di accedervi, implementando -un opportuno protocollo. +che le funzioni \func{read} o \func{write} vengono eseguite comunque e non +risentono affatto della presenza di un eventuale \textit{lock}; pertanto è +sempre compito dei vari processi che intendono usare il file locking, +controllare esplicitamente lo stato dei file condivisi prima di accedervi, +utilizzando le relative funzioni. In generale si distinguono due tipologie di \textit{file lock}:\footnote{di seguito ci riferiremo sempre ai blocchi di accesso ai file con la @@ -1269,17 +1280,17 @@ In generale si distinguono due tipologie di \textit{file lock}:\footnote{di processo (cioè la condizione in cui il processo viene posto in stato di \textit{sleep}).} la prima è il cosiddetto \textit{shared lock}, detto anche \textit{read lock} in quanto serve a bloccare l'accesso in scrittura su un -file affinché non venga modificato mentre lo si legge. Si parla appunto di -\textsl{blocco condiviso} in quanto più processi possono richiedere -contemporaneamente uno \textit{shared lock} su un file per proteggere il loro -accesso in lettura. +file affinché il suo contenuto non venga modificato mentre lo si legge. Si +parla appunto di \textsl{blocco condiviso} in quanto più processi possono +richiedere contemporaneamente uno \textit{shared lock} su un file per +proteggere il loro accesso in lettura. La seconda tipologia è il cosiddetto \textit{exclusive lock}, detto anche \textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in lettura che in scrittura) da parte di altri processi mentre lo si sta scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo processo alla volta può richiedere un \textit{exclusive lock} su un file per -proteggere il suo accesso in scrittura. +proteggere il suo accesso in scrittura. \begin{table}[htb] \centering @@ -1313,12 +1324,17 @@ lettura) prima di eseguire l'accesso ad un file. Se il lock viene acquisito il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un comportamento non bloccante) viene posto in stato di sleep. Una volta finite le operazioni sul file si deve provvedere a rimuovere il lock. La situazione -delle varie possibilità è riassunta in \tabref{tab:file_file_lock}. - -Si tenga presente infine che il controllo di accesso è effettuato quando si -apre un file, l'unico controllo residuo è che il tipo di lock che si vuole -ottenere deve essere compatibile con le modalità di apertura dello stesso (di -lettura per un read lock e di scrittura per un write lock). +delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si +sono riportati, per le varie tipologie di lock presenti su un file, il +risultato che si ha in corrispondenza alle due tipologie di \textit{file lock} +menzionate, nel successo della richiesta. + +Si tenga presente infine che il controllo di accesso e la gestione dei +permessi viene effettuata quando si apre un file, l'unico controllo residuo +che si può avere riguardo il \textit{file locking} è che il tipo di lock che +si vuole ottenere su un file deve essere compatibile con le modalità di +apertura dello stesso (in lettura per un read lock e in scrittura per un write +lock). %% Si ricordi che %% la condizione per acquisire uno \textit{shared lock} è che il file non abbia @@ -1326,7 +1342,7 @@ lettura per un read lock e di scrittura per un write lock). %% \textit{exclusive lock} non deve essere presente nessun tipo di blocco. -\subsection{La funzione \func{flock}} +\subsection{La funzione \func{flock}} \label{sec:file_flock} La prima interfaccia per il file locking, quella derivata da BSD, permette di @@ -1401,7 +1417,7 @@ diversi che aprono lo stesso file. \begin{figure}[htb] \centering - \includegraphics[width=12.5cm]{img/file_flock} + \includegraphics[width=14cm]{img/file_flock} \caption{Schema dell'architettura del file locking, nel caso particolare del suo utilizzo da parte dalla funzione \func{flock}.} \label{fig:file_flock_struct} @@ -1528,14 +1544,6 @@ file; in questo modo un certo punto fino alla fine del file, coprendo automaticamente quanto eventualmente aggiunto in coda allo stesso. -Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso -può assumere i tre valori definiti dalle costanti riportate in -\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno -\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock -precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in -caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta -il \acr{pid} del processo che detiene il lock. - \begin{table}[htb] \centering \footnotesize @@ -1553,6 +1561,14 @@ il \acr{pid} del processo che detiene il lock. \label{tab:file_flock_type} \end{table} +Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso +può assumere i tre valori definiti dalle costanti riportate in +\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno +\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock +precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in +caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta +il \acr{pid} del processo che detiene il lock. + Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione effettivamente svolta dalla funzione è stabilita dal valore dall'argomento \param{cmd} che, come già riportato in \secref{sec:file_fcntl}, specifica diff --git a/img/mmap_layout.dia b/img/mmap_layout.dia index 8c964dc..9394095 100644 Binary files a/img/mmap_layout.dia and b/img/mmap_layout.dia differ diff --git a/tcpsock.tex b/tcpsock.tex index eba896e..63b9743 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -2461,7 +2461,7 @@ avanti, ed fare con la necessità di lavorare con più descrittori, nel qual caso diventa si pone la questione di come fare a non restare bloccati su un socket quando altri potrebbero essere liberi. Vedremo come affrontare questa problematica in -\secref{sec:TCP_xxx_advanced}. +\secref{sec:TCP_sock_multiplexing}. \subsection{Altri scenari di terminazione della connessione} diff --git a/tcpsockadv.tex b/tcpsockadv.tex index 3ac5348..81c37eb 100644 --- a/tcpsockadv.tex +++ b/tcpsockadv.tex @@ -1,4 +1,4 @@ -%% tcpsockadv.tex + %% 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 @@ -17,9 +17,44 @@ socket TCP. \section{Socket multiplexing} -\label{sec:TCP_sock_mutiplexing} +\label{sec:TCP_sock_multiplexing} + +Affronteremo in questa sezione l'utilizzo dell'I/O multiplexing, affrontato in +\secref{sec:file_multiplexing}, nell'ambito delle applicazioni di rete. Già in +\ref{sec:TCP_server_crash} era emerso il problema relativo al client del +servizio echo che non era in grado di accorgersi della terminazione precoce +del server essendo bloccato nella lettura dei dati immessi da tastiera. + +Abbiamo visto in \secref{sec:file_multiplexing} quali sono le funzionalità del +sistema che ci permettono di tenere sotto controllo più file descriptor in +contemporanea; in quella occasione non abbiamo fatto esempi, in quanto quando +si tratta con file normali questa tipologia di I/O non viene usata, è invece +un caso tipico delle applicazioni di rete quello di dover gestire varie +connessioni da cui possono arrivare dati comuni in maniera asincrona, per cui +riprenderemo l'argomento in questa sezione. + + + +\subsection{La funzione \func{select} con i socket.} +\label{sec:TCP_sock_select} + + + + +Iniziamo con la prima delle funzioni usate per l'I/O multiplexing, +\func{select}, il suo funzionamento è già stato descritto in dettaglio in +\secref{sec:file_multiplexing}; e sappiamo che la funzione ritorna quando uno +o più dei file descriptor messi sotto controllo è pronto per la relativa +operazione. + +In quell'occasione non abbiamo però definito cosa si intende per pronto, +infatti se per dei normali file, o anche per delle pipe, la condizione di +essere pronti per la lettura o la scrittura è ovvia, lo è un po' meno di meno +nel caso dei socket, visto che intervengono tutte le possibili condizioni +dovute alla rete. Occorre allora specificare quali sono le condizioni in cui +un socket risulta \textsl{pronto}. + -Affronteremo in questa sezione l'utilizzo dei socket