Il livello Trasporto.

Bibliografia:
Computer Networking. Cap. 3. Autori: James F. Kurose (University of Massachusetts, Amherst) Keith W. Ross (Polytechnic Institute of NYU).

Principi di un trasferimento affidabile

Il problema dell'affidabilità riguarda il livello Trasporto, il livello Collegamento e il livello Applicazione.

      

L'astrazione fornita alle entità dei livelli superiori è quella di un canale affidabile attraverso il quale possono essere trasferiti i dati. Su un canale affidabile i bit dei dati non vengono alterati o perduti, e vengono consegnati nell'ordine in cui sono partiti. Questo è esattamente il modello di servizio offerto dal TCP alle applicazioni Internet.

      

È compito di un protocollo di trasferimento affidabile realizzare il servizio astratto descritto. Il compito è particolarmente difficile perchè il livello rete sottostante non è affidabile. Ad esempio, il TCP è un protocollo di trasferimento dati affidabile che è implementato sul livello rete (IP) che non è affidabile. Il livello rete, su cui si appoggia il protocollo di trasporto, potrebbe essere costituito da un unico canale o da una rete.

In questa sezione si svilupperà il lato mittente e il lato ricevitore di un protocollo di trasferimento affidabile, perfezionando sempre di più il modello del canale sottostante. Dapprima, si ipotizza che il canale sottostante può modificare i bit o perdere un intero pacchetto. Si assume che i pacchetti vengano consegnati nell'ordine in cui partono, nonostante qualcuno possa essere perso. In altri termini, il canale non riordina i pacchetti.

La figura illustra le interfacce del protocollo di trasferimento dei dati.

Il trasmettitore crea un oggetto send:

PrintWriter send = new PrintWriter(socket.getOutputStream(), true);

Il ricevitore crea un oggetto rcv:

BufferedReader rcv = new BufferedReader(new InputStreamReader(socket.getInputStream()));

Il livello applicazione del trasmettitore usa l'oggetto send per inviare i dati:

send.println("Hello.");

Il livello applicazione del ricevitore usa l'oggetto rcv per prelevare i dati:

String dati = rcv.readLine();

In un modello di comunicazione, dal lato del mittente, il servizio di trasferimento verrà richiamato con la funzione send.println(), passando come parametro i dati che dovranno essere consegnati al livello applicazione del ricevitore. Al lato del ricevitore, quando giunge un pacchetto, verrà richiamata la funzione rcv(). Quando il protocollo deve consegnare i dati al livello superiore richiamerà la funzione deliver_data().

Oltre a scambiare pacchetti di dati, il ricevitore e il trasmettitore si scambiano pacchetti di controllo.

Costruzione di un protocollo di trasferimento affidabile su un canale affidabile

Versione 1

Si consideri dapprima il caso del canale perfettamente affidabile. Il comportamento del trasmettitore e del ricevitore può essere descritto da una macchina a stati finiti.

Trasmettitore:
Lo stato X del trasmettitore è "attesa di fornire il servizio alle applicazioni",
l'input I che può ricevere in questo stato, e che lo riporta nello stesso stato, è "Send(dati)",
l'output U emesso durante la transizione di stato è un pacchetto da consegnare al livello rete.

Ricevitore
Lo stato X del ricevitore è "attesa di ricevere un pacchetto dal livello Rete",
l'input I che può ricevere in questo stato, e che lo riporta nello stesso stato, è "rcv(dati)",
l'output U emesso durante la transizione di stato è un messagggio da consegnare al livello applicazione.

Dal lato del mittente, quando si verifica l'evento send(data), il protocollo accetta dati dal livello superiore, mette i dati in un pacchetto tramite l'azione make_pkt(packet, data) e invia il pacchetto sul canale.

Dal lato del ricevitore, il protocollo acquisisce un pacchetto dal canale sottostante, tramite il gestore dell'evento rcv(packet), estrae i dati dal pacchetto tramite l'azione extract(packet, data) e consegna i dati al livello superiore.

Su un canale perfettamente affidabile non è richiesto che il ricevitore confermi la ricezione corretta di un pacchetto, perchè nessun pacchetto viene perso o modificato. Inoltre il ricevitore è in grado di acquisire pacchetti alla stessa velocità con cui vengono generati dal trasmettitore. In questo modello, il ricevitore non ha bisogno di chiedere al trasmettitore di ridurre la velocità.

Trasferimento affidabile su un canale con rumore.

Versione 2

Un modello più realistico del canale utilizzato dalle applicazioni ammette che alcuni bit nel pacchetto possano subire delle modifiche. Questi errori possono avvenire nei componenti della rete mentre il pacchetto viene trasmesso, propagato o memorizzato. Per il momento si supponga che i pacchetti trasmessi vengano ricevuti nello stesso ordine in cui sono stati inviati (nonostante, alcuni bit possano subire errori). Allo scopo di progettare un protocollo per una comunicazione affidabile su un tale canale, si consideri il modo in cui si svolge il dialogo tra due persone in un ambiente rumoroso. Questo è caratterizzato da affermazioni del tipo "Ok" dopo che una frase è stata compresa correttamente o dalla richiesta del tipo: "Puoi ripetere?" quando non si comprende la frase. Questo protocollo usa le conferme positive ("OK"') e le conferme negative ("Puoi ripetere?"). Questi messaggi di controllo consentono al ricevitore di far sapere al mittente se il messaggio è stato ricevuto correttamente o è necessaria la ritrasmissione. In una rete di calcolatori l'affidabilità basata sulla ritrasmissione usa tecniche dette ARQ (Automatic Retransmission reQuest).

Un protocollo che si serve di una tecnica ARQ deve possedere tre requisiti per gestire la presenza di errori:

Il successivo modello del trasmettitore prevede due stati: X e Y. Nello stato X, il protocollo dal lato del trasmettitore è in attesa di trasmettere dati provenienti dal livello superiore. Quando riceve i dati da inviare, calcola il checksum, lo inserisce nel pacchetto insieme ai dati e consegna il pacchetto al livello rete. Nello stato Y, il protocollo del trasmettitore è in attesa di una conferma (ACK o NAK) proveniente dal ricevitore. Quando il mittente riceve un pacchetto ACK, sa che l'ultimo pacchetto è stato ricevuto correttamente e così il protocollo ritorna nello stato di attesa di dati dal livello superiore. Se viene ricevuto un NAK, il protocollo ritrasmette l'ultimo pacchetto e aspetta che il ricevitore invii il pacchetto di risposta contenente la conferma. È importante notare che quando il ricevitore si trova nello stato attesa di ACK o NAK, non può ricevere altri dati dal livello superiore. Solo quando il trasmettitore riceve un pacchetto di conferma potrà uscire da questo stato Y. Il mittente non può inviare un nuovo pacchetto se non è sicuro che il ricevitore abbia ricevuto correttamente il pacchetto appena inviato. Per questo comportamento questa tecnica ARQ è detta stop-and-wait.

Il ricevitore può trovarsi in un solo stato: X. Alla ricezione di un pacchetto, il destinatario risponde con ACK o NAK, a seconda se il pacchetto è corretto o alterato da rumore.

In queste considerazioni si è trascurata l'eventualità che l'errore si possa presentare sul pacchetto di conferma. Come minimo occorre aggiungere il campo checksum ai pacchetti ACK/NAK per riconoscere la presenza di errori. Il problema è come si deve comportare il trasmettitore che riceve un errore in un pacchetto ACK o NAK? La difficoltà è che se un pacchetto ACK o un pacchetto NAK è errato, il mittente non ha modo di sapere se il pacchetto è stato ricevuto oppure no.

Ci sono tre ipotesi di gestione dei pacchetti di conferma ACK o NAK errati:

Versione 3

Per quest'ultima ipotesi, il problema del riconoscimento dei pacchetti ripetuti viene risolto con una tecnica (adottata nel TCP) che consiste nell'aggiungere un campo al pacchetto, nel quale il mittente inserisce un numero di sequenza. Il ricevitore deve controllare questo numero di sequenza per distinguere i pacchetti duplicati dai pacchetti nuovi. Per questo semplice caso di tecnica stop-and-wait, basta un numero di sequenza di 1 bit, perchè il trasmettitore cambia il valore del bit quando invia un pacchetto nuovo, lo lascia invariato quando ripete il pacchetto. Si tratta di un contatore modulo 2. Ipotizzando che il canale non perda pacchetti, i pacchetti di conferma ACK e NAK non hanno bisogno di portare il numero di sequenza, perchè il mittente assume che sia confermato sempre l'ultimo pacchetto inviato.

Volendo rappresentare il trasmettitore e il ricevitore con una macchina a stati finiti, bisogna raddoppiare il numero di stati in cui si possono trovare i due interlocutori, perchè lo stato del protocollo deve tenere conto se il pacchetto spedito dal mittente o aspettato dal ricevitore deve avere il numero di sequenza 0 o 1. In entrambi gli stati le azioni sono simmetriche. la sola differenza è la gestione dei numeri di sequenza.

Macchina a stati finiti del trasmettitoreMacchina a stati finiti del ricevitore

Nel protocollo che si sta costruendo, il ricevitore usa sia le conferme positive che quelle negative. La conferma negativa viene inviata se viene ricevuto un pacchetto errato o fuori ordine. Invece di mandare una conferma negativa si può, in modo equivalente, inviare la conferma positiva per l'ultimo pacchetto ricevuto correttamente. Il mittente che riceve due conferme per lo stesso pacchetto capisce che il ricevitore non ha acquisito correttamente il pacchetto che segue quello confermato due volte. Un leggero miglioramento della versione del protocollo che si sta costruendo consiste nel modificare il comportamento del ricevitore. Il ricevitore deve includere nel pacchetto ACK il numero di sequenza del pacchetto che deve confermare (cioè ACK 0 o ACK 1), mentre il mittente deve controllare il numero di sequenza del pacchetto che aspetta di essere confermato.

Trasferimento affidabile su un canale con rumore e con perdita di pacchetti

Versione 4

Si introduce adesso l'ipotesi che il canale, oltre a danneggiare i pacchetti, possa perdere i pacchetti. Il protocollo deve avere la possibilità di accorgersi che un pacchetto sia stato smarrito e deve prevedere la possibilità di recuperarlo. L'uso del campo checksum, dei numeri di sequenza, dei pacchetti ACK, e le tecniche ARQ consentono di recuperare un pacchetto perso. Il problema di riconoscere la perdita di un pacchetto, invece, richiede l'introduzione di un nuovo meccanismo nel protocollo.

Si consideri che il mittente invii un pacchetto e che il pacchetto, o la conferma inviata dal ricevitore, si perdano. In ogni caso, il mittente non avrà nessuna risposta dal destinatario. Il mittente stabilisce un massimo tempo di attesa e, se non riceve la risposta entro questo tempo, ritrasmetterà il pacchetto.

La durata dell'attesa deve comprendere il tempo di andata e ritorno impiegato dal pacchetto, incluso i tempi di transito e memorizzazione nei dispositivi intermedi, più un certo tempo impiegato dal ricevitore per elaborare il pacchetto. È molto difficile stimare una durata di attesa minima. Idealmente il pacchetto dovrebbe essere recuperato il prima possibile. Di conseguenza il pacchetto potrebbe essere ritrasmesso perchè la conferma sta arrivando con un ritardo maggiore del previsto provocando il fenomeno della duplicazione dei pacchetti. Ma la gestione di questa eventualità è effettuata con l'impiego dei numeri di sequenza.

Il mittente non sa se il pacchetto o se la conferma è stata smarrita, o se entrambi stanno subendo dei ritardi. In ogni caso il pacchetto viene ritrasmesso. Allo scopo di trattare questo meccanismo è richiesto l'utilizzo di un timer a decremento, inizializzato con un valore tale da giungere a 0 in un tempo prestabilito, e quando giunge a 0, il timer deve generare un'interruzione, per avvertire il mittente che il tempo di attesa è scaduto. Il trasmettitore quindi dovrà ripetere la trasmissione del pacchetto, reinizializzando il timer. Se invece giunge la conferma al pacchetto inviato il timer dovrà essere fermato.

L'esistenza di pacchetti duplicati e di pacchetti perduti introduce una complicazione. Se il mittente riceve un ACK, ha il dubbio se il ricevitore lo ha mandato in risposta agli ultimi pacchetti trasmessi o se è giunto in ritardo ed è relativo ad un vecchio pacchetto. Per confermare correttamente i pacchetti, il ricevitore deve gestire una variabile locale, ad esempio N(R), in cui conserva il numero di sequenza del pacchetto che si aspetta di ricevere e quando deve inviare il pacchetto ACK copia questa variabile nel pacchetto ed incrementa la variabile N(R). Anche il mittente deve gestire una variabile locale N(S) per confrontare il numero del pacchetto confermato con il numero del pacchetto che si aspetta di confermare.

Riepilogo

Trasmissione priva di errori e di perdita di pacchetti

Il trasmettitore inizializza la sua variabile locale N(S)=0,
prepara il pacchetto e copia N(S) nel campo "numero di sequenza" dell'header del pacchetto.
Il ricevitore inizializza la sua variabile N(R)=0.
Quando riceve il pacchetto 0 verifica che il numero di sequenza sia uguale ad N(R).
Accetta il pacchetto, incrementa N(R)=1,
copia N(R) nel campo numero di sequenza del pacchetto ACK ed invia ACK 1.
Il trasmettitore verifica che il numero di sequenza nel pacchetto sia uguale a N(S)+1,
incrementa N(S) portandolo a 1, lo copia nel campo numero di sequenza ed invia il pacchetto.

I contatori N(S) ed N(R) sono lunghi 1 bit,
quindi l'incremento consiste nel fargli assumere alternativamente i valori 0 e 1.

Perdita di pacchetti

Il trasmettitore, per ogni pacchetto inviato avvia il timer.
Nell'esempio, il trasmettitore invia il pacchetto 1 ed avvia il timer,
alla scadenza del timer, il trasmettitore non ha ancora ricevuto la conferma,
quindi il pacchetto viene ripetuto.
Questa volta il pacchetto giunge a destinazione e l'ACK viene ricevuto
prima che si verifichi il timeout.

Perdita del pacchetto di conferma

Il pacchetto viene ricevuto correttamente e il ricevitore invia il pacchetto di conferma.
Questo si perde nella rete e, allo scadere del timer, il mittente ripete la trasmissione del pacchetto.
Il ricevitore si accorge di aver ricevuto un duplicato e ripete la conferma.

timeout troppo breve.

Il pacchetto viene ricevuto correttamente e viene confermato.
Il timeout scade prima che giunga la conferma, per cui il pacchetto viene ripetuto.
Il ricevitore si accorge di un pacchetto duplicato e lo conferma nuovamente.