From 4b024e83c333c441b9f9c10d7b3595d8ca7def63 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Tue, 12 Sep 2006 13:29:14 +0000 Subject: [PATCH] Spiegato per bene il significato delle varie opzioni di ottimizzazione dei socket TCP: {{{TCP_NODELAY}}}, {{{TCP_DEFER_ACCEPT}}}, {{{TCP_CORK}}}, {{{TCP_QUICKACK}}}. --- sockctrl.tex | 308 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 201 insertions(+), 107 deletions(-) diff --git a/sockctrl.tex b/sockctrl.tex index 886d6d0..d3293ec 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2299,6 +2299,8 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: \func{select} che ritorna a causa dello stesso. \end{basedescript} +% TODO documentare SO_ATTACH_FILTER e SO_DETACH_FILTER + \subsection{L'uso delle principali opzioni dei socket} \label{sec:sock_options_main} @@ -3050,12 +3052,12 @@ accessibili includendo detto file.\footnote{in realt \hline \hline \const{TCP\_NODELAY} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& - spedisce tutti i pacchetti il prima possibile.\\ + spedisce immediatamente i dati in segmenti singoli.\\ \const{TCP\_MAXSEG} &$\bullet$&$\bullet$& &\texttt{int}& - valore della \itindex{Maximum~Segment~Size} MSS per i pacchetti in + valore della \itindex{Maximum~Segment~Size} MSS per i segmenti in uscita.\\ \const{TCP\_CORK} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& - non invia frame parziali.\\ + accumula i dati in un unico segmento.\\ \const{TCP\_KEEPIDLE} &$\bullet$&$\bullet$& &\texttt{int}& tempo in secondi prima di inviare un \textit{keepalive}.\\ \const{TCP\_KEEPINTVL} &$\bullet$&$\bullet$& &\texttt{int}& @@ -3089,107 +3091,187 @@ la spiegazione del funzionamento delle singole opzioni con una maggiore quantità di dettagli è fornita nel seguente elenco: \begin{basedescript}{\desclabelwidth{3.3cm}\desclabelstyle{\nextlinelabel}} -\item[\const{TCP\_NODELAY}] il protocollo TCP un meccanismo di bufferizzazione - dei pacchetti uscenti, per evitare la trasmissione di tanti pacchetti - piccoli con un utilizzo non ottimale della banda disponibile. Questo - meccanismo è controllato da un apposito algoritmo (detto \textsl{algoritmo - di Nagle}, vedi sez.\ref{sez:tcp_protocol_xxx}). Il comportamento normale - del protocollo prevede che i pacchetti siano accumulati fintanto che non si - raggiunge una quantità di dati considerata adeguata per eseguire la - trasmissione. - - Impostando questa opzione si disabilita questo meccanismo ed i pacchetti - vengono inviati immediatamente qualunque sia la loro dimensione; l'opzione - viene sovrascritta dall'eventuale impostazione dell'opzione - \const{TCP\_CORK}, che blocca l'invio immediato. Tuttavia quando la si - abilita viene sempre forzato lo scaricamento della coda di invio (con - conseguente trasmissione di tutti i pacchetti pendenti), anche qualora si - fosse già abilitata \const{TCP\_CORK}.\footnote{si tenga presente però che - \const{TCP\_CORK} può essere specificata insieme a \const{TCP\_NODELAY} - soltanto a partire dal kernel 2.5.71.} - -\item[\const{TCP\_MAXSEG}] permette di leggere e modificare il valore della - \itindex{Maximum~Segment~Size} MSS (vedi sez.~\ref{sec:net_lim_dim} e - sez.\ref{sez:tcp_protocol_xxx}) dei pacchetti uscenti, e se l'opzione è - impostata prima di stabilire la connessione, cambia anche il valore della +\item[\const{TCP\_NODELAY}] il protocollo TCP utilizza un meccanismo di + bufferizzazione dei dati uscenti, per evitare la trasmissione di tanti + piccoli segmenti con un utilizzo non ottimale della banda + disponibile.\footnote{il problema è chiamato anche \textit{silly window + syndrome}, per averne un'idea si pensi al risultato che si ottiene + quando un programma di terminale invia un segmento TCP per ogni tasto + premuto, 40 byte di intestazione di protocollo con 1 byte di dati + trasmessi; per evitare situazioni del genere è stato introdotto + l'\textsl{algoritmo di Nagle}.} Questo meccanismo è controllato da un + apposito algoritmo (detto \textsl{algoritmo di Nagle}, vedi + sez.\ref{sez:tcp_protocol_xxx}). Il comportamento normale del protocollo + prevede che i dati siano accumulati fintanto che non si raggiunge una + quantità considerata adeguata per eseguire la trasmissione di un singolo + segmento. + + Ci sono però delle situazioni in cui questo comportamento può non essere + desiderabile, ad esempio quando si sa in anticipo che l'applicazione invierà + soltanto un piccolo quantitativo di dati;\footnote{è il caso classico di una + richiesta HTTP.} in tal caso l'attesa introdotta dall'algoritmo di + bufferizzazione non soltanto è inutile, ma peggiora le prestazioni + introducendo un ritardo. Impostando questa opzione si disabilita l'uso + dell'\textsl{algoritmo di Nagle} ed i dati vengono inviati immediatamente in + singoli segmenti, qualunque sia la loro dimensione. Ovviamente l'uso di + questa opzione è dedicato a chi ha esigenze particolari come quella + illustrata, che possono essere stabilite solo per la singola applicazione. + + Si tenga conto che questa opzione viene sovrascritta dall'eventuale + impostazione dell'opzione \const{TCP\_CORK} (il cui scopo è sostanzialmente + l'opposto) che blocca l'invio immediato. Tuttavia quando la si abilita viene + sempre forzato lo scaricamento della coda di invio (con conseguente + trasmissione di tutti i dati pendenti), anche qualora si fosse già abilitata + \const{TCP\_CORK}.\footnote{si tenga presente però che \const{TCP\_CORK} può + essere specificata insieme a \const{TCP\_NODELAY} soltanto a partire dal + kernel 2.5.71.} + +\item[\const{TCP\_MAXSEG}] con questa opzione si legge o si imposta il valore + della \itindex{Maximum~Segment~Size} MSS (vedi sez.~\ref{sec:net_lim_dim} e + sez.\ref{sez:tcp_protocol_xxx}) dei segmenti TCP uscenti. Se l'opzione è + impostata prima di stabilire la connessione, si cambia anche il valore della \itindex{Maximum~Segment~Size} MSS annunciata all'altro capo della connessione. Se si specificano valori maggiori della MTU questi verranno ignorati, inoltre TCP imporrà anche i suoi limiti massimo e minimo per questo valore. -\item[\const{TCP\_CORK}] quando questa opzione viene abilitata non vengono - inviati pacchetti di dati fintanto che essa non venga disabilitata; a quel - punto tutti i dati rimasti in coda saranno inviati in un solo pacchetto. - Questa opzione viene usata per gestire manualmente il flusso dei dati - mettendo una sorta di ``\textsl{tappo}'' (da cui il nome in inglese) al - flusso di uscita, in modo ottimizzare a mano l'uso della banda. È molto - utile anche quando si effettua il trasferimento di dati da un file con - \func{sendfile} (vedi sez.~\ref{sec:file_sendfile}), se si vuole inserire - una intestazione prima della chiamata a questa funzione. +\item[\const{TCP\_CORK}] questa opzione è il complemento naturale di + \const{TCP\_NODELAY} e serve a gestire a livello applicativo la situazione + opposta, cioè quella in cui si sa fin dal principio che si dovranno inviare + grosse quantità di dati. Anche in questo caso l'\textsl{algoritmo di Nagle} + tenderà a suddividerli in dimensioni da lui ritenute + opportune,\footnote{l'algoritmo cerca di tenere conto di queste situazioni, + ma essendo un algoritmo generico tenderà comunque ad introdurre delle + suddivisioni in segmenti diversi, anche quando potrebbero non essere + necessarie, con conseguente spreco di banda.} ma sapendo fin dall'inizio + quale è la dimensione dei dati si potranno di nuovo ottenere delle migliori + prestazioni disabilitandolo, e gestendo direttamente l'invio del nostro + blocco di dati in soluzione unica. + + Quando questa opzione viene abilitata non vengono inviati segmenti di dati + fintanto che essa non venga disabilitata; a quel punto tutti i dati rimasti + in coda saranno inviati in un solo segmento TCP. In sostanza con questa + opzione si può controllare il flusso dei dati mettendo una sorta di + ``\textsl{tappo}'' (da cui il nome in inglese) al flusso di uscita, in modo + ottimizzare a mano l'uso della banda. Si tenga presente che per l'effettivo + funzionamento ci si deve ricordare di disattivare l'opzione al termine + dell'invio del blocco dei dati. + + Si usa molto spesso \const{TCP\_CORK} quando si effettua il trasferimento + diretto di un blocco di dati da un file ad un socket con \func{sendfile} + (vedi sez.~\ref{sec:file_sendfile}), per inserire una intestazione prima + della chiamata a questa funzione; senza di essa l'intestazione potrebbe + venire spedita in un segmento a parte, che a seconda delle condizioni + potrebbe richiedere anche una risposta di ACK, portando ad una notevole + penalizzazione delle prestazioni. Si tenga presente che l'implementazione corrente di \const{TCP\_CORK} non - consente di bloccare l'invio dei pacchetti per più di 200 millisecondi, - passati i quali i dati accumulati in coda sanno inviati comunque. Questa - opzione non è disponibile su tutti i kernel unix-like e deve essere evitata - se si vuole scrivere codice portabile. - -\item[\const{TCP\_KEEPIDLE}] imposta l'intervallo di tempo, in secondi, che - deve trascorrere senza traffico sul socket prima che vengano inviati, - qualora si sia attivata su di esso l'opzione \const{SO\_KEEPALIVE}, i - messaggi di \textit{keep-alive} (si veda la trattazione relativa al - \textit{keep-alive} in sez.~\ref{sec:sock_options_main}). Anche questa - opzione non è disponibile su tutti i kernel unix-like e deve essere evitata - se si vuole scrivere codice portabile. - -\item[\const{TCP\_KEEPINTVL}] imposta l'intervallo di tempo, in secondi, fra - due messaggi di \textit{keep-alive} successivi (si veda sempre quanto - illustrato in sez.~\ref{sec:sock_options_main}). Come la precedente non è - disponibile su tutti i kernel unix-like e deve essere evitata se si vuole - scrivere codice portabile. + consente di bloccare l'invio dei dati per più di 200 millisecondi, passati i + quali i dati accumulati in coda sanno inviati comunque. Questa opzione è + tipica di Linux\footnote{l'opzione è stata introdotta con i kernel della + serie 2.4.x.} e non è disponibile su tutti i kernel unix-like, pertanto + deve essere evitata se si vuole scrivere codice portabile. + +\item[\const{TCP\_KEEPIDLE}] con questa opzione si legge o si imposta + l'intervallo di tempo, in secondi, che deve trascorrere senza traffico sul + socket prima che vengano inviati, qualora si sia attivata su di esso + l'opzione \const{SO\_KEEPALIVE}, i messaggi di \textit{keep-alive} (si veda + la trattazione relativa al \textit{keep-alive} in + sez.~\ref{sec:sock_options_main}). Anche questa opzione non è disponibile + su tutti i kernel unix-like e deve essere evitata se si vuole scrivere + codice portabile. + +\item[\const{TCP\_KEEPINTVL}] con questa opzione si legge o si imposta + l'intervallo di tempo, in secondi, fra due messaggi di \textit{keep-alive} + successivi (si veda sempre quanto illustrato in + sez.~\ref{sec:sock_options_main}). Come la precedente non è disponibile su + tutti i kernel unix-like e deve essere evitata se si vuole scrivere codice + portabile. -\item[\const{TCP\_KEEPCNT}] imposta il numero totale di messaggi di - \textit{keep-alive} da inviare prima di concludere che la connessione è - caduta per assenza di risposte ad un messaggio di \textit{keep-alive} (di - nuovo vedi sez.~\ref{sec:sock_options_main}). Come la precedente non è - disponibile su tutti i kernel unix-like e deve essere evitata se si vuole +\item[\const{TCP\_KEEPCNT}] con questa opzione si legge o si imposta il numero + totale di messaggi di \textit{keep-alive} da inviare prima di concludere che + la connessione è caduta per assenza di risposte ad un messaggio di + \textit{keep-alive} (di nuovo vedi sez.~\ref{sec:sock_options_main}). Come + la precedente non è disponibile su tutti i kernel unix-like e deve essere + evitata se si vuole scrivere codice portabile. + +\item[\const{TCP\_SYNCNT}] con questa opzione si legge o si imposta il numero + di tentativi di ritrasmissione dei segmenti SYN usati nel + \itindex{three~way~handshake} \textit{three way handshake} prima che il + tentativo di connessione venga abortito (si ricordi quanto accennato in + sez.\ref{sec:TCP_func_connect}). Sovrascrive per il singolo socket il valore + globale impostato con la \textit{sysctl} \texttt{tcp\_syn\_retries} (vedi + sez.~\ref{sec:sock_ipv4_sysctl}). Non vengono accettati valori maggiori di + 255; anche questa opzione non è standard e deve essere evitata se si vuole scrivere codice portabile. -\item[\const{TCP\_SYNCNT}] imposta il numero di tentativi di ritrasmissione - dei segmenti SYN usati nel \itindex{three~way~handshake} \textit{three way - handshake} prima che il tentativo di connessione venga abortito (si - ricordi quanto accennato in sez.\ref{sec:TCP_func_connect}). Sovrascrive per - il singolo socket il valore globale impostato con la \textit{sysctl} - \texttt{tcp\_syn\_retries} (vedi sez.~\ref{sec:sock_ipv4_sysctl}). Non - vengono accettati valori maggiori di 255; anche questa opzione non è - standard e deve essere evitata se si vuole scrivere codice portabile. - -\item[\const{TCP\_LINGER2}] imposta, in numero di secondi, il tempo di - sussistenza dei socket terminati nello stato \texttt{FIN\_WAIT2} (si ricordi - quanto visto in sez.~\ref{sec:TCP_conn_term}).\footnote{si tenga ben - presente che questa opzione non ha nulla a che fare con l'opzione - \const{SO\_LINGER} che abbiamo visto in sez.~\ref{sec:sock_options_main}.} - Questa opzione consente di sovrascrivere per il singolo socket il valore - globale impostato con la \textit{sysctl} \texttt{tcp\_fin\_timeout} (vedi +\item[\const{TCP\_LINGER2}] con questa opzione si legge o si imposta, in + numero di secondi, il tempo di sussistenza dei socket terminati nello stato + \texttt{FIN\_WAIT2} (si ricordi quanto visto in + sez.~\ref{sec:TCP_conn_term}).\footnote{si tenga ben presente che questa + opzione non ha nulla a che fare con l'opzione \const{SO\_LINGER} che + abbiamo visto in sez.~\ref{sec:sock_options_main}.} Questa opzione + consente di sovrascrivere per il singolo socket il valore globale impostato + con la \textit{sysctl} \texttt{tcp\_fin\_timeout} (vedi sez.~\ref{sec:sock_ipv4_sysctl}). Anche questa opzione è da evitare se si ha a cuore la portabilità del codice. -\item[\const{TCP\_DEFER\_ACCEPT}] consente ad un socket in ascolto di - ritornare da \func{accept} soltanto quando sono presenti dati sullo stesso, - e non alla conclusione del \itindex{three~way~handshake} \textit{three way - handshake}. Prende un valore intero che indica il numero massimo di - secondi per cui il ritorno di \func{accept} viene rimandato; non deve essere +\item[\const{TCP\_DEFER\_ACCEPT}] questa opzione consente di modificare il + comportamento standard del protocollo TCP nello stabilirsi di una + connessione; se ricordiamo il meccanismo del \itindex{three~way~handshake} + \textit{three way handshake} illustrato in fig.~\ref{fig:TCP_TWH} possiamo + vedere che in genere un client inizierà ad inviare i dati ad un server solo + dopo l'emissione dell'ultimo segmento di ACK. + + Di nuovo esistono situazioni (e la più tipica è quella di una richiesta + HTTP) in cui sarebbe utilie inviare immediatamente la richiesta all'interno + del segmento con l'ultimo ACK del \itindex{three~way~handshake} + \textit{three way handshake}; si potrebbe così risparmiare l'invio di un + segmento successivo per la richiesta e il ritardo sul server fra la + ricezione dell'ACK e quello della richiesta. + + Se si invoca \const{TCP\_DEFER\_ACCEPT} su un socket dal lato client (cioè + dal lato da cui si invoca \func{connect}) si istruisce il kernel a non + inviare immediatamente l'ACK finale del \itindex{three~way~handshake} + \textit{three way handshake}, attendendo per un po' di tempo la prima + scrittura, in modo da inviare i dati di questa insieme col segmento ACK. + Chiaramente la correttezza di questo comportamento dipende in maniera + diretta dal tipo di applicazione che usa il socket; con HTTP, che invia una + breve richiesta, permette di risparmiare un segmento, con FTP, in cui invece + si attende la ricezione del prompt del server, introduce un inutile ritardo. + + Allo stesso tempo il protocollo TCP prevede che sul lato del server la + funzione \func{accept} ritorni dopo la ricezione dell'ACK finale, in tal + caso quello che si fà usualmente è lanciare un nuovo processo per leggere i + successivi dati che si bloccherà su una \func{read} se questi non sono + disponibili, ma così si saranno impiegate delle risorse (per la creazione + del nuovo processo) che non saranno usate immediatamente. L'uso di + \const{TCP\_DEFER\_ACCEPT} consente di intervenire anche in questa + situazione; quando la si invoca sul lato server (vale a dire su un socket in + ascolto) l'opzione fa sì che \func{accept} ritorni soltanto quando sono + presenti dei dati sul socket, e non alla ricezione dell'ACK conclusivo del + \itindex{three~way~handshake} \textit{three way handshake}. + + L'opzione prende un valore intero che indica il numero massimo di secondi + per cui mantenere il ritardo, sia per quanto riguarda il ritorno di + \func{accept} su un server, che per l'invio dell'ACK finale insieme ai dati + su un client. L'opzione è specifica di Linux non deve essere utilizzata in + codice che vuole essere portabile.\footnote{su FreeBSD è presente una + opzione \texttt{SO\_ACCEPTFILTER} che consente di ottenere lo stesso + comportamento di \const{TCP\_DEFER\_ACCEPT} per quanto riguarda il lato + server.} + +\item[\const{TCP\_WINDOW\_CLAMP}] con questa opzione si legge o si imposta + alla dimensione specificata, in byte, il valore dichiarato della + \itindex{advertised~window} \textit{advertised window} (vedi + sez.\ref{sez:tcp_protocol_xxx}). Il kernel impone comunque una dimensione + minima pari a \texttt{SOCK\_MIN\_RCVBUF/2}. Questa opzione non deve essere utilizzata in codice che vuole essere portabile. -\item[\const{TCP\_WINDOW\_CLAMP}] limita alla dimensione specificata (in byte) - il valore dichiarato della \itindex{advertised~window} \textit{advertised - window} (vedi sez.\ref{sez:tcp_protocol_xxx}). Il kernel impone comunque - una dimensione minima pari a \texttt{SOCK\_MIN\_RCVBUF/2}. Questa opzione - non deve essere utilizzata in codice che vuole essere portabile. - -\item[\const{TCP\_INFO}] opzione, specifica di Linux, ma introdotta anche in - altri kernel (ad esempio FreeBSD) di controllare lo stato di un socket TCP - in user space. L'opzione restituisce in una speciale struttura - \struct{tcp\_info}, la cui definizione è riportata in +\item[\const{TCP\_INFO}] questa opzione, specifica di Linux, ma introdotta + anche in altri kernel (ad esempio FreeBSD) permette di controllare lo stato + di un socket TCP in user space. L'opzione restituisce in una speciale + struttura \struct{tcp\_info}, la cui definizione è riportata in fig.~\ref{fig:tcp_info_struct}, tutta una serie di dati relativi al socket. Anche questa opzione deve essere evitata se si vuole scrivere codice portabile. @@ -3221,15 +3303,28 @@ fig.~\ref{fig:is_closing}, in cui si utilizza il valore del campo \label{fig:is_closing} \end{figure} -\item[\const{TCP\_QUICKACK}] abilita o disabilita la modalità speciale - \textit{quickack}, in cui i pacchetti ACK vengono inviati immediatamente - senza le attese talvolta imposte dal normale funzionamento del protocollo - TCP. Questa opzione prende un valore logico, e non è permanente, nel senso - che si limita a forzare al momento della chiamata un passaggio da o verso la - modalità \textit{quickack}; le operazioni successive potrebbero a loro volta - entrare o uscire da questa modalità a seconda del processo interno del - protocollo o dalle condizioni della connessione (ad esempio in presenza di - timeout ritardati per i pacchetti ACK). +\item[\const{TCP\_QUICKACK}] con questa opzione è possibile eseguire una forma + di controllo sull'invio dei segmenti ACK all'interno di in flusso di dati su + TCP. In genere questo invio viene gestito direttamente dal kernel, il + comportamento standard, corrispondente la valore logico di vero (in genere + 1) per questa opzione, è quello di inviare immediatamente i segmenti ACK, in + quanto normalmente questo significa che si è ricevuto un blocco di dati e si + può passare all'elaborazione del blocco successivo. + + Qualora però la nostra applicazione sappia in anticipo che alla ricezione di + un blocco di dati seguirà immediatamente l'invio di un altro + blocco,\footnote{caso tipico ad esempio delle risposte alle richieste HTTP.} + poter accorpare quest'ultimo al segmento ACK permette di risparmiare sia in + termini di dati inviati che di velocità di risposta. Per far questo si può + utilizzare \const{TCP\_QUICKACK} impostando un valore logico falso (cioè 0), + in questo modo il kernel attenderà così da inviare il prossimo segmento di + ACK insieme ai primi dati disponibili. + + Si tenga presente che l'opzione non è permanente, vale a dire che una volta + che la si sia impostata a 0 il kernel la riporterà al valore di default dopo + il suo primo utilizzo. Sul lato server la si può impostare anche una volta + sola su un socket in ascolto, ed essa verrà ereditata da tutti i socket che + si otterranno da esso al ritorno di \func{accept}. % TODO trattare con gli esempi di apache @@ -3958,6 +4053,14 @@ pagina di manuale (accessibile con \texttt{man 7 tcp}), sono i seguenti: \item[\texttt{tcp\_wmem}] \end{basedescript} + +%%% Local Variables: +%%% mode: latex +%%% TeX-master: "gapil" +%%% End: + + + % LocalWords: socket sez dotted decimal resolver Domain Name Service cap DNS % LocalWords: client fig LDAP Lightweight Access Protocol NIS Information Sun % LocalWords: like netgroup Switch Solaris glibc libc uclib NSS tab shadow uid @@ -4029,14 +4132,5 @@ pagina di manuale (accessibile con \texttt{man 7 tcp}), sono i seguenti: % LocalWords: intvl probes latency orphans l'ACK SYNQ HSIZE tw buckets mem rfc % LocalWords: orphan reordering collapse sack stdurg synack syncookies recycle % LocalWords: timestamps scaling vegas avoid westwood tcpi l'incapsulazione - - - - - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: "gapil" -%%% End: % LocalWords: metric EOPNOTSUPP mtu hwaddr ARPHRD interrupt DMA map qlen % LocalWords: rename ifconf -- 2.30.2