TCP: Affidabilità, Error Recovery e Gestione delle Perdite
Come TCP trasforma un servizio IP inaffidabile in un flusso affidabile, ordinato e senza duplicati: numeri di sequenza, ACK cumulativi, stima RTT, RTO, Karn, SACK e Fast Retransmit.
1. Il problema dell'affidabilità su rete IP
IP è un protocollo best-effort: consegna i pacchetti nel modo migliore possibile ma non garantisce nulla. I datagrammi possono andare persi, duplicati, riordinati, corrotti. TCP costruisce un servizio affidabile sopra IP attraverso tre meccanismi fondamentali: numerazione dei byte, acknowledgment e ritrasmissione.
TCP garantisce che il flusso di byte venga consegnato all'applicazione ricevente completamente, in ordine e senza duplicati, indipendentemente dai guasti della rete sottostante, tramite numeri di sequenza, ACK cumulativi e ritrasmissione controllata dal timeout.
Perdita
IP può scartare datagrammi per congestione o errori. TCP deve accorgersene.
Riordino e duplicazione
Percorsi diversi = ordine diverso. TCP rinumera tutto per ricostruire il flusso.
ACK + RTO + SACK
Riconoscimenti, timeout adattivo e ack selettivi per ritrasmettere solo ciò che manca.
2. Numerazione dei byte e ACK cumulativo
TCP tratta i dati come un flusso continuo di byte. Ogni byte ha un numero di sequenza. Il campo Sequence Number nell'header indica il numero del primo byte del payload trasportato in quel segmento.
L'ACK è cumulativo: il valore indica il numero del prossimo byte atteso, quindi implicitamente conferma la ricezione di tutti i byte precedenti. Questo semplifica la gestione ma ha un limite: se arriva il segmento 3 prima del 2, il ricevitore non può riscontrare il 3 senza prima riscontrare il 2 (SACK risolve questo problema).
Wireshark: seq e ack relativi. Se catturi l'handsake, Wireshark mostra Relative Sequence Numbers (0,5,11...) per leggibilità. Clicca su TCP → disattiva relative per vedere i valori reali 1001-style.
3. Timeout e ritrasmissione — stima dell'RTT
Se un ACK non arriva entro il RTO (Retransmission TimeOut), il mittente ritrasmette il segmento. Il timeout non può essere fisso: una rete WAN ha RTT molto diverso da una LAN locale. TCP deve stimare dinamicamente l'RTT.
Algoritmo di Jacobson/Karels (RFC 6298)
Media filtrata
EWMA con α=1/8 evita oscillazioni per un singolo campione anomalo.
Variazione
Stima quanto l'RTT è nervoso. Più nervoso → RTO più largo.
Timeout sicuro
Sempre maggiore di SRTT: SRTT + 4×RTTVAR copre 99% delle variazioni.
All'interrogazione: RTO NON è uguale a RTT. È una stima cauta: SRTT+4*RTTVAR con backoff esponenziale. Se ti chiedono perché non usare RTT fisso, rispondi: LAN 1ms vs satellite 600ms – impossibile un valore unico.
Algoritmo di Karn — l'ambiguità delle ritrasmissioni
Se un segmento viene ritrasmesso, quando arriva l'ACK, a quale invio si riferisce? Al primo o al secondo? Non puoi saperlo. Karn (1987): non aggiornare SRTT/RTTVAR con campioni provenienti da segmenti ritrasmessi. Usa solo ACK di segmenti trasmessi una sola volta. Usa timestamp TCP (opzione) per disambiguare.
| Evento | Cosa fa TCP | Perché |
|---|---|---|
| ACK di segmento non ritrasmesso | Aggiorna SRTT e RTTVAR | Campione affidabile |
| ACK di segmento ritrasmesso | NON aggiorna stime (Karn) | Ambiguità temporale |
| Timeout → Ritrasmissione | Raddoppia RTO (backoff) | Rete forse congestionata |
| Timestamp option | Permette misura anche su rtx | Disambigua con TSval/TSecr |
4. SACK — Selective Acknowledgment (RFC 2018)
L'ACK cumulativo ha un difetto: dice solo "mi manca N", ma non dice quali blocchi successivi sono già arrivati. Senza SACK, il mittente deve ritrasmettere tutto da N in poi, anche se alcuni pezzi erano già nel buffer del ricevitore.
SACK permette al ricevitore di segnalare blocchi non contigui già ricevuti (es. 3000-4000 e 5000-6000) così il mittente ritrasmette solo il buco 4000-5000, non tutto.
Attivazione: negoziata in fase di handshake con opzione SACK-Permitted (Kind=4) nei SYN. Se entrambi la supportano, poi si usa SACK (Kind=5).
5. ACK duplicati e Fast Retransmit
Se il ricevitore riceve un segmento fuori ordine (es. il 5 arriva ma mancava il 3), continua a mandare ACK=3. Il mittente riceve così più ACK con lo stesso valore: ACK duplicati.
| N° di ACK duplicati | Interpretazione | Azione mittente |
|---|---|---|
| 1–2 | Probabile riordinamento in rete | Attendi |
| 3 | Segnale forte di perdita | Fast Retransmit: ritrasmissione immediata senza attendere timeout |
| >3 | Ancora fuori ordine | Fast Recovery (L06/L07) + inflazione cwnd |
Mittente invia 1001,1006,1011,1016. 1006 perso. Ricevitore riceve 1001 → ACK 1006. Riceve 1011 (fuori ordine) → ACK 1006 dup #1. Riceve 1016 → ACK 1006 dup #2. Ricevitore riceve altro → ACK 1006 dup #3 → Mittente ritrasmette subito 1006.
Il timeout RTO segnala una perdita grave (nessun segnale dalla rete). Il Fast Retransmit (3 ACK duplicati) segnala una perdita lieve (la rete funziona, ma un segmento è andato perso). La risposta è diversa: il timeout porta TCP in Slow Start, il Fast Retransmit attiva Fast Recovery (più aggressivo). Vedi L07 controllo congestione.
6. Gestione dei segmenti fuori ordine e buffer di ricezione
I segmenti che arrivano fuori ordine vengono bufferizzati dal ricevitore (non scartati). Quando il segmento mancante arriva, il ricevitore ricompone il flusso in ordine e invia un ACK cumulativo che riscontra tutti i byte ricevuti in sequenza.
La capacità di bufferizzare segmenti fuori ordine dipende dalla receive window (rwnd) del ricevitore. Se il buffer è pieno, i segmenti fuori ordine vengono scartati — questo porta a ulteriori ritrasmissioni. Il dimensionamento del buffer TCP è un parametro critico per le performance in reti ad alta latenza (es. satellitari). Window Scaling (L04) aiuta.
| Meccanismo | Cosa garantisce | Quando scatta |
|---|---|---|
| Sequenza + ACK cumulativo | Ordine e rilevazione buchi | Sempre |
| RTO + Jacobson/Karels | Recupero da perdita totale | Nessun ACK entro RTO |
| Karn + Timestamp | Stima RTT corretta | Ritrasmissioni |
| SACK | Ritrasmissione selettiva | Hole + blocchi bufferizzati |
| Fast Retransmit 3 DUPACK | Recupero rapido | 3 ACK duplicati |
7. Verifica / Esercizio pratico con Wireshark
🔬 Attività — Analizza una cattura TCP
Scarica una cattura filtrata tcp.analysis.flags oppure genera perdita con tc netem in laboratorio. Osserva:
- Identifica una serie di 3 ACK duplicati e il conseguente Fast Retransmit. Qual è il Sequence Number ritrasmesso?
- Calcola SampleRTT da due segmenti non ritrasmessi usando Timestamp TSval/TSecr. Applica formula SRTT con α=1/8.
- Cerca l'opzione SACK in un ACK: quanti blocchi SACK segnala? Quale buco sta indicando?
- Perché Karn vieta di usare un ACK di ritrasmissione per aggiornare SRTT? Fai un esempio con ambiguità temporale.
- Simula: rwnd=4096 byte, arrivano 2 segmenti da 1460 fuori ordine. Quanti byte restano liberi? Cosa succede al terzo segmento OOO da 1460?
1: DUPACK stesso ACK number (es. 1006) ripetuto. RTX ha stesso SEQ del buco. Wireshark lo marca [TCP Fast Retransmission].
2: SampleRTT = T_ack - T_send. SRTT_new = 0.875*SRTT_old + 0.125*Sample. Es: SRTT_old 100ms, Sample 120ms → SRTT_new=102.5ms.
3: Opzione Kind 5, vedi TCP Option - SACK 3000-4000 – buco tra ACK cumulativo e primo bordo SACK.
4: Se RTT originale 100ms e ritrasmissione dopo 500ms, ACK dopo 600ms: non sai se RTT è 600ms o 100ms della rtx. Stima falsata → RTO sbagliato.
5: 2×1460=2920 occupati. Restano 1176. Terzo OOO 1460 non entra → scartato, anche se utile. Serve Window Scaling o aumentare SO_RCVBUF.
8. Riepilogo e concetti chiave
📚 Prossimo passo — TCP Controllo del flusso
Dopo aver visto come TCP recupera gli errori end-to-end, vediamo in dettaglio come avviene il controllo del flusso di dati