In questo articolo spiego i principali protocolli del livello trasporto dello stack TCP/IP: i protocolli TCP e UDP. Analizzeremo le caratteristiche di entrambi i protocolli, le loro differenze e i contesti di utilizzo.
Indice dei contenuti
Introduzione
Il modello TCP/IP (Transmission Control Protocol/Internet Protocol) rappresenta l’architettura di riferimento per le comunicazioni su Internet. All’interno di questo modello, il livello di trasporto svolge un ruolo cruciale nel garantire l’affidabilità e l’efficienza della trasmissione dei dati. Due protocolli principali operano a questo livello: TCP (Transmission Control Protocol) e UDP (User Datagram Protocol). I protocolli di trasporto creano l’astrazione logica di una connessione end-to-end, ovvero il supporto alla comunicazione tra due processi che si trovano ai due estremi del canale logico. In questo articolo, analizzeremo le caratteristiche di entrambi i protocolli, le loro differenze e i contesti di utilizzo.
Compiti principali del livello Trasporto
Il compito principale del livello Trasporto nel modello TCP/IP è stabilire, mantenere e chiudere il collegamento logico tra processi applicativi in esecuzione su host remoti, fornendo un servizio con connessione (connection oriented) affidato al protocollo TCP o senza connessione (connctionless) delegato al protocollo UDP.
Lato mittente, il livello trasporto riceve i dati (payload) dall’applicazione che genera il messaggio. I dati sono imbustati aggiungendo un’intestazione. Il PDU (Protocol Data Unit) ottenuto si chiama segmento. Il segmento è poi passato al livello Rete, che lo imbusta con l’intestazione del protocollo di livello Rete (protocollo IP) per generare il pacchetto, che è inoltrato al livello Data link e, infine, al livello fisico, che invia tutto sul canale fisico di trasmissione.
Lato destinatario, il livello Trasporto riceve il segmento dal livello Rete, elimina l’intestazione del livello Trasporto e passa i dati al livello superiore, cioè all’applicazione destinataria del messaggio. Il tragitto fisico dei dati procede in verticale. I protocolli collegano logicamente, in orizzontale, entità di pari livello. Il livello trasporto fornisce una connessione end-to-end per lo scambio di dati, dando la possibilità alle due applicazioni remote di comunicare

Altri compiti dei protocolli del livello Trasporto:
- indirizzamento
- multiplexing/demultiplexing
- rilevamento degli errori di trasmissione
- error recovery
- controllo del flusso
- controllo della congestione della rete
Indirizzamento – porte logiche, socket
La porta è un identificatore numerico a 16 bit assegnato in modo univoco a ogni applicazione durante una comunicazione di rete.
- Il numero di porta sorgente identifica l’applicazione (processo) che ha generato i dati (lato mittente);
- Il numero di porta di destinazione identifica l’applicazione (processo) che deve ricevere i dati (lato destinatario).
Ciascun processo è identificato attraverso un numero a 16 bit contenuto nell’intestazione del segmento del protocollo TCP o UDP. Questo numero prende il nome di porta logica. La numerazione parte da 0 e arriva a 65535. Un certo numero di porte (Well Known Ports) sono assegnate ad applicazioni specifiche, altre sono assegnate a produttori di software (Registered Ports), altre sono liberamente utilizzabili.
La coppia {<indirizzo IP>, <numero di porta>} forma un socket e rappresenta l’estremità del canale di collegamento (endpoint) tra due processi in esecuzione. Formalmente un socket si indica con l’indirizzo IP del dispositivo, seguito dal numero della porta, separati da “:”.
Per esempio IP 101.54.36.152:3410 identifica l’applicazione 3410 in esecuzione sul dispositivo con IP IP 101.54.36.152
Il canale logico è formato da una coppia di socket, una per ciascun processo:
- {<indirizzo IP sorgente>: <numero di porta sorgente>}
- {<indirizzo IP destinazione>: <numero di porta destinazione>}
Per esempio, per una richiesta di una pagina web:
- la richiesta parte da un client HTTP identificato, per esempio, dal numero di porta 3410, in esecuzione su un dispositivo con indirizzo IP 101.54.36.152;
- la richiesta deve arrivare a un server web identificato dal numero di porta 80 (porta di default di un server web), in esecuzione su un dispositivo con indirizzo IP 134.5.6.7;
- Il server web deve restituire la pagina web all’applicazione 3410 in esecuzione su 101.54.36.152
La richiesta sarà incapsulata in un segmento (o più segmenti) con numero di porta sorgente 3410 e numero di porta di destinazione 80. Questo segmento sarà poi incapsulato in un pacchetto con IP mittente 101.54.36.152 e IP destinatario 134.5.6.7.
La risposta sarà incapsulata in un segmento (o più segmenti) con numero di porta sorgente 80 e numero di porta di destinazione 3410. Quest’ultimo segmento sarà poi incapsulato in un pacchetto con IP mittente 134.5.6.7 e IP destinatario 101.54.36.152.

multiplexing/demultiplexing
Utilizzando i numeri di porta, i dati provenienti da diversi servizi, come ad esempio quelli relativi al web (protocollo HTTP) o alla posta elettronica (protocollo SMTP), possono essere trasmessi simultaneamente sulla stessa connessione di rete tramite il meccanismo del multiplexing.
Il multiplexing è il processo che consente all’host mittente di raccogliere il flusso dei dati provenienti dalle diverse applicazioni e imbustarli come payload del segmento.
Il demultiplexing è il processo opposto al multiplexing. Consegna i dati ricevuti ai processi che sono collegati alle porte di destinazione: il nodo ricevente utilizza il numero di porta di destinazione per individuare l’applicazione coinvolta nel trasferimento dei dati

Affidabilità, error recovery, controllo del flusso e congestione della rete sono prerogative dei protocolli affidabili del livello trasporto, come il TCP e li analizzaremo più avanti nell’articolo
Transmission Control Protocol (TCP)
TCP è un protocollo orientato alla connessione che assicura la trasmissione affidabile dei dati tra due dispositivi. Questo protocollo viene utilizzato in applicazioni dove l’integrità dei dati è essenziale, come la navigazione web, la posta elettronica e il trasferimento di file.
Caratteristiche principali di TCP
- Connessione Affidabile: prima della trasmissione, TCP stabilisce una connessione tra mittente e destinatario attraverso un handshake a tre vie.
- Controllo di flusso: garantisce che il mittente non invii dati più velocemente di quanto il destinatario possa elaborare.
- Controllo della congestione: riduce il traffico di rete in caso di sovraccarico.
- Segmentazione e riassemblaggio: divide i dati in segmenti che vengono riassemblati nella sequenza corretta.
- Ritrasmissione dei pacchetti persi: se un pacchetto non viene ricevuto, TCP ne richiede la ritrasmissione.
Il funzionamento del protocollo TCP prevede tre fasi:
- apertura della connessione TCP;
- trasferimento dei dati;
- chiusura della connessione TCP
Ogni segmento è imbustato in un pacchetto IP che, al massimo, può essere lungo 65535 byte, anche se ogni rete ha una propria unità massima di trasferimento (MTU) che condiziona il numero massimo di byte ammessi su quella tratta.
Affinché mittente e destinatario possano scambiarsi i pacchetti, TCP stabilisce una connessione, una sorta di “tubo” logico entro cui passano i dati, che è utilizzato per tutto il tempo della comunicazione. L’apertura della connessione è effettuata con una procedura chiamata Three-Way Handshake (stretta di mano a tre vie), che corrisponde a una stretta di mano “forte”, nella quale si fanno tre passaggi per presentarsi.
Funzionamento dell’handshake a tre vie
- SYN (Synchronize): il client invia una richiesta di connessione al server.
- SYN-ACK (Synchronize-Acknowledge): il server risponde accettando la richiesta.
- ACK (Acknowledge): il client conferma la connessione e inizia la trasmissione dei dati.
A invia a B un segmento di richiesta di apertura connessione. Il segmento è contraddistinto da SYN = 1, ACK = 0, Sequence Number = k, dove k è un numero generato casualmente che è utilizzato per identificare la connessione.
B invia ad A un segmento di conferma di richiesta di apertura della connessione. Il segmento è contraddistinto da SYN = 1, ACK = 1, Aknowledge Number = k + 1 (per comunicare che si conferma il segmento k), Sequence Number = J. In caso di rifiuto della richiesta, il flag RST viene posto a 1.
A invia a B un segmento per confermare la ricezione della conferma. Il segmento è contraddistinto da SYN = 0, ACK = 1, Aknowledge Number = J + 1 (per comunicare che si conferma il segmento di conferma). In teoria, B potrebbe inviare conferma della conferma della conferma, e lo scambio delle conferme non avrebbe fine
Dopo il terzo segmento la connessione è stabilita e A e B possono iniziare a scambiarsi dati in full duplex

La chiusura di una connessione TCP avviene con lo scambio di quattro segmenti e può partire da uno qualunque dei due host
La chiusura di una connessione TCP avviene con lo scambio di quattro segmenti e può partire da uno qualunque dei due host.
- Una delle applicazioni su un end-system (parte attiva) effettua la chiusura attiva (active close) chiamando la funzione close(), che spedisce un segmento con FIN = 1 e numero di sequenza M uguale all’ultimo dei byte trasmessi in precedenza più uno.
- L’end system che riceve il FIN (parte passiva) effettua la chiusura passiva (passive close) all’insaputa dell’applicazione del livello superiore: per prima cosa il modulo TCP dell’end-system passivo spedisce all’endsystem attivo un segmento Ack Number = M +1, per confermare la corretta ricezione del segmento M; successivamente il TCP passivo trasmette all’applicazione a cui deve passare i dati il segnale FIN, sotto forma di end-of-file, che viene accodato ai dati non ancora letti dall’applicazione. Poiché la ricezione del FIN significa che non si riceverà nessun altro dato, con l’end-of-file il TCP comunica all’applicazione che lo stream di input è chiuso.
- Quando l’applicazione dell’end-system passivo legge dal buffer l’end-of-file, deve effettuare per quel socket la chiamata alla funzione close(), che ordina al modulo TCP di inviare a sua volta all’end-system attivo un segmento FIN, col numero di sequenza uguale a K, cioè l’ultimo byte trasmesso più 1.
- Quando il modulo TCP dell’end-system attivo riceve il FIN, spedisce un ACK con Ack Number = K + 1. Terminato questo passo viene conclusa anche la funzione close() dell’attivo.

Affidabilità
L’affidabilità è ottenuta utilizzando il numero di sequenza, il numero di conferma e un timer:
- il mittente invia un segmento dati con numero di sequenza K;
- il destinatario riceve il segmento e ne controlla la correttezza usando il checksum;
- se il segmento è corretto, il ricevente invia un segmento di conferma con numero di conferma J dove J = k + numero di byte ricevuti + 1. Il numero di conferma specifica il numero del prossimo byte che il ricevente si aspetta di ricevere, confermando di avere ricevuto tutti i byte precedenti in modo corretto;
- quando il mittente invia un segmento, imposta un timer. Se entro lo scadere deltimer (time out) non riceve la conferma,assume che il segmento trasmesso non è stato ricevuto e lo rinvia. Se però la conferma non arriva entro il tempo stabilito, allora il ricevente riceve dei segmenti duplicati, uno dei quali sarà scartato.
Error recovery
Le tecniche di error recovery (per il recupero di segmenti persi o errati) sono:
- Go-Back-N: a partire dal segmento errato o mancante, vengono rinviati tutti i segmenti, anche se sono già stati ricevuti correttamente. Il ricevente accetta e conferma i segmenti che arrivano corretti con il numero di sequenza atteso. Dopo il primo segmento errato o non atteso, non accetta altri segmenti
- Selective Repeat: è più efficiente di Go-Back-N in quanto viene rinviato solo il segmento errato o mancante. Il ricevente accetta e conferma tutti i segmenti che arrivano corretti, anche dopo un eventuale segmento errato.
Controllo del flusso
Per migliorare le prestazioni, TCP trasmette più segmenti prima di fermarsi in attesa delle conferme. C’è quindi la necessità di effettuare il controllo del flusso cioè regolare la velocità di trasmissione del mittente in base alla quantità di memoria disponibile del ricevente. TCP realizza il controllo del flusso tramite la tecnica della finestra scorrevole
- la finestra lato mittente contiene i numeri di sequenza dei segmenti che devono essere trasmessi, oppure che sono stati trasmessi, ma non sono stati fermati. Stabilisce la quantità massima di byte che il trasmettitore è autorizzato a inviare senza averne ricevuto riscontro. Quando il modulo TCP del mittente riceve un messaggio dal livello applicazione, inserisce il numero di sequenza nella finestra e, quando arriva la conferma di corretta ricezione (ACK) da parte del destinatario, elimina il numero dalla finestra. Se la finestra è piena, il TCP deve aspettare a trasmettere nuovi segmenti e attendere che si liberi spazi
- La finestra di ricezione rappresenta il numero di byte disponibili nel buffer del ricevente. Il ricevente comunica lo spazio disponibile, utilizzando il campo window size dell’intestazione. Se il buffer del ricevente è pieno, il campo window size è 0 e il mittente deve fermarsi e attendere per inviare nuovi dati. Quando l’applicazione del ricevente legge dal buffer ricevente i dati, si libera dello spazio e il mittente può riprendere l’invio dei dati

Nonostante l’accortezza del TCP nel trattare la gestione dei segmenti per garantirne la correttezza, una cattiva gestione del controllo di flusso può creare seri problemi di efficienza. I problemi sono due, uno complementare all’altro:
- un processo di scrittura molto lento da parte del mittente (problema studiato da Nagle);
- un processo di lettura e svuotamento del buffer di ricezione dati molto lento da parte del ricevente (problema studiato da Clark).
In entrambi i casi, ciò comporta l’invio in rete di segmenti contenenti una quantità molto piccola di dati (pochi byte), con conseguente aumento del rapporto tra il numero di byte dell’intestazione e il numero di byte dati, e uso inefficiente del canale trasmissivo. Vediamo ora come TCP risolve questi due problemi
La soluzione proposta da Nagle è la seguente: il mittente invia il primo byte e mantiene in un buffer i successivi, che saranno trasmessi in un unico segmento quando il mittente riceve la conferma del primo byte inviato


Secondo problema: l’applicazione ricevente prende i dati da TCP al ritmo di un byte alla volta (algoritmo di Clark) Il secondo problema, complementare al primo, affronta il caso in cui il mittente vuole inviare grandi blocchi di dati, ma il ricevente accetta un solo carattere, o pochi caratteri, alla volta. Il caso è chiamato anche sindrome della finestra stupida (Silly Window), perché un uso inappropriato della finestra, pur essendo corretto, causa notevoli inefficienze.
La soluzione al problema della Silly Window proposta da Clark è la seguente: il destinatario attende di avere sufficiente spazio di memoria libero, prima di “aprire la finestra”, cioè prima di inviare un valore di window size sufficientemente consistente.


Congestione
C’è poi un terzo problema di cui si fa carico TCP: il problema della congestione della rete. Questo si verifica quando la rete deve subire un carico superiore a quello che è in grado di gestire.
Accade quando, per esempio, un router è sovraccaricato di pacchetti e non riesce più a smaltirli, perché la velocità con cui li riceve è superiore a quella con cui riesce a spedirli. La sua memoria si riempie di pacchetti fino a saturarsi e a perderli. La soluzione consiste nel rilevare la potenziale congestione e, di conseguenza, diminuire la velocità dei dati trasmessi in rete.
Per questo, oltre alla finestra di ricezione (window size) presente nell’intestazione TCP, occorre una finestra di congestione, relativa alla capacità di rete e non a quella del ricevente.
L’idea che sta alla base dell’algoritmo consiste nell’inserire in rete un nuovo pacchetto solo quando il precedente è stato consegnato al destinatario e non è più in rete. Il rilevamento della congestione si basa sul controllo dei tempi di conferma dei pacchetti trasmessi (timeout). La finestra di ricezione è relativa allo spazio di memoria disponibile del ricevente, la finestra di congestione è relativa alla capacità della rete.

Applicazioni di TCP
- HTTP/HTTPS (navigazione web)
- SMTP, POP3, IMAP (email)
- FTP (trasferimento file)
- SSH (connessioni sicure)
User Datagram Protocol (UDP)
UDP è un protocollo senza connessione, progettato per applicazioni che necessitano di bassa latenza e tollerano una certa perdita di dati. È utilizzato principalmente in streaming multimediali, giochi online e servizi di VoIP.
Caratteristiche principali di UDP
- Velocità: l’assenza di controllo di flusso e congestione lo rende più veloce di TCP.
- Trasmissione non affidabile: i pacchetti possono essere persi o arrivare fuori ordine senza alcun meccanismo di correzione automatica.
- Nessun overhead per la gestione della connessione: UDP non richiede l’handshake iniziale.
- Supporto per broadcast e multicast: ideale per la trasmissione di dati a più destinatari.
Applicazioni di UDP
- Streaming audio e video (YouTube, Netflix, Spotify)
- VoIP (Skype, Zoom, WhatsApp Calls)
- Giochi online (FPS, MMO)
- DNS (Domain Name System)
- Protocollo NTP (Network Time Protocol)
Differenze tra TCP e UDP
La seguente tabella evidenzia le principali differenze tra i due protocolli:

Conclusione
La scelta tra TCP e UDP dipende dalle esigenze dell’applicazione. Se la priorità è l’affidabilità e l’integrità dei dati, TCP è la scelta migliore. Se invece si privilegia la velocità e una latenza ridotta, UDP rappresenta la soluzione ottimale.
Comprendere le differenze tra questi protocolli è essenziale per sviluppare applicazioni di rete performanti ed efficienti.
Lascia un commento