Parte III — Trasporto affidabile e TCP · Capitolo 11

TCP: calcolo del time-out e controllo di flusso

~45 min di lettura5 widget interattivi

In questo capitolo

  1. La scelta del time-out di ritrasmissione
  2. La stima del Round-Trip Time
  3. Il metodo classico (RFC 793)
  4. L'algoritmo di Jacobson
  5. Media, EWMA e RTO a confronto
  6. Ambiguità del RTT e algoritmo di Karn
  7. Back-off esponenziale
  8. Conferma della trasmissione e SACK
  9. ACK duplicati e Fast Retransmit
  10. ACK ritardati e algoritmo di Nagle
  11. Il controllo di flusso del TCP
  12. Gestione dei buffer di trasmissione e ricezione
  13. Deadlock, Persist Timer e window probe
  14. Silly window syndrome e keepalive
  15. Verifica le tue conoscenze

1. La scelta del time-out di ritrasmissione

Quando il TCP trasmette un segmento avvia il Retransmission Time-Out, o RTO. Il protocollo mantiene tipicamente un solo contatore per connessione: l'ACK deve arrivare prima della sua scadenza, altrimenti i dati non riscontrati vengono ritrasmessi.

La scelta del valore non ammette scorciatoie. Un time-out troppo breve non lascia agli ACK il tempo di tornare e produce ritrasmissioni inutili; un time-out troppo lungo fa attendere troppo un ACK che non arriverà, perdendo tempo e riducendo l'efficienza. Il valore corretto è quindi strettamente legato alla stima del Round-Trip Time.

RTO troppo breve TxRx segmento ACK RTO scade ritrasmissione inutile RTO < RTT osservato RTO troppo lungo TxRx perso RTO scade molto tardi attesa improduttiva recupero ritardato Il RTT varia con le condizioni della rete: per questo RTO deve essere determinato dinamicamente.
Tavola 11.1 — I due errori opposti nella scelta del time-out. Anticipare l'ACK spreca trasmissioni; aspettare troppo una perdita spreca tempo.

Il RTT è una variabile aleatoria: media e varianza cambiano con le condizioni della rete. Un RTO statico non può seguire entrambi i cambiamenti. L'idea di base è mantenere aggiornata una stima del RTT e calcolare il time-out in funzione sia del livello medio sia della variabilità osservata.

2. La stima del Round-Trip Time

Il TCP campiona continuamente ciò che accade ai segmenti inviati. Per ogni misura memorizza l'istante di trasmissione di un segmento e lo sottrae dall'istante di arrivo del relativo ACK. Ottenuto un campione, aggiorna gli stimatori e avvia una nuova misura.

Quando l'opzione timestamp è presente, la misura può usare i valori trasportati dai segmenti: TS Value nel segmento dati inviato dalla sorgente e TS Echo Reply nel relativo ACK della destinazione. Il lessico delle formule è:

SimboloSignificato
RTTkk-esimo campione misurato del Round-Trip Time
sRTTkstima smussata del valore medio, basata sui campioni fino a k
RTTvarkstima della deviazione media del RTT rispetto alla media stimata
Idea chiave

Il campione dice che cosa è appena successo; sRTT descrive il livello attorno a cui oscillano le misure; RTTvar misura quanto sia prudente allontanare RTO da quel livello. Una media senza dispersione non distingue una rete stabile da una rete molto variabile.

3. Il metodo classico (RFC 793)

Il metodo classico aggiorna la stima media con una Exponential Weighted Moving Average, o EWMA:

sRTTₖ = α sRTTₖ₋₁ + (1 − α) RTTₖ

α raccomandato: 0.8–0.9

La media è pesata perché α decide il peso dei campioni passati rispetto al nuovo; è mobile perché si aggiorna a ogni misura; è esponenziale perché il peso dei campioni precedenti diminuisce geometricamente. Con α vicino a 1 la memoria è lunga e la risposta ai cambiamenti è graduale.

Il metodo stima soltanto la media. Per trasformarla in un time-out applica un fattore di scala β e impone limiti fissi:

RTO = min(ubound, max(lbound, β sRTT))

β = 1.3–2.0       ubound = 1 min       lbound = 1 s

La moltiplicazione prova a lasciare margine sopra la media, ma non misura davvero la varianza. Con β = 1.3 si rischia di sottostimare RTT quando oscilla; con β = 2.0 si sovrastima troppo quando RTT è stabile. La stima è accurata soltanto se la varianza rimane limitata.

Per l'esame

Nella formula classica il nuovo campione pesa 1 − α, non α. Va scritta per intero insieme alla saturazione: RTO = min(ubound, max(lbound, β sRTT)). Il difetto da citare è l'assenza di una stima esplicita della variabilità.

4. L'algoritmo di Jacobson (RFC 2988, 6298)

Jacobson conserva l'EWMA della media e aggiunge un'EWMA della deviazione media. Con la convenzione delle RFC 2988 e 6298 le formule sono:

sRTTₖ = (1 − α) sRTTₖ₋₁ + α RTTₖ
RTTvarₖ = (1 − β) RTTvarₖ₋₁ + β |sRTTₖ₋₁ − RTTₖ|
RTO = sRTT + max(G, 4 RTTvar)

α = 1/8       β = 1/4       G = granularità del clock

Qui α pesa direttamente il campione nuovo: è la stessa EWMA del metodo classico scritta con una convenzione complementare. Nella seconda riga lo scarto usa il valore precedente sRTTk−1. Il termine 4 RTTvar crea un margine che cresce quando le misure sono instabili; G impedisce che il margine scenda sotto la risoluzione temporale disponibile.

MomentoInizializzazione
prima di misurare RTTRTO = 1 s
dopo il primo campionesRTT₁ = RTT₁ e RTTvar₁ = RTT₁/2
limitiminimo 1 s; massimo opzionale, ma almeno 1 min

Se le fluttuazioni sono piccole, RTTvar si contrae e RTO ≈ sRTT, salvo i limiti. Se le fluttuazioni sono grandi, il margine cresce e RTO > sRTT in modo consistente. È proprio il comportamento che il solo fattore di scala non riesce a ottenere.

Per l'esame

Le tre formule di Jacobson, i valori α = 1/8, β = 1/4 e l'inizializzazione dopo il primo campione sono da saper ricostruire. Non confondere β di Jacobson, che pesa la deviazione, con il fattore 1.3–2.0 del metodo classico.

5. Esempio di stima: media semplice, EWMA e RTO a confronto

Le figure delle slide confrontano una traccia di RTT con la media semplice, la EWMA classica e i diversi RTO. Il comportamento qualitativo è netto: la media semplice diventa sempre meno reattiva perché ogni nuovo campione pesa quanto tutti i precedenti; l'EWMA continua invece ad attribuire un peso controllato alle osservazioni recenti.

Risposta qualitativa a una variazione del RTT RTTk 020406080100 RTT campionato media semplice sRTT classico RTO classico β=1.3 RTO classico β=2.0 RTO Jacobson Jacobson allarga il margine durante la fase variabile e lo restringe quando si stabilizza. Curve schematiche: mostrano il confronto delle slide, non una scala operativa del limite minimo di 1 s.
Tavola 11.2 — Il confronto qualitativo fra gli stimatori. Un fattore fisso non sa essere insieme prudente durante un salto e vicino alla media durante una fase stabile; la deviazione stimata sì.

Nel calcolo guidato, il primo campione inizializza entrambi i metodi. A ogni passo successivo il classico aggiorna soltanto sRTT e moltiplica per β = 3/2; Jacobson aggiorna prima la deviazione rispetto al precedente sRTT, poi la media. Il campione alto evidenziato nella serie allarga RTTvar; i campioni successivi la fanno rientrare gradualmente.

6. Ambiguità del RTT e algoritmo di Karn

Senza timestamp, un ACK ricevuto dopo una ritrasmissione è ambiguo: potrebbe confermare il segmento originale arrivato tardi oppure la sua copia ritrasmessa. Nel primo caso misurare dall'ultima trasmissione sottostima il RTT; nel secondo misurare dalla prima lo sovrastima. Il solo numero di riscontro non permette di distinguere le due storie.

L'algoritmo di Karn elimina il campione ambiguo invece di indovinarne l'origine:

Per l'esame

Karn non corregge matematicamente il campione: lo scarta. La frase completa è «non misurare RTT dopo una ritrasmissione e riprendere al prossimo ACK pulito». Questo protegge sia sRTT sia RTTvar da un dato di cui non si conosce l'origine.

7. Back-off esponenziale

Karn introduce anche il back-off esponenziale. Dopo una ritrasmissione, il valore corrente di RTO potrebbe essere troppo basso e provocare altre scadenze premature. Per lasciare più tempo all'ACK, il TCP raddoppia RTO a ogni nuova ritrasmissione, fino al valore massimo previsto.

La sequenza è RTO1 → RTO2 → RTO3 → RTO4, con ciascun intervallo doppio del precedente. Alla ricezione dell'ACK il valore viene ripristinato: il back-off è una cautela transitoria, non una nuova misura del RTT.

Per l'esame

Karn e back-off risolvono problemi distinti ma collegati: Karn impedisce che un ACK ambiguo inquini lo stimatore; il back-off impedisce che un RTO già sospetto inneschi una raffica di ritrasmissioni. Il primo agisce sulla misura, il secondo sull'attesa.

8. Conferma della trasmissione e SACK

Gli ACK possono viaggiare in piggybacking, dentro segmenti dati con ACK=1 diretti nel verso opposto, oppure in segmenti ACK-only, formati dalla sola intestazione TCP con ACK=1. In entrambi i casi sono cumulativi: AckN identifica il primo byte non ancora ricevuto in sequenza.

La procedura predefinita è di tipo Go-Back-N, sebbene molte implementazioni conservino in memoria i segmenti corretti arrivati fuori sequenza. All'apertura della connessione, nelle opzioni di SYN e SYN+ACK, gli endpoint possono negoziare il Selective Acknowledgement. Con SACK il ricevitore aggiunge agli ACK cumulativi gli intervalli di numeri di sequenza ricevuti correttamente ma fuori sequenza.

SACK negoziato in SYN / SYN+ACK sorgentedestinazione SeqN=200 SeqN=300 AckN=300 SeqN=400 X AckN=400 SeqN=500 SeqN=600 AckN=400 · SACK: 500–599 AckN=400 · SACK: 500–699 ritrasmette SeqN=400 AckN=700 Il riscontro cumulativo resta 400; SACK descrive i blocchi già presenti oltre il buco.
Tavola 11.3 — SACK non sostituisce AckN: lo completa. Il ricevitore continua a chiedere il byte 400, ma comunica che gli intervalli 500–599 e poi 500–699 non devono essere ritrasmessi.

9. Segmenti persi o fuori sequenza e Fast Retransmit

Quando manca un segmento ma arrivano i successivi, la destinazione riceve dati fuori sequenza e invia immediatamente un ACK duplicato per ciascun segmento. Tutti ripetono il numero del primo byte ancora atteso. La sorgente apprende così che quel segmento non è ancora arrivato e può reagire prima dello scadere di RTO.

Un singolo ACK duplicato, però, non prova una perdita: anche un segmento semplicemente ritardato rispetto ai successivi crea la stessa osservazione. Il Fast Retransmit attende tre ACK duplicati, cioè quattro ACK complessivi con lo stesso AckN. A quel punto assume la perdita e ritrasmette immediatamente il segmento con SeqN = AckN.

Il segmento con SeqN=400 non arriva. I segmenti successivi producono ripetutamente AckN=400. Dopo il terzo duplicato la sorgente esegue Fast Retransmit di SeqN=400, senza attendere RTO.

Dato ricevutoRiscontroInterpretazione
SeqN=300AckN=400ACK nuovo
SeqN=500AckN=400primo duplicato
SeqN=600AckN=400secondo duplicato
SeqN=700AckN=400terzo duplicato: ritrasmetti 400

Il segmento con SeqN=400 è soltanto in ritardo. I primi dati fuori sequenza generano AckN=400, ma quando 400 arriva il riscontro avanza. Attendere tre duplicati riduce quindi il rischio di una ritrasmissione inutile per riordinamenti modesti.

Dato ricevutoRiscontroInterpretazione
SeqN=300AckN=400ACK nuovo
SeqN=500AckN=400primo duplicato
SeqN=600AckN=400secondo duplicato
SeqN=400AckN=700il buco si chiude

La soglia di tre è quindi un compromesso informativo: un duplicato segnala un disordine possibile, tre duplicati consecutivi rendono plausibile che abbastanza dati successivi abbiano superato un vero buco.

10. ACK ritardati e algoritmo di Nagle

Delayed ACK

La destinazione può inviare subito un ACK oppure ritardarlo per ridurre il numero di segmenti di conferma. L'attesa termina quando arriva un ulteriore pacchetto oppure quando si raggiunge una soglia, per esempio 200 ms. Normalmente viene generato un ACK ogni due segmenti. Il ritardo non può crescere liberamente, perché rischierebbe di far scadere RTO alla sorgente.

Sorgenti lente, tinygram e Nagle

Un'applicazione interattiva, come SSH, può consegnare al TCP pochi byte alla volta. Trasmetterli immediatamente produce tinygram: per pochi byte informativi servono almeno 40 byte di intestazioni IP+TCP e altri 40 byte per l'ACK. L'overhead per byte diventa enorme.

L'algoritmo di Nagle trasmette un nuovo segmento soltanto se vale almeno una delle condizioni seguenti:

Altrimenti aspetta l'ACK e aggrega nel frattempo i byte prodotti dall'applicazione. Insieme ai delayed ACK può emergere un effetto Stop-and-Wait: meno overhead ma più latenza. In una LAN gli ACK arrivano rapidamente e l'effetto si nota poco; in una WAN la latenza diventa percepibile. Le applicazioni interattive possono disabilitare Nagle con l'opzione socket TCP_NODELAY.

11. Il controllo di flusso del TCP

Il controllo di flusso TCP è un meccanismo a finestra scorrevole variabile, o credit based. La sorgente conosce il proprio buffer di trasmissione, ma non lo spazio disponibile nel buffer remoto; perciò la destinazione annuncia esplicitamente la Advertised Window, AW.

I due endpoint mantengono finestre con ruoli diversi:

FinestraDefinizione
WTinsieme dei segmenti inviabili dal trasmettitore senza nuove conferme
WRinsieme dei segmenti memorizzabili fuori sequenza dal ricevitore
Mspazio di numerazione; nel TCP M = 232

Per evitare conflitti nel riuso dei numeri di sequenza deve valere WT + WR ≤ M. Nel flusso a byte, AckN fissa il margine sinistro e AW il credito: il limite destro della finestra è AckN + AW. I byte già inviati ma non confermati sono inflight e consumano una parte del credito.

AW = 5 kB · MSS = 1 kB stato prima dell'ACK 12345 678910 111213 WT = AW confermatiinflightinviabilibloccati arriva AckN = 6 kB: la finestra scorre, non cambia ampiezza 12345 678910 111213 WT Ogni byte inflight riduce la Effective Window; ogni ACK cumulativo libera credito sul margine destro.
Tavola 11.4 — La finestra sul byte stream. I dati confermati restano a sinistra, gli inflight consumano credito e i dati oltre AckN + AW non sono ancora trasmissibili.

12. Gestione dei buffer di trasmissione e ricezione

La finestra annunciata collega direttamente i due buffer alle applicazioni. Alla sorgente gli indici devono rispettare:

LastByteAcked ≤ LastByteSent ≤ LastByteWritten
LastByteWritten − LastByteAcked ≤ MaxSendBuffer

Il primo vincolo separa dati confermati, dati già trasmessi e dati soltanto scritti dall'applicazione. Il secondo impedisce all'applicazione trasmittente di superare il buffer locale.

Alla destinazione valgono invece:

LastByteRead < NextByteExpected ≤ LastByteRcvd + 1
LastByteRcvd − LastByteRead ≤ MaxRcvBuffer

NextByteExpected < LastByteRcvd + 1  ⇒  segmenti fuori sequenza

Se LastByteRcvd è oltre il prossimo byte atteso, nel buffer esistono dati ricevuti dopo un buco. Lo spazio libero che la destinazione comunica è:

AW = MaxRcvBuffer − ((NextByteExpected − 1) − LastByteRead)

La sorgente deve rispettare il credito già occupato:

LastByteSent − LastByteAcked ≤ AW
EW = AW − (LastByteSent − LastByteAcked)

EW, la Effective Window, è il credito ancora spendibile subito. Se l'applicazione ricevente legge lentamente, AW si chiude; di conseguenza si chiude EW, il buffer di trasmissione si riempie e infine l'applicazione trasmittente viene rallentata. Il controllo di flusso propaga così la capacità del consumatore remoto fino al produttore locale.

Nota del redattore

AW protegge la destinazione; non descrive lo stato della rete. Nel capitolo 12 comparirà una seconda finestra, la congestion window, che protegge i router. Il TCP potrà inviare soltanto quanto consentito dal vincolo più stretto.

13. Deadlock, Persist Timer e window probe

Quando il buffer remoto si riempie, la destinazione invia AW = 0 e la sorgente sospende i dati. Se poi l'applicazione ricevente libera spazio ma non ha dati propri da spedire, l'unico annuncio di AW > 0 è un ACK di window update. Quell'ACK può perdersi e non viene ritrasmesso: la sorgente resta ferma perché crede la finestra chiusa, la destinazione attende dati perché la finestra è aperta. È un deadlock.

Il Persist Timer rende questo stato verificabile. Ricevuto un ACK con AckN = X e AW = 0, il trasmettitore avvia PT, per esempio usando RTO con back-off esponenziale. Alla scadenza invia una window probe di un byte con SeqN = X, ritrasmettendola se si perde.

Risposta alla sondaSignificato e azione
AckN = X+1, AW > 0il byte è stato ricevuto e c'è spazio: la trasmissione riprende normalmente
AckN = X, AW = 0il byte X non entra nel buffer: PT = 2 × PT e si attende di nuovo

14. Silly window syndrome e keepalive

Destinazione lenta: silly window syndrome

Una finestra che si riapre non è necessariamente una finestra utile. Se il buffer è pieno, l'applicazione legge un byte e il ricevitore annuncia AW = 1, la sorgente invia un byte e il buffer torna pieno. Ripetuto, il ciclo trasporta un byte per RTT indipendentemente dalla capacità della rete: è il silly window syndrome.

La soluzione lato ricevitore è non aumentare AW finché l'incremento non raggiunge almeno:

min(MSS, metà del buffer di ricezione)

In questo modo il credito non viene frammentato in annunci troppo piccoli. Nagle affronta un problema affine alla sorgente, aggregando scritture minute; la regola della finestra evita che sia la destinazione a sollecitare segmenti minuscoli.

Keepalive Timer

Una connessione TCP attiva può restare senza dati teoricamente all'infinito: è il caso di una sessione SSH lasciata inattiva. Molte implementazioni usano un Keepalive Timer per verificare che l'endpoint remoto sia ancora attivo e per mantenere lo stato nei nodi intermedi stateful, come NAT e firewall.

Allo scadere vengono inviati messaggi keepalive e relativi ACK. Questi messaggi non incrementano il numero di sequenza: verificano la vitalità della connessione senza avanzare il flusso dati.

Nota del redattore

Persist e keepalive non sono sinonimi. Persist risolve un possibile blocco del controllo di flusso mentre AW = 0; keepalive verifica una connessione inattiva e conserva lo stato lungo il percorso. Il capitolo 13 tornerà invece sui timer dal punto di vista delle prestazioni complessive.

Verifica le tue conoscenze

Perché un RTO statico non è adeguato al TCP?

Perché RTT è una variabile aleatoria la cui media e varianza dipendono dalle condizioni della rete. Un valore statico può essere troppo breve, causando ritrasmissioni inutili, oppure troppo lungo, ritardando il recupero delle perdite. RTO deve essere aggiornato dinamicamente in funzione delle misure.

Come funziona l'EWMA classica e quale ruolo ha α?

sRTTk = α sRTTk−1 + (1−α) RTTk. Con α raccomandato fra 0.8 e 0.9, un valore alto dà più memoria alla stima precedente e meno peso al campione nuovo. I pesi dei campioni passati decadono esponenzialmente.

Come calcola RTO il metodo classico e qual è il suo limite?

RTO = min(ubound, max(lbound, β sRTT)), con β fra 1.3 e 2.0, ubound = 1 min e lbound = 1 s. Un fattore fisso non stima la varianza: il metodo è accurato soltanto quando la variabilità del RTT è limitata.

Quali sono le formule di Jacobson e perché compare 4 RTTvar?

sRTTk = (1−α)sRTTk−1 + αRTTk; RTTvark = (1−β)RTTvark−1 + β|sRTTk−1−RTTk|; RTO = sRTT + max(G, 4 RTTvar). Il termine di deviazione allarga il margine quando RTT oscilla e lo restringe quando è stabile.

Come si inizializzano RTO, sRTT e RTTvar?

Prima della prima misura si usa RTO = 1 s. Dopo il primo campione: sRTT1 = RTT1 e RTTvar1 = RTT1/2. I parametri raccomandati sono α = 1/8, β = 1/4 e G pari alla granularità del clock.

Qual è l'ambiguità risolta dall'algoritmo di Karn?

Dopo una ritrasmissione, senza timestamp non si sa se l'ACK confermi l'originale o la copia. Karn evita di misurare quel RTT ambiguo e riprende il campionamento con il prossimo segmento confermato senza ritrasmissione.

Perché il back-off è esponenziale e quando viene ripristinato?

Una ritrasmissione suggerisce che il RTO corrente possa essere troppo breve. Il TCP lo raddoppia a ogni ulteriore ritrasmissione, fino al massimo, per evitare scadenze ripetute. Alla ricezione dell'ACK ripristina il valore di RTO.

Che cosa aggiunge SACK agli ACK cumulativi?

SACK, negoziato nelle opzioni di SYN e SYN+ACK, indica gli intervalli di numeri di sequenza ricevuti correttamente ma fuori sequenza. AckN continua a indicare il primo byte mancante; gli intervalli SACK evitano di ritrasmettere dati già presenti nel buffer remoto.

Che cosa significano gli ACK duplicati e perché Fast Retransmit ne aspetta tre?

Indicano che il primo byte identificato da AckN non è ancora arrivato mentre sono arrivati dati successivi. Anche un semplice riordinamento li può produrre; attendere tre duplicati riduce le ritrasmissioni inutili. Alla soglia si ritrasmette subito il segmento con SeqN = AckN.

Come funzionano i delayed ACK?

La destinazione ritarda l'ACK fino all'arrivo di un ulteriore pacchetto o fino a una soglia, per esempio 200 ms, allo scopo di ridurre il numero di ACK. Normalmente genera un ACK ogni due segmenti, senza ritardare tanto da rischiare la scadenza di RTO.

Che cos'è un tinygram e quali condizioni usa Nagle?

È un segmento con pochissimi dati e overhead elevato: almeno 40 byte IP+TCP più altri 40 per l'ACK. Nagle trasmette se i dati accumulati sono almeno MSS oppure se non ci sono ACK pendenti; altrimenti attende. TCP_NODELAY lo disabilita nelle applicazioni interattive sensibili alla latenza.

Qual è la differenza fra WT e WR?

WT è l'insieme dei segmenti inviabili senza nuove conferme; WR è l'insieme memorizzabile fuori sequenza dal ricevitore. Con spazio di numerazione M = 232 deve valere WT + WR ≤ M per evitare conflitti.

Quali invarianti descrivono i buffer di trasmissione e ricezione?

Trasmissione: LastByteAcked ≤ LastByteSent ≤ LastByteWritten. Ricezione: LastByteRead < NextByteExpected ≤ LastByteRcvd+1. Se NextByteExpected < LastByteRcvd+1, sono presenti segmenti fuori sequenza.

Come si calcolano AW ed EW?

AW = MaxRcvBuffer − ((NextByteExpected−1) − LastByteRead). La sorgente impone LastByteSent − LastByteAcked ≤ AW; il credito ancora utilizzabile è EW = AW − (LastByteSent − LastByteAcked).

Come nasce il deadlock con AW=0 e come lo risolve la window probe?

La sorgente è ferma e un window update con AW>0 può perdersi senza essere ritrasmesso. Il Persist Timer fa inviare una sonda di un byte con SeqN=X. La risposta comunica la finestra corrente; se resta zero, PT raddoppia e il tentativo verrà ripetuto.

Che cos'è il silly window syndrome e qual è la soluzione?

È il ciclo in cui una destinazione lenta libera e annuncia un solo byte, che viene subito inviato, ottenendo un throughput dell'ordine di un byte per RTT. Il ricevitore non deve aumentare AW finché l'incremento non è almeno min(MSS, metà del buffer di ricezione).

A che cosa serve il Keepalive Timer?

Serve a verificare un endpoint remoto durante connessioni inattive e a mantenere lo stato nei nodi intermedi stateful, come NAT e firewall. I messaggi keepalive e i relativi ACK non incrementano il numero di sequenza.