From: Simone Piccardi Date: Thu, 17 May 2001 22:56:40 +0000 (+0000) Subject: Riscritta la parte di accept. Inserite le parti relative al comportamento X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=1fd3d7933b5accf8d360b164ecb1bb688cca63d4;p=gapil.git Riscritta la parte di accept. Inserite le parti relative al comportamento specifico su linux prese dalle manpages --- diff --git a/elemtcp.tex b/elemtcp.tex index 9eab58a..fcb3b32 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -1,27 +1,28 @@ \chapter{Socket TCP elementari} \label{cha:elem_TCP_sock} -In questo capitolo inizieremo ad approndire la conoscenza dei socket TCP, +In questo capitolo iniziamo ad approndire la conoscenza dei socket TCP, tratteremo qui dunque il funzionamento delle varie funzioni che si sono usate nei due esempi elementari forniti in precedenza (vedi \secref{sec:net_cli_sample} e \secref{sec:net_serv_sample}), previa una descrizione delle principali caratteristiche del funzionamento di una connessione TCP. -La seconda parte del capitolo sarà poi dedicata alla scrittura di una prima -semplice applicazione client/server completa, che implementi il servizio -standard \texttt{echo} su TCP. +Infine riscriveremo il precedente esempio elementare di server +\texttt{daytime} in una forma appena più evoluta (come server concorrente) e +con alcune caratteristiche aggiuntive che mettano in luce quanto andremo ad +illustrare. \section{Il funzionamento di una connessione TCP} \label{sec:TCPel_connession} Prima di entrare nei dettagli delle funzioni usate nelle applicazioni che utilizzano i socket TCP, è fondamentale spiegare alcune basi del funzionamento -del TCP, la conoscenza del funzionamento del protocollo è infatti essenziale +del TCP; la conoscenza del funzionamento del protocollo è infatti essenziale per capire il modello di programmazione ed il funzionamento delle API. -In particolare ci concentreremo sulle modalità con le quali il protocollo da -inizio e conclude una connessione; faremo anche un breve accenno al +In particolare ci concentreremo sulle modalità con le quali il protocollo dà +inizio e conclude una connessione; faremo inoltre anche un breve accenno al significato di alcuni dei vari stati che il protocollo assume durante la vita di una connessione, che possono essere osservati per ciascun socket attivo con l'uso del programma \texttt{netstat}. @@ -716,7 +717,7 @@ La funzione \texttt{connect} connessione con un server TCP, il prototipo della funzione è il seguente: \begin{prototype}{sys/socket.h} -{int connect(int sockfd, const struct sockaddr *serv\_addr, socklen\_t addrlen)} +{int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t addrlen)} Il primo argomento è un file descriptor ottenuto da una precedente chiamata a \texttt{socket}, mentre il secondo e terzo argomento sono rispettivamente @@ -919,7 +920,6 @@ lasciare la gestione della connessione alla ritrasmissione prevista dal protocollo TCP. - \subsection{La funzione \texttt{accept}} \label{sec:TCPel_func_accept} @@ -929,15 +929,14 @@ funzione restituisce un nuovo socket descriptor su cui si potr effettuare la comunicazione. Se non ci sono connessioni completate il processo viene messo in attesa. Il prototipo della funzione è il seguente: - \begin{prototype}{sys/socket.h} -{int listen(int sockfd, struct sockaddr *addr, socklen\_t *addrlen)} - La funzione estrae la prima connessione completa relativa al socket - \texttt{sockfd} in attesa sulla coda delle connessioni complete che associa - nuovo socket con le stesse caratteristiche di \texttt{sockfd} (restituito - dalla funzione stessa). Il socket originale non viene toccato. Nella - struttura \texttt{addr} e nella variabile \texttt{addrlen} vengono - restituiti indirizzo e relativa lunghezza del client che si è connesso. +{int listen(int sockfd, struct sockaddr *addr, socklen\_t *addrlen)} + La funzione estrae la prima connessione relativa al socket \texttt{sockfd} + in attesa sulla coda delle connessioni complete, che associa ad nuovo socket + con le stesse caratteristiche di \texttt{sockfd} (restituito dalla funzione + stessa). Il socket originale non viene toccato. Nella struttura + \texttt{addr} e nella variabile \texttt{addrlen} vengono restituiti + indirizzo e relativa lunghezza del client che si è connesso. La funzione restituisce un numero di socket descriptor positivo in caso di successo e -1 in caso di errore, nel qual caso la variabile \texttt{errno} @@ -959,6 +958,13 @@ viene messo in attesa. Il prototipo della funzione \item \texttt{ENOBUFS, ENOMEM} Not enough free memory. This often means that the memory allocation is limited by the socket buffer limits, not by the system memory. + + Inoltre possono essere restituiti gli errori di rete relativi al nuovo + socket come: \texttt{EMFILE}, \texttt{EINVAL}, \texttt{ENOSR}, + \texttt{ENOBUFS}, \texttt{EPERM}, \texttt{ECONNABORTED}, + \texttt{ESOCKTNOSUPPORT}, \texttt{EPROTONOSUPPORT}, \texttt{ETIMEDOUT}, + \texttt{ERESTARTSYS}. + \end{errlist} \end{prototype} @@ -971,26 +977,48 @@ connessioni, la conferma della connessione viene fatta implicitamente dalla prima chiamata ad una \texttt{read} o una \texttt{write} mentre il rifiuto della connessione viene fatta con la funzione \texttt{close}. +E da chiarire che linux presenta un comportamento diverso nella gestione degli +errori rispetto ad altre implementazioni dei socket BSD, infatti la funzione +\texttt{accept} passa gli errori di rete pendenti sul nuovo socket come codici +di errore per \texttt{accept}. Inoltre la funzione non fa ereditare ai nuovi +socket flag come \texttt{O_NONBLOCK}, che devono essere rispecificati volta +volta, questo è un comportamento diverso rispetto a quanto accade con BSD e +deve essere tenuto in conto per scrivere programmi portabili. + I due parametri \texttt{cliaddr} e \texttt{addrlen} (si noti che quest'ultimo è passato per indirizzo per avere indietro il valore) sono usati per ottenere l'indirizzo del client da cui proviene la connessione. Prima della chiamata \texttt{addrlen} deve essere inizializzato alle dimensioni della struttura il -cui indirizzo è passato come parametro in \texttt{cliaddr}, al rientro della +cui indirizzo è passato come parametro in \texttt{cliaddr}, al ritorno della funzione \texttt{addrlen} conterrà il numero di bytes scritti dentro -\texttt{cliaddr}. - -Se la funzione ha successo restituisce un nuovo socket descriptor, detto -\textit{connected socket}, su cui è agganciata la connessione che il client -TCP ha effettuato verso il socket \texttt{sockfd}. Quest'ultimo, che viene -chiamato invece \textit{listening socket}, deve essere stato creato in -precedenza e messo in ascolto con \texttt{listen}, e non viene toccato dalla -funzione. - -Questa distinzione è essenziale per capire +\texttt{cliaddr}. Se questa informazione non interessa basterà inizializzare a +\texttt{NULL} detti puntatori. + +Se la funzione ha successo restituisce il descrittore di un nuovo socket +creato dal kernel (detto \textit{connected socket}) a cui viene associata la +prima connessione completa (estratta dalla relativa coda, vedi +\secref{sec:TCPel_func_listen}) che il client TCP ha effettuato verso il +socket \texttt{sockfd}. Quest'ultimo (detto \textit{listening socket}) è +quello creato all'inizio e messo in ascolto con \texttt{listen}, e non viene +toccato dalla funzione. + +Se non ci sono connessioni pendenti da accettare la funzione mette in attesa +il processo\footnote{a meno che non si sia settato il socket per essere + non-bloccante, nel qual caso ritorna con l'errore \texttt{EAGAIN}, + torneremo su questa modalità di operazione in \secref{sec:xxx_sock_noblock}} +fintanto che non ne arriva una. + +Questo meccanismo è essenziale per capire il funzionamento di un server, in +generale infatti c'è sempre un solo socket in ascolto, che resta per tutto il +tempo nello stato \texttt{LISTEN}, mentre le connessioni vengono gestite dai +nuovi socket ritornati da \texttt{accept} che sono posti automaticamente nello +stato \texttt{ESTABLISHED} e utilizzati fino alla chiusura della connessione +che avviene su di essi. Si può riconoscere questo schema anche nell'esempio +elementare in \figref{fig:net_serv_code} dove per ogni connessione il socket +creato da \texttt{accept} viene chiuso dopo l'invio dei dati. +\section{Un server concorrente su TCP} +\label{sec:TCPel_cunc_serv} -\section{Una semplice implementazione del servizio \texttt{echo} su TCP} -\label{sec:TCPel_echo_example} -Veniamo ora ad una applicazione