Sei sulla pagina 1di 34

Lezione 7

Il trasporto affidabile
Corso di Reti di calcolatori
Prof. Antonio Puliafito
apuliafito@unime.it
Versioni di protocolli per il
trasferimento affidabile
Analizzeremo i seguenti casi, che portano a differenti
soluzioni:
• Caso ideale
• Caso con errore nel canale (meccanismi di ACK e
NACK): RDT 2.0
• Aggiunta di un numero di sequenza: RDT 2.1
• Segnalazione solo con ACK e numero di sequenza:
RDT 2.2
• Utilizzo di timeout per la trasmissione (caso di
canale con perdite): RDT 3.0
Principi del trasferimento dati affidabile
 Importante nei livelli di applicazione, trasporto e collegamento
 Tra i dieci problemi più importanti del networking!

 Le caratteristiche del canale inaffidabile determinano la complessità


del protocollo di trasferimento dati affidabile (Reliable Data Transfer
o RDT a differenza di Unreliable Data Transfer o UDT ).
3-3
Trasferimento dati affidabile: preparazione
rdt_send(): chiamata dall’alto, (ad
deliver_data(): chiamata
es. dall’applicazione). Trasferisce i dati
da rdt per consegnare i dati al
da consegnare al livello superiore del
livello superiore
ricevente

lato lato
invio ricezione

udt_send(): chiamata da rdt rdt_rcv(): chiamata quando il


per trasferire il pacchetto al pacchetto arriva nel lato ricezione del
ricevente tramite il canale canale
inaffidabile
3-4
Trasferimento dati affidabile: preparazione
 Svilupperemo progressivamente i lati d’invio e di ricezione di un
protocollo di trasferimento dati affidabile (RDT)
 Considereremo soltanto i trasferimenti dati unidirezionali, ma le
informazioni di controllo fluiranno in entrambe le direzioni!
 Utilizzeremo automi a stati finiti per specificare il mittente e il ricevente

evento che causa la transizione di stato


stato: lo stato successivo a azioni svolte nella transizione
questo è determinato
unicamente dall’evento stato stato
successivo 1 evento
2
azioni

3-5
Rdt1.0: trasferimento affidabile su canale affidabile (caso ideale)
 Canale sottostante perfettamente affidabile
 Nessun errore nei bit
 Nessuna perdita di pacchetti
 Automa distinto per il mittente e per il ricevente:
 il mittente invia i dati nel canale sottostante
 il ricevente legge i dati dal canale sottostante

Attesa di rdt_send(data) Attesa di rdt_rcv(packet)


chiamata chiamata extract (packet,data)
packet = dal basso
dall’alto deliver_data(data)
make_pkt(data)
udt_send(packet)
mittente ricevente

3-6
Rdt2.0: canale con errori nei bit
 Il canale sottostante potrebbe confondere i bit nei pacchetti
 checksum per rilevare gli errori nei bit
 domanda: come correggere gli errori:
 notifica positiva (ACK): il ricevente comunica espressamente al mittente che
il pacchetto ricevuto è corretto
 notifica negativa (NAK): il ricevente comunica espressamente al mittente
che il pacchetto contiene errori
 il mittente ritrasmette il pacchetto se riceve un NAK
 nuovi meccanismi in rdt2.0 (oltre a rdt1.0):
 rilevamento di errore
 feedback del destinatario: messaggi di controllo (ACK, NAK)
ricevente->mittente

Questo modello non considera le perdite totali di pacchetti, ma


solo errori nei bit che lo compongono
3-7
rdt2.0: specifica dell’automa
ricevente

mittente

3-8
rdt2.0: operazione senza errori

3-9
rdt2.0: scenario di errore

3-10
rdt2.0 ha un difetto fatale!
Che cosa accade se i pacchetti Gestione dei duplicati:
ACK/NAK sono danneggiati? soluzione
 Il mittente non sa che cosa sia  Il mittente ritrasmette il
accaduto al destinatario! Due pacchetto corrente se ACK/NAK
possibili reazioni: è alterato
• Ritrasmettere il pacchetto:  Il mittente aggiunge un numero
possibili duplicati, nel caso di sequenza
a ogni pacchetto
fosse stato inviato un ACK
 Il ricevente può scartare il
• Trasmettere il prossimo pacchetto duplicato grazie al
pacchetto: perdita di quello numero di sequenza
precedente nel caso fosse
stato inviato un NACK
Consideriamo caso stop and wait
Il mittente invia un pacchetto, poi aspetta la risposta del
destinatario. Quindi bastano due soli numeri di sequenza (0 e 1) 3-11
rdt2.1: il mittente gestisce gli ACK/NAK alterati
rdt_send(data)
sndpkt = make_pkt(0, data, checksum)
udt_send(sndpkt)
rdt_rcv(rcvpkt) &&
( corrupt(rcvpkt) ||
Attesa di
Attesa di ACK o NAK
isNAK(rcvpkt) )
chiamata 0 0
rdt_rcv(rcvpkt) dal basso udt_send(sndpkt)
&&
notcorrupt(rcvpkt) rdt_rcv(rcvpkt)
&& isACK(rcvpkt) && notcorrupt(rcvpkt)
&& isACK(rcvpkt)
Λ
Attesa di Attesa di
Λ
ACK o chiamata 1
rdt_rcv(rcvpkt) && NAK 1 dall’alto
( corrupt(rcvpkt) ||
rdt_send(data)
isNAK(rcvpkt) )
sndpkt = make_pkt(1, data, checksum)
udt_send(sndpk udt_send(sndpkt)
t)
3-12
rdt2.1: il ricevente gestisce gli ACK/NAK alterati
rdt_rcv(rcvpkt) && notcorrupt(rcvpkt)
&& has_seq0(rcvpkt)
extract(rcvpkt,data)
deliver_data(data)
sndpkt = make_pkt(ACK, chksum)
udt_send(sndpkt)
rdt_rcv(rcvpkt) && (corrupt(rcvpkt) rdt_rcv(rcvpkt) && (corrupt(rcvpkt)
sndpkt = make_pkt(NAK, chksum) sndpkt = make_pkt(NAK, chksum)
udt_send(sndpkt) udt_send(sndpkt)
Attesa di Attesa di
0 dal 1 dal
rdt_rcv(rcvpkt) && basso rdt_rcv(rcvpkt) &&
basso
not corrupt(rcvpkt) && not corrupt(rcvpkt) &&
has_seq1(rcvpkt) has_seq0(rcvpkt)
sndpkt = make_pkt(ACK, chksum) sndpkt = make_pkt(ACK, chksum)
udt_send(sndpkt) udt_send(sndpkt)
rdt_rcv(rcvpkt) && notcorrupt(rcvpkt)
&& has_seq1(rcvpkt)
extract(rcvpkt,data)
deliver_data(data)
sndpkt = make_pkt(ACK, chksum)
udt_send(sndpkt)

3-13
rdt2.1: sommario
Mittente: Ricevente:
 Aggiunge il numero di sequenza  Deve controllare se il pacchetto
al pacchetto ricevuto è duplicato
 Saranno sufficienti due numeri  lo stato indica se il numero di
di sequenza (0,1). sequenza previsto è 0 o 1
 Deve controllare se gli ACK/NAK  nota: il ricevente non può
sono danneggiati sapere se il suo ultimo
ACK/NAK è stato ricevuto
 Il doppio di stati
correttamente dal mittente:
 lo stato deve “ricordarsi” se il
non esiste un riscontro per i
pacchetto “corrente” ha
numero di sequenza 0 o 1 pacchetti ACK/NAK

3-14
rdt2.2: un protocollo senza NAK
 Stessa funzionalità di rdt2.1, utilizzando soltanto gli ACK
 Al posto del NAK, il destinatario invia un ACK per l’ultimo
pacchetto ricevuto correttamente
 il destinatario deve includere esplicitamente il numero
di sequenza del pacchetto con l’ACK
 Un ACK duplicato presso il mittente determina
la stessa azione del NAK: ritrasmettere
il pacchetto corrente

Ci stiamo avvicinando al comportamento del TCP

3-15
rdt2.2: frammenti del mittente
e del ricevente
rdt_send(data)
sndpkt = make_pkt(0, data, checksum)
udt_send(sndpkt) rdt_rcv(rcvpkt) &&
( corrupt(rcvpkt) ||
Attesa di Attesa di isACK(rcvpkt,1) )
chiamata 0 ACK 0
dall’alto udt_send(sndpkt)
Frammento
del mittente rdt_rcv(rcvpkt)
&& notcorrupt(rcvpkt)
rdt_rcv(rcvpkt) && && isACK(rcvpkt,0)
(corrupt(rcvpkt) || Λ
has_seq1(rcvpkt)) Attesa Frammento
di 0 dal
basso del ricevente
udt_send(sndpkt)
rdt_rcv(rcvpkt) && notcorrupt(rcvpkt)
&& has_seq1(rcvpkt)
extract(rcvpkt,data)
deliver_data(data)
sndpkt = make_pkt(ACK1, chksum) 3-16
udt_send(sndpkt)
rdt3.0: canali con errori e perdite

Nuova ipotesi: il canale Soluzione: il mittente attende un ACK


per un tempo “ragionevole”
sottostante può anche (timeout)
smarrire i pacchetti (dati o  ritrasmette se non riceve un ACK in questo
periodo
ACK)
 se il pacchetto (o l’ACK) è soltanto in
 checksum, numero di ritardo (non perso):
sequenza, ACK e  la ritrasmissione sarà duplicata, ma
l’uso dei numeri di sequenza gestisce
ritrasmissioni aiuteranno, ma già questo
non saranno sufficienti  il destinatario deve specificare il
numero di sequenza del pacchetto da
riscontrare
 occorre un contatore (countdown timer
per il timeout)

3-17
rdt3.0 mittente
rdt_send(data)
rdt_rcv(rcvpkt) &&
sndpkt = make_pkt(0, data, checksum) ( corrupt(rcvpkt) ||
udt_send(sndpkt) isACK(rcvpkt,1) )
rdt_rcv(rcvpkt) start_timer
Λ
Λ Attesa di Attesa
timeout
chiamata 0 di
ACK 0 udt_send(sndpkt)
dall’alto start_timer
rdt_rcv(rcvpkt)
&& notcorrupt(rcvpkt) rdt_rcv(rcvpkt)
&& isACK(rcvpkt,1) && notcorrupt(rcvpkt)
stop_timer && isACK(rcvpkt,0)
stop_timer
Attesa Attesa di
timeout di chiamata 1
udt_send(sndpkt) ACK 1 dall’alto
start_timer rdt_rcv(rcvpkt)
rdt_send(data) Λ
rdt_rcv(rcvpkt) &&
( corrupt(rcvpkt) || sndpkt = make_pkt(1, data, checksum)
isACK(rcvpkt,0) ) udt_send(sndpkt)
start_timer
Λ

3-18
rdt3.0 in azione (Stop & Wait)
Mittente Ricevente
Mittente Ricevente

(perdita)

a) Operazioni senza perdite

b) Perdita di pacchetto

3-19
rdt3.0 in azione (Stop & Wait)
Mittente Ricevente Mittente Ricevente

(perdita) X

c) Perdita di ACK d) Timeout prematuro

3-20
Prestazioni di rdt3.0 Stop & Wait (1/2)
 rdt3.0 funziona, ma le prestazioni non sono soddisfacenti
 esempio: collegamento da 1 Gbps, ritardo di propagazione 15 ms, pacchetti
da 1 KB:

L (lunghezza del pacchetto in bit) 8 kb/pacc


T trasm = = = 8 microsec
R (tasso trasmissivo, bps) 109 b/sec

U L/R 0,008
mitt = =
30,008
= 0,00027
RTT + L / R

 Umitt : utilizzo è la frazione di tempo in cui il mittente è occupato


nell’invio di bit
 Un pacchetto da 1 KB ogni 30 msec -> throughput di 33 kB/sec in un
collegamento da 1 Gbps
 Il protocollo di rete limita l’uso delle risorse fisiche!
3-21
Prestazioni di rdt3.0 Stop & Wait (2/2)

Mittente Ricevente
Primo bit del pacchetto trasmesso, t = 0
Ultimo bit del
pacchetto trasmesso, t = L / R

Arriva il primo bit


RTT Arriva l’ultimo bit, invia ACK

Arriva ACK, invia il prossimo


pacchetto, t = RTT + L / R

U L/R 0,008
mitt = =
30,008
= 0,00027
RTT + L / R
RTT è un tempo morto perché non si inviano pacchetti (Stop & Wait) 3-22
Protocolli con pipeline
Pipelining: il mittente ammette più pacchetti in transito,
ancora da riscontrare
 l’intervallo dei numeri di sequenza deve essere incrementato, non
bastano semplicemente 0 e 1
 buffering dei pacchetti presso il mittente e/o ricevente

• Esistono due forme di protocolli con pipeline:


Go-Back-N e ripetizione selettiva
3-23
Pipelining: aumento dell’utilizzo
Primo bit del primo
Mittente Ricevente
pacchetto trasmesso, t = 0
Ultimo bit del primo
pacchetto trasmesso, t = L / R
Arriva il primo bit del primo pacchetto
Arriva l’ultimo bit del primo pacchetto,
RTT invia ACK
Arriva l’ultimo bit del secondo pacchetto,
invia ACK
Arriva ACK, invia il prossimo Arriva l’ultimo bit del terzo pacchetto,
pacchetto, t = RTT + L / R invia ACK

Inviando 3 pacchetti
durante l’RTT abbiamo
un aumento dell’utilizzo
3* L/R 0,024 di un fattore 3!
U mitt = = = 0,0008
RTT + L / R 30,008

3-24
Protocolli con pipeline
Go-back-N: Ripetizione selettiva
 Il mittente può avere fino a N  Il mittente può avere fino a N
pacchetti senza ACK in pipeline pacchetti senza ACK in pipeline
 Il ricevente invia solo ACK  Il ricevente dà l’ACK per ogni
cumulativi pacchetto
 Non dà l’ACK di un pacchetto  Il mittente mantiene un timer
se c’è un gap (una sequenza di per ciascun pacchetto che non
arrivo: 1,2,3,5 non provoca ha ancora ricevuto ACK
riscontro del 5, ma del 3)
 Quando il timer scade,
 Il mittente mantiene un timer ritrasmette solo il pacchetto
per ciascun pacchetto che non che non ha avuto ACK,
ha ancora ricevuto ACK facendo ripartire il timer di
 Se il timer scade, ritrasmette quel singolo pacchetto
tutti i pacchetti senza ACK (nel
caso precedente manderebbe
il 4 e il 5), facendo ripartire i
relativi timer
3-25
Go-Back-N (GBN)
 Mittente:
 Numero di sequenza nell’intestazione del pacchetto
 “Finestra” contenente fino a N pacchetti consecutivi non riscontrati

 ACK(n): riscontro di tutti i pacchetti con numero di sequenza minore o uguale a n -


“riscontri cumulativi”
 pacchetti duplicati sono scartati (vedere il ricevente)
 timer per ogni pacchetto in transito
 timeout(n): ritrasmette il pacchetto n e tutti i pacchetti con i numeri di sequenza più
grandi nella finestra

3-26
GBN: automa esteso del mittente
rdt_send(data)
if (nextseqnum < base+N) {
sndpkt[nextseqnum] = make_pkt(nextseqnum,data,chksum)
udt_send(sndpkt[nextseqnum])
if (base == nextseqnum)
start_timer
nextseqnum++
}
Λ else
refuse_data(data)
base=1
nextseqnum=1
timeout
start_timer
Attesa udt_send(sndpkt[base])
rdt_rcv(rcvpkt) udt_send(sndpkt[base+1])
&& corrupt(rcvpkt) …
udt_send(sndpkt[nextseqnum-1])
rdt_rcv(rcvpkt) &&
notcorrupt(rcvpkt)
base = getacknum(rcvpkt)+1
If (base == nextseqnum)
stop_timer
else
start_timer 3-27
GBN: automa esteso del ricevente
default
udt_send(sndpkt) rdt_rcv(rcvpkt)
&& notcurrupt(rcvpkt)
Λ && hasseqnum(rcvpkt,expectedseqnum)
expectedseqnum=1 Attesa extract(rcvpkt,data)
sndpkt = deliver_data(data)
make_pkt(expectedseqnum,ACK,chksum) sndpkt = make_pkt(expectedseqnum,ACK,chksum)
udt_send(sndpkt)
expectedseqnum++
ACK-soltanto: invia sempre un ACK per un pacchetto ricevuto correttamente
e in sequenza
 potrebbe generare ACK duplicati (arrivi di pacchetti fuori sequenza es.
1,2,3,5, riscontra due volte il 3)
 deve memorizzare soltanto expectedseqnum (il numero di
sequenza che si aspetta)
 Pacchetto fuori sequenza:
 scartato (non è salvato) -> senza buffering del ricevente! Infatti il mittente
invierà di nuovo i pacchetti fuori sequenza (nel es. precedente il 4 e il 5)
3-28
GBN in
azione

Invia i pacchetti
2,3,4,5 anche se
l’unico non arrivato
era il 2
3-29
Ripetizione selettiva

 Il ricevente invia riscontri specifici per tutti i pacchetti


ricevuti correttamente
 buffer dei pacchetti, se necessario, per eventuali consegne in
sequenza al livello superiore
 Il mittente ritrasmette soltanto i pacchetti per i quali
non ha ricevuto un ACK
Come il GBN mantiene una:
 Finestra del mittente
 N numeri di sequenza consecutivi
 limita ancora i numeri di sequenza dei pacchetti inviati non
riscontrati

3-30
Ripetizione selettiva: finestre del mittente e del
ricevente

3-31
Ripetizione selettiva: sommario
Mittente Ricevente
Dati dall’alto (applicazione): Pacchetto n in [rcvbase, rcvbase+(N-
 Se nella finestra è disponibile il 1)]
successivo numero di sequenza, invia  Invia ACK(n)
il pacchetto  Se n fuori sequenza: bufferizza il pacchetto
Timeout(n): senza inviarlo all’applicazione
 Ritrasmette il pacchetto n, riparte il Altrimenti
relativo timer n in sequenza: consegna all’applicazione
(vengono consegnati anche i pacchetti
ACK(n) in [sendbase,sendbase+(N-1)] bufferizzati in sequenza); la finestra avanza
(intera finestra):
al successivo pacchetto non ancora ricevuto
 Marca il pacchetto n come ricevuto
 Se n è il numero di sequenza più Pacchetto n in [rcvbase-N, rcvbase-1]
piccolo, la base della finestra avanza  ACK(n): pacchetto duplicato a causa di
al successivo numero di sequenza del perdita dell’ACK; da riscontrare
pacchetto non riscontrato
altrimenti:
 Ignora: situazione che non dovrebbe
accadere mai

3-32
Ripetizione selettiva in azione

La finestra non scorre finché non


arriva il pacchetto 2 (si completa
la sequenza)

3-33
Ripetizione selettiva:
dilemma
Esempio:
 Numeri di sequenza: 0, 1, 2, 3
 Dimensione della finestra = 3

 Il ricevente non vede alcuna


differenza fra i due scenari!
 Passa erroneamente i dati duplicati
come nuovi: infatti nel caso (a) il
pacchetto 0 ricevuto è quello vecchio,
mentre nel caso (b) è quello nuovo
Lo spazio dei numeri di sequenza è
troppo piccolo o equivalentemente la
finestra è troppo grande e causa
questa ambiguità
D: Qual è la relazione fra lo spazio dei
numeri di sequenza e la dimensione
della finestra?
R: La finestra deve avere dimensione
inferiore o uguale alla meta’ dello
3-34
spazio dei numeri di sequenza