2.3. Le protocole TCP
Le protocole TCP (Transmission Control Protocol) est décrit dans le RFC 793. Ce RFC original a depuis été amendé et complété par de nombreux autres RFC, mais les principes de base sont toujours valides.
TCP fournit un tout autre service qu’UDP. Il est :
- orienté connexion, ce qui signifie que les deux entités communiquant vont au préalable ouvrir la connexion, puis la terminer lorsque les transmissions de données sont terminées
- en mode flux d’octets : les applications se transmettent les données sans délimitation. Cela peut être octet par octet ou par paquets de taille variable, selon les cas. A la réception, les données peuvent également arriver au compte-goutte ou par paquet, pas nécessairement selon le même rythme qu’à l’émission.
- fiable : il garantit que le flux d’octet sera reconstitué à l’identique, sans erreur, perte ou mélange d’octets.
L’en-tête TCP
Implémenter ce type de services est complexe, et cela se ressent dans l’en-tête du protocole, qui est nettement plus grand que celui d’UDP :
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Les champs identiques entre l’en-tête TCP et l’en-tête UDP sont :
- Les numéros de port source et destination (16 bits chacun)
- Le checksum TCP, sur 16 bits toujours
D’autres éléments y figurent, pour garantir le service spécifique à TCP :
- Le numéro de séquence : Il identifie le numéro du premier octet de données dans l’ensemble du flux de données transmis. Ainsi, au cours d’une transmission d’un flux de 25 octets répartis dans 5 segments de 5 octets, les numéros de séquence seront 0, 5, 10, 15 et 20. Notez que cette numérotation ne commence en général pas à zéro, pour des raisons de sécurité. Ce numéro de séquence sert à reconstituer le flux de données (les segments pouvant arriver dans le désordre ou être dupliqués), mais également à détecter les pertes au niveau du destinataire.
- Le numéro d’accusé de réception : Il permet au receveur d’annoncer à l’émetteur le numéro du prochain octet attendu, ce qui permet à ce dernier de vérifier si toutes les données sont bien arrivées à destination.
- Les flags permettent d’indiquer des éléments de contrôle. Il y a notamment :
- Le flag ACK, qui indique si le segment contient un numéro d’accusé de réception valide
- Le flag RST, qui indique que la connexion doit être interrompue immédiatement
- Le flag SYN, qui indique une demande d’ouverture de connexion
- Le flag FIN, qui indique qu’un des interlocuteurs a terminé ses transferts et que la connexion peut être interrompue dans cette direction.
- Le champ Window, qui indique la quantité maximum d’octets qui peuvent être en transit sur le réseau à un moment donné. Chaque interlocuteur indique la valeur acceptable pour lui, en fonction des ressources mémoire que l’OS peut allouer au stockage des données TCP en attente. Les deux interlocuteurs utiliseront la taille de fenêtre la plus petite parmi les deux valeurs échangées, pour s’adapter au fonctionnement de celui qui a le moins de ressources. La valeur de ce champs peut évoluer au cours d’une transmission
Déroulement d’une session TCP
Une connexion TCP normale contient 3 phases :
- l’établissement de la connexion (en vert sur le schéma ci-dessous), où l’initiateur s’assure que le destinataire est disponible, et où les deux interlocuteurs peuvent éventuellement se mettre d’accord sur l’utilisation d’options TCP.
- l’échange de données (en jaune), où chacun peut envoyer des données. Par exemple, dans le cas d’une connexion HTTP au dessus de TCP, le client enverra une requête HTTP et le serveur répondra avec une réponse contenant une page web. Sur la figure ci-dessus, l’hôte A et l’hôte B s’échangent des données. Les communications TCP bi-directionnelles.
- la fermeture de la connexion (en rouge), si tout s’est déroulé comme attendu. Chaque direction de transmission clôture son canal, et lorsque les deux directions sont fermées, toutes les données sont considérées comme transmises. Dans le cas où un problème technique perturbe le déroulement de la communication, la partie concernée envoie un segment avec le flag RST activé : cela signifie la fin abrupte et unilatérale de la communication. Ce cas de figure ne permet pas de garantir que toutes les données ont été transmises.
Ouverture de connexion TCP
L’établissement de la connexion se fait via un triple échange, appelé “Three-Way Handshake”. Tout d’abord, l’hôte qui souhaite établir la connexion (appelons-le A) envoie un segment SYN contenant le premier numéro de séquence de la transmission dans cette direction.Le destinataire (B) envoie à son tour un segment, qui aura deux significations :
- un flag ACK signalant que le segment contient l’accusé de réception du SYN reçu de A, validant la demande d’ouverture dans ce sens
- un flag SYN demandant l’ouverture de l’autre direction de transmission (de B vers A). Ce segment contiendra également le premier numéro de séquence du flux B-A.
Pour finir cet établissement de connexion, un troisième segment est envoyé, par A, contenant un ACK validant l’ouverture du flux B-A.
Remarquez que :
- Pour des raisons de sécurité, les numéros de séquence commencent à une valeur initiale aléatoire, et non à 0.
- Un segment avec le flag SYN activé “consomme” un octet de données : Le numéro de séquence suivant est incrémenté. Par contraste, le ACK ne consomme pas de numéro de séquence, et le segment suivant aura donc le même numéro.
Transmission de données TCP
Une fois la connexion établie, les deux entités échangent des données de manière bidirectionnelle. Chaque segment peut contenir des données et/ou des accusés de réception, selon la présence ou non d’un payload et du flag ACK.
Par exemple, dans la figure ci-dessous, les segments contenant les données “XY” et “DE” contiennent également un accusé de réception, respectivement pour le segment contenant “AB” et pour le segment contenant “XY”.
Durant cette transmission, des pertes de segments peuvent survenir. Dans ce cas, l’émetteur doit pouvoir détecter ces pertes et retransmettre les données manquantes. Il utilise pour cela un timer de retransmission. Si ce dernier expire, il retransmet ses données, comme illustré dans la figure ci-dessous.
Dans cette figure, le segment numéroté 125 se perd. L’émetteur, ne recevant pas d’accusé de réception pour ces données, attend l’expiration de son timer, puis retransmet le segment perdu. Cette fois, le destinataire reçoit bien l’information, la transmet à l’application et envoie l’accusé de réception.
Du côté du receveur, lorsqu’un segment n’arrive pas à destination dans une série, le receveur constate qu’il y a un “trou” dans les numéros de séquence reçu. Il ne peut donc plus continuer à transmettre le flux de données au processus applicatif en attente, puisque livrer des octets dans le désordre ne respecterait pas le contrat de service. Selon les implémentations TCP, soit il jette les segments ayant des numéros supérieurs à celui attendu, soit il les met de côté dans un buffer pour les transmettre une fois les données manquantes reçues.
Un premier algorithme est l’algorithme Go-Back-N : Le receveur jette les segments reçus hors séquence (i.e. qui ne correspondent pas au numéro de séquence attendu, 123 dans l’exemple ci-dessous). Du coup, lors de l’expiration du timer, le receveur retransmet tous les segments non acquittés de sa fenêtre de transmission.
Si, à l’inverse, le receveur dispose d’un buffer en mémoire pour stocker les segments reçus hors séquence, l’algorithme “Selective Repeat” peut être exploité, comme le montre la figure ci-dessous.
Lorsque les segments contenant CD et E arrivent à la destination, l’OS de l’hôte B ne les transmet pas à l’application, puisqu’ils sont hors séquence. Par contre, il les stocke temporairement dans un buffer. Du côté de l’émetteur, ce dernier ayant connaissance de l’utilisation de l’algorithme Selective Repeat par le receveur, il peut se contenter de ne retransmettre que le segment perdu. Une fois ce dernier enfin arrivé à destination, B peut transmettre l’ensemble des données à l’application : L’information “AB” juste reçue, ainsi que “CDE” depuis le buffer.
Avec Selective Repeat, pour éviter la retransmission des segments arrivés correctement à destination, on ajoutera également dans l’en-tête du message un champ spécial contenant des “acquis sélectifs” (SACK). Dans l’exemple ci-dessus, lors de la réception des valeurs “CD” et “E”, le receveur ajoutera dans ses segments ACK un champ SACK pour “125” et “127” respectivement, en plus de l’accusé de réception classique “ack 123”.
En pratique, TCP utilise un algorithme hybride, basé sur Go-Back-N mais avec souvent, selon les implémentations, une stratégie de réception proche du Selective Repeat. Il propose également des optimisations dans les retransmissions, telles que le “Fast Retransmit” : Lorsque l’émetteur reçoit trois accusés de réception dupliqués pour un même segment, il en déduit qu’un segment s’est perdu mais que les suivants sont bien arrivés (cf. acquis dupliqués dans la figure illustrant Go-Back-N ci-dessus). Il va donc retransmettre le segment concerné sans attendre l’expiration du timer.
Une explication complète des mécanismes de retransmission est disponible dans le livre Computer Networking :
- le chapitre sur les retransmissions dans le cadre de la couche Liaison de données introduit les principes de fonctionnement des retransmissions
- Les spécificités de ces mécanismes dans le cadre de la couche Transport sont détaillés dans le chapitre “Data Transfert”.
- Et enfin, l’implémentation de ces mécanismes dans TCP est détaillée dans la section “TCP Reliable Data Transfer”.
Fermeture de connexion TCP
Comme expliqué plus haut, les données sont bi-directionnelles avec TCP. Il y a donc deux directions de transmission, et chacune doit être fermée spécifiquement et indépendamment. Pour cela, chaque direction, lorsqu’elle a fini sa transmission, envoie un FIN, puis attend un ACK de confirmation. La communication est entièrement terminée à la fin des deux échanges FIN/ACK, comme le montre la figure ci-dessous. Ce cas de figure est appelé “Fermeture Gracieuse”. Il garantit que l’ensemble des données de la transmission ont été correctement reçues.
Si, par contre, un événement imprévu interrompt la connexion (par ex. interruption du processus applicatif), l’OS va réagir en interrompant directement la connexion TCP par l’envoi d’un unique segment avec le flag RST. La fermeture est abrupte : les données en transit sont potentiellement perdues. Ce cas de figure est illustré dans la figure ci-dessous.
Usages de TCP
La qualité principale de TCP est sa fiabilité, mais cette fiabilité vient avec un coût : le temps nécessaire à la retransmission. TCP ajoute donc des délais lors de la transmission de données en milieu instable, ce qui ne convient pas à toutes les applications. Par contre, il conviendra parfaitement aux applications nécessitant des transferts de données précis (documents, exécutables, données critiques, … ), mais étant plus tolérant à des délais potentiellement instables. Les applications et protocoles utilisant principalement TCP sont :
- HTTP pour les échanges de documents Web
- SMTP, POP, IMAP pour les emails
- Les applications de transfert de fichiers (ex : FTP)
- Les protocoles d’accès distant (ex : SSH)
- Certaines applications multimédia non interactives (ex : streaming avec bufferisation possible)