Sistemi e Reti - Anno 4 - Modulo 3 - Lezione 05 - TCP Affidabilità ed Error Recovery
Sistemi e Reti · Anno 4 · Modulo 3 · Lezione 05
✍ Autore: profgiagnotti · Materia: Sistemi e Reti

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.

// obiettivi di apprendimento
✓Spiegare come TCP garantisce la consegna ordinata e affidabile tramite numeri di sequenza e ACK cumulativi
✓Descrivere il meccanismo di stima dell'RTT (algoritmo di Jacobson/Karels) e il calcolo del timeout RTO
✓Comprendere il funzionamento di SACK (Selective Acknowledgment) e il vantaggio rispetto agli ACK cumulativi
✓Distinguere il ruolo degli ACK duplicati come segnale di perdita e il meccanismo di Fast Retransmit
✓Analizzare la gestione dei segmenti fuori ordine e l'applicazione dell'algoritmo di Karn per evitare ambiguità nelle ritrasmissioni

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.

📌 Definizione da ricordare

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.

01 · IP FAIL

Perdita

IP può scartare datagrammi per congestione o errori. TCP deve accorgersene.

02 · IP FAIL

Riordino e duplicazione

Percorsi diversi = ordine diverso. TCP rinumera tutto per ricostruire il flusso.

03 · TCP FIX

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.

TRACCIA · Flusso di byte e ACK
Mittente invia: Seg 1: seq=1001, payload="Hello" → 5 byte, occupa seq 1001-1005 Seg 2: seq=1006, payload=" World" → 6 byte, occupa seq 1006-1011 Ricevitore risponde: ACK=1006 (ho ricevuto fino a 1005, attendo 1006) ACK=1012 (ho ricevuto fino a 1011, attendo 1012) ACK è CUMULATIVO: ACK=N conferma tutti i byte < N.

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).

SEQ=1001 LEN=5 Hello [1001-1005] SEQ=1006 LEN=6 World [1006-1011] ACK=1012 Cumulativo OK ricevitore riordina per SEQ e consegna ordinato all'app Flusso ricostruito: 1001| H e l l o | W o r l d | → APP
🎯 Esempio in classe

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)

RFC 6298 · Formule RTT estimation
// Misura un campione RTT: SampleRTT = ACK_time - Send_time (solo se non ritrasmesso!) SRTT = (1-α)·SRTT + α·SampleRTT ; α tipico = 1/8 (smoothed RTT) RTTVAR = (1-β)·RTTVAR + β·|SRTT - SampleRTT| ; β tipico = 1/4 (variazione) RTO = SRTT + max(G, K·RTTVAR) ; K=4, G = clock granularity RTO = clamp(RTO, 1s, 60s) // limite inferiore 1s (RFC6298) – implementazioni moderne usano 200ms min // Exponential Backoff ad ogni ritrasmissione: RTO = RTO * 2 fino a max 60s
01 · SRTT

Media filtrata

EWMA con α=1/8 evita oscillazioni per un singolo campione anomalo.

02 · RTTVAR

Variazione

Stima quanto l'RTT è nervoso. Più nervoso → RTO più largo.

03 · RTO

Timeout sicuro

Sempre maggiore di SRTT: SRTT + 4×RTTVAR copre 99% delle variazioni.

💬 Tip del docente

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.

EventoCosa fa TCPPerché
ACK di segmento non ritrasmessoAggiorna SRTT e RTTVARCampione affidabile
ACK di segmento ritrasmessoNON aggiorna stime (Karn)Ambiguità temporale
Timeout → RitrasmissioneRaddoppia RTO (backoff)Rete forse congestionata
Timestamp optionPermette misura anche su rtxDisambigua 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.

📌 Definizione da ricordare

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.

Sequenza byte: 1000-2000 OK 2000-3000 PERSO 3000-4000 BUF 4000-5000 BUF Senza SACK: ACK=2000 → mittente ritrasmette 2000-5000 (3000 byte inutili) Con SACK: ACK=2000 + SACK=[3000-5000] → ritrasmette solo 2000-3000 (efficiente) Opzione TCP: Kind=5 Length variabile, fino a 3-4 blocchi (8 byte per blocco)

Attivazione: negoziata in fase di handshake con opzione SACK-Permitted (Kind=4) nei SYN. Se entrambi la supportano, poi si usa SACK (Kind=5).

TCP OPTION · SACK example
SYN → SACK-Permitted SYN-ACK → SACK-Permitted (entrambi accordano) ... perdita 2000-3000 ... Ricevitore → ACK=2000 ; SACK 3000-4000, 4000-5000 Mittente ritrasmette SOLO 2000-3000 RFC 2018 consente fino a 4 blocchi per opzione, 3 se con Timestamp.

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 duplicatiInterpretazioneAzione mittente
1–2Probabile riordinamento in reteAttendi
3Segnale forte di perditaFast Retransmit: ritrasmissione immediata senza attendere timeout
>3Ancora fuori ordineFast Recovery (L06/L07) + inflazione cwnd
🎯 Diagramma Fast Retransmit

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.

Mittente Ricevitore SEQ 1001 ACK 1006 SEQ 1006 PERSO SEQ 1011 (OOO) ACK 1006 DUP1 SEQ 1016 (OOO) ACK 1006 DUP2 ACK 1006 DUP3 → FAST RTX! RTX SEQ 1006
⚠️ Differenza RTO vs Fast Retransmit

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.

⚠️ Limite — dimensione del buffer

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.

MeccanismoCosa garantisceQuando scatta
Sequenza + ACK cumulativoOrdine e rilevazione buchiSempre
RTO + Jacobson/KarelsRecupero da perdita totaleNessun ACK entro RTO
Karn + TimestampStima RTT correttaRitrasmissioni
SACKRitrasmissione selettivaHole + blocchi bufferizzati
Fast Retransmit 3 DUPACKRecupero rapido3 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:

  1. Identifica una serie di 3 ACK duplicati e il conseguente Fast Retransmit. Qual è il Sequence Number ritrasmesso?
  2. Calcola SampleRTT da due segmenti non ritrasmessi usando Timestamp TSval/TSecr. Applica formula SRTT con α=1/8.
  3. Cerca l'opzione SACK in un ACK: quanti blocchi SACK segnala? Quale buco sta indicando?
  4. Perché Karn vieta di usare un ACK di ritrasmissione per aggiornare SRTT? Fai un esempio con ambiguità temporale.
  5. Simula: rwnd=4096 byte, arrivano 2 segmenti da 1460 fuori ordine. Quanti byte restano liberi? Cosa succede al terzo segmento OOO da 1460?
✅ Soluzione ragionata

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.

✓Numeri di sequenza: ogni byte è numerato — il ricevitore riordina i segmenti fuori ordine e consegna ordinato all'app
✓ACK cumulativo: ACK=N indica prossimo byte atteso, conferma implicitamente tutti i <N – semplice ma non selettivo
✓RTO = SRTT + 4×RTTVAR, clamp 1s-60s, Jacobson/Karels, backoff esponenziale ad ogni timeout
✓Karn: non aggiornare SRTT con campioni da segmenti ritrasmessi – timestamp opzione risolve ambiguità
✓SACK (RFC 2018): ricevitore segnala blocchi non contigui – mittente ritrasmette solo buchi, non tutto da ACK
✓Fast Retransmit: 3 ACK duplicati = perdita quasi certa → RTX immediata senza attendere RTO, poi Fast Recovery

📚 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