PROGRAMMIAMO
Internet - Protocollo TCP: trasmissione dati
Handshake e connessione

Il protocollo TCP regola la comunicazione fra due host in modo tale che lo scambio avvenga in modo affidabile. Per tale ragione si tratta di un protocollo orientato alla connessione, cioè i due host devono stabilire una connessione prima di potersi effettivamente scambiare i dati. Non è difficile comprendere come una connessione sia fondamentale per l'affidabilità del servizio. Infatti per verificare la completa e corretta ricezione di tutti i segmenti, è necessario che il processo di trasmissione sia incorporato in una "struttura" di livello superiore, che è appunto la connessione. Supponiamo, per fare un esempio, di voler spedire per posta il nostro ultimo romanzo al nostro editore. Siccome il libro è molto voluminoso, decidiamo di spedire un capitolo alla volta. Poiché le poste sono notoriamente inaffidabili, numeriamo i capitoli e prima della spedizione avvisiamo l'editore che stiamo per mandargli il nostro romanzo e di quanti capitoli sarà formato: in questo modo se un capitolo andrà perso, l'editore potrà accorgersene e chiederci di rispedirglielo.

Questo processo di accordo preventivo sulle modalità di una comunicazione viene appunto detto stabilire una connessione. Quando il trasferimento sarà completato, in modo simmetrico la connessione dovrà essere chiusa.

Nel caso del protocollo TCP la procedura necessaria per stabilire la connessione prende il nome di handshake (letteralmente "stretta di mani") a tre vie ed è sintetizzata nella figura seguente:

handshake

Vediamoli brevemente nel dettaglio (la parte di handshake è mostrata in giallo in figura):

  1. l'host client invia al server un segmento SYN (sta per Synchronize). In pratica si tratta di un segmento nel quale il campo dati è vuoto e viene settato ad 1 esclusivamente il campo SYN, facente parte della famiglia dei bit di Flag nell'header del pacchetto;

  2. l'host server riceve il segmento (se tutto va bene!), ne legge il contenuto e notifica che la connessione è possibile attraverso l'invio di un segmento SYN-ACK (sta per Synchronize-Acknowledgement), anche questo con il campo dati vuoto;

  3. l'host client rimane in attesa del segmento SYN-ACK e quando lo riceve invia al server un pacchetto ACK (Acknowledge), questo segmento serve per confermare che la connessione è stata instaurata con successo e potrebbe già contenere dati (inizio della trasmissione).

Dopo che la connessione è stata stabilita, la trasmissione prosegue con uno scambio di segmenti ACQ nelle due direzioni, come mostrato nella figura precedente (fino alla chiusura della connessione stessa, vedi oltre).

Un semplice esempio di trasmissione dati monodirezionale

Terminata la fase di handshake i due host iniziano la fase di trasferimento dati. La trasmissione viene effettuata per mezzo di una serie di pacchetti di tipo ACK scambiati fra i due host. Come abbiamo precedentemente accennato, ogni pacchetto contiene due numeri fondamentali:

Vedremo adesso un po' meglio come funziona questo meccanismo considerando dapprima un caso semplice, quello cioè in cui ci sia solo un host che trasmette e uno che riceve. Osserviamo la figura seguente:

In questo esempio abbiamo considerato una trasmissione in cui ogni segmento contenga solo 3 byte, corrispondenti a tre caratteri di una frase. La trasmissione è già iniziata da un po' di tempo e in figura viene mostrato il caso in cui viene trasmessa la stringa di caratteri "HELLO WORLD" a partire dalla posizione 101 all'interno del testo totale (cioè vuol dire che ci sono altri 100 caratteri, non mostrati, prima della H di HELLO).

Come si vede nell'esempio, il trasmettitore invia un segmento con numero di sequenza 101 (la posizione della lettera H nella stringa totale) e con numero di riconoscimento 12. In generale il numero di riconoscimento del trasmettitore è legato a quanto l'altro host sta a sua volta trasmettendo. Ricordiamo che il protocollo TCP consente una comunicazione bidirezionale (Full-Duplex) e dunque prevede che entrambi gli host possano essere contemporaneamente trasmettitori e ricevitori. In questo nostro primo semplice esempio tuttavia, come si è detto, noi supponiamo che solo uno degli host trasmetta e l'altro riceva soltanto. In questo caso il numero di riconoscimento del nostro primo segmento (12) si riferirà alla numerazione dello scambio iniziale di segmenti in fase di sincronizzazione. Non preoccupiamoci per adesso troppo di questi dettagli e facciamo finta che il numero di riconoscimento nei pacchetti inviati dal mittente non serva a nulla (rimane fisso a 12 per tutta la trasmissione).

Osserviamo invece che il ricevitore risponde alla ricezione del segmento con SEQ 101 con un segmento con numero di riconoscimento ACQ uguale a 104: ciò significa che il ricevitore conferma la ricezione del segmento e dice che si aspetta che il prossimo segmento in arrivo sia numerato con numero di sequenza 104 (cioè +3 byte rispetto al segmento appena ricevuto: in pratica ACQ no. si ottiene sommando tre, la dimensione dati di ogni segmento, al SEQ no. del segmento che è stato ricevuto).

 

Gestione degli errori e ritrasmissione

Perché tutte queste complicazioni? Abbiamo più volte detto che TCP offre un sistema di trasmissione affidabile pur in presenza di una comunicazione intrinsecamente inaffidabile sui livelli inferiori (IP). Ciò significa in pratica che alcuni segmenti potrebbero andare persi o potrebbero contenere errori.

Nel protocollo TCP è il trasmettitore che si accorge dell'eventuale perdita di un segmento nel caso in cui non riceva una conferma ACQ dal ricevitore entro un certo tempo limite (detto timeout). Tralasciamo in quale modo venga deciso un valore ragionevole di timeout (non troppo breve per evitare di segnalare come dispersi segmenti che in realtà sono ancora in viaggio e non troppo lungo da rallentare inutilmente la trasmissione) e vediamo invece nella figura seguente cosa accade nel caso in cui un segmento vada perduto:

Osserviamo che, allo scadere del timeout (RTO), il ricevitore invia di nuovo un segmento di richiesta con lo stesso numero di sequenza (101) del segmento che (presumibilmente) è andato perso. In realtà potrebbe essersi perso non il segmento contenente i dati, ma quello di conferma di ricevimento (ACK). In questo ultimo caso il ricevitore riceverà due volte lo stesso segmento e potrà accorgersi della duplicazione poiché riceve due volte un segmento con lo stesso numero di sequenza (101). Se succede così, il ricevitore scarterà uno dei due segmenti identici e darà comunque di nuovo conferma al trasmettitore dell'avvenuta ricezione.

Nella realtà le cose sono più complicate perché non è detto che il ricevitore riceva i segmenti nella sequenza corretta (cioè nella stessa sequenza in cui sono stati richiesti). Allo stesso modo, in maniera speculare, il trasmettitore non necessariamente riceverà le ACK nello stessa sequenza in cui il ricevitore le ha fornite. Per questo i numeri di sequenza e i numeri di riscontro sono importanti, in quanto permettono al ricevitore di ricostruire la corretta sequenza dei segmenti ricevuti (e di individuare, come visto, eventuali duplicati) e al trasmettitore di sapere se e quali segmenti eventualmente debbano essere ritrasmessi.

Un altro caso interessante è quello di un segmento che venga ricevuto con errori (a tale scopo interviene il controllo checksum). In questo caso il ricevitore semplicemente non convalida il dato ricevuto (cioè non invia l'ACK corrispondente) in modo tale che il trasmettitore, scaduto il timeout, ritrasmetta spontaneamente il segmento.

Un esempio di trasmissione full-duplex

Un caso ancora più complesso (e realistico) è quello mostrato nella figura qui sotto:

Qui entrambi gli host possono trasmettere e ricevere. Inoltre mentre la dimensione dei dati nei segmenti inviati dall'host di sinistra è 3 byte (3 caratteri), l'host di destra invia segmenti con dimensione dati massima di 4 byte (4 caratteri).

Si osservi che ogni segmento inviato dall'host di destra a quello di sinistra (e viceversa) conferma la ricezione dei segmenti precedenti e, contemporaneamente trasmette a destinazione dei nuovi dati. Si tratta di un meccanismo piuttosto efficiente in quanto con un unico segmento si effettua insieme una conferma di ricezione e una nuova trasmissione. Si noti anche come i numeri Seq. no. e ACQ no. si scambino di ruolo nelle due direzioni.

Chiusura della connessione

Dopo che è stata stabilita, una connessione TCP non è considerata una singola connessione bidirezionale, ma piuttosto come l'insieme di due connessioni monodirezionali. Pertanto, ognuna delle parti deve terminare la sua connessione, e possono esistere anche connessioni aperte a metà, in cui solo uno dei due terminali ha chiuso la connessione e non può più trasmettere, ma può (e deve) ricevere i dati dall'altro terminale. Di conseguenza, la chiusura della connessione si può effettuare in due modi:

L'handshake a 3 vie è omologo a quello usato per l'apertura della connessione, con la differenza che il flag utilizzato è il FIN invece del SYN. Un terminale invia un pacchetto con la richiesta FIN, l'altro risponde con un FIN + ACK, ed infine il primo manda l'ultimo ACK, e l'intera connessione viene terminata. L'handshake a 4 vie invece viene utilizzato quando la disconnessione non è contemporanea tra i due terminali in comunicazione. In questo caso uno dei due terminali invia la richiesta di FIN, e attende l'ACK. L'altro terminale farà poi altrettanto, generando quindi un totale di 4 pacchetti.

_images/tcp_closes.png

 

precedente - successiva

Sito realizzato in base al template offerto da

http://www.graphixmania.it