6.4) Rilascio di una connessione |
Rilasciare una connessione è più
semplice che stabilirla, ma comunque qualche piccolo problema
c'è anche in questa fase.
In questo contesto, rilasciare la connessione significa che l'entità
di trasporto rimuove le informazioni sulla connessione dalle proprie
tavole e informa l'utente di livello superiore che la connessione
è chiusa.
Ci sono due tipi di rilasci:
Nel primo caso (esemplificato dal sistema telefonico) quando una
delle due parti "mette giù" si chiude immediatamente
la connessione. Ciò però può portare alla
perdita di dati, in particolare di tutti quelli che l'altra parte
ha inviato e non sono ancora arrivati.
Nel secondo caso si considera la connessione come una coppia di
connessioni unidirezionali, che devono essere rilasciate indipendentemente.
Quindi, lungo una direzione possono ancora scorrere dei dati anche
se la connessione lungo l'altra direzione è stata chiusa.
Il rilascio simmetrico è utile quando un processo sa esattamente
quanti dati deve spedire, e quindi può autonomamente decidere
quando rilasciare la sua connessione in uscita.
Se invece le due entità vogliono essere d'accordo prima
di rilasciare la connessione, un modo di raggiungere lo scopo
potrebbe essere questo:
Purtroppo, le cose non sono così semplici: c'è un
problema famoso in proposito, il problema
delle due armate:
La definizione del problema è la seguente:
Come fanno ad accordarsi gli eserciti dell'armata A sull'ora dell'attacco? Una possibilità è la seguente:
Si potrebbe pensare di risolvere il problema con un passaggio
in più (ossia con un three-way handshake): l'arrivo della
risposta dell'esercito 2 deve essere a sua volta confermato. Ora
però chi esita è il comandante dell'esercito 1,
perché se tale conferma si perde, l'armata 2 non saprà
che la sua conferma alla proposta di attaccare è arrivata
e quindi non attaccherà.
Aggiungere ulteriori passaggi non aiuta, perché c'è
sempre un messaggio di conferma che è l'ultimo, e chi lo
spedisce non può essere sicuro che sia arrivato. Dunque,
non esiste soluzione.
Se ora sostituiamo la frase "attacchiamo l'armata B"
con "rilasciamo la connessione", vediamo che si rischia
effettivamente di non rilasciare mai una connessione.
Per fortuna, rilasciare una connessione è meno critico
che attaccare un'armata nemica. Quindi, qualche rischio si può
anche prendere.
Un protocollo di tipo three-way handshaking arricchito con la gestione di timeout è considerato adeguato, anche se non infallibile:
disconn.request
e, se non
arriva risposta entro un tempo prefissato (timeout), lo invia
nuovamente per un massimo di n volte:
disconn.request
)
rilascia la connessione in ingresso e invia un ack di conferma;
disconn.request
,
fa partire un timer, invia a sua volta un disconn.request
e attende l'ack di conferma. Quando arriva l'ack o scade il timer,
rilascia la connessione in ingresso.
Normalmente il funzionamento è il seguente:
Se si perde l'ack:
Se invece si perde la risposta alla prima proposta di chiusura
(supponendo che il timeout del destinatario sia molto più
ampio di quello del mittente):
Infine, si può perdere la risposta alla prima proposta
di chiusura e tutte le successive proposte di chiusura:
Il protocollo fallisce se tutte le trasmissioni di disconn.request
della peer entity che inizia la procedura si perdono: in tal caso
essa rilascia la connessione, ma l'altra entity non se ne accorge
e la tiene aperta. Il risultato è una half-open
connection.
Un modo per risolvere il problema è che le parti rilascino
una connessione quando passa un certo lasso di tempo (ad es. 60
secondi) senza che arrivino dati. Naturalmente, in tal caso, i
processi devono scambiarsi dei dummy
TPDU, cioé dei TPDU vuoti, con una certa
frequenza anche se non c'è necessità di comunicare
alcunché, per evitare che la connessione cada.
6.5) Controllo di flusso e buffering |
Per alcuni aspetti il controllo di flusso
a livello transport è simile a quello di livello data link:
è necessario un meccanismo, quale la gestione di una sliding
window, per evitare che il ricevente sia sommerso di TPDU.
Però ci sono anche importanti differenze:
Se il livello transport dispone solo di servizi di livello network di tipo datagram:
Viceversa, ove siano disponibili servizi network di tipo affidabile ci possono essere altre possibilità per il livello transport:
Un problema legato al buffering è come gestirlo, vista la grande variabilità di dimensione dei TPDU:
In generale, data la grande variabilità di condizioni che si possono verificare, conviene adottare regole diverse di caso in caso:
Per gestire al meglio queste situazioni, di norma i protocolli
di livello transport consentono alle peer entity di mettersi d'accordo
in anticipo (al setup della connessione) sui meccanismi di bufferizzazione
da usare.
Inoltre, spesso la gestione della dimensione delle finestre scorrevoli
è disaccoppiata dalla gestione degli ack (vedremo il caso
di TCP).
6.6) Multiplexing |
Una importante opportunità è
data dal multiplexing delle conversazioni di livello transport
su quelle di livello network.
Se le connessioni di livello network (in una rete che le offre)
sono costose da istituire, allora è conveniente convogliare
molte conversazioni transport su un'unica connessione network
(upward multiplexing).
Viceversa, se si vuole ottenere una banda superiore a quella consentita
a una singola connessione network, allora si può guadagnare
banda ripartendo la conversazione transport su più connessioni
network (downward multiplexing).
Ciò può essere utile, ad sempio, in una situazione dove:
Supponendo che la dimensione dei pacchetti sia di 128 byte, il
mittente può spedire al massimo 28 - 1 pacchetti
ogni 540 msec, e quindi ha a disposizione una banda di 484 kbps,
anche se la banda del canale satellitare è tipicamente
100 volte più grande.
Se la conversazione transport è suddivisa su, ad esempio,
10 connessioni network, essa potrà disporre di una banda
10 volte maggiore.