1 TCP - Transmission Control Protocol
TCP est l'acronyme de `` Transmission Control Protocol '', il est défini dans la RFC 793 [Postel 1981c]. Les données encapsulées dans un en-tête TCP sont des `` paquets TCP ''.
figure VII.01 -- TCP encapsulé dans IP
TCP est bien plus compliquéVII1 qu'UDP examiné au chapitre précédent, il apporte en contrepartie des services beaucoup plus élaborés.
0.3cm
Cinq points principaux caractérisent ce protocole :
0.3cm
Il faut préciser que les paquets de données sont acquittés
de bout en bout et non de point en point. D'une manière
générale le réseau assure l'acheminement et les extrémités
le contrôle (Dave Clark).
Conceptuellement, pour établir une connexion -- un circuit
virtuel -- il faut avoir réunis les éléments du
quintuplet :
L'ensemble de ces cinq éléments définit un circuit virtuel
unique. Que l'un d'eux change et il s'agit d'une autre
connexion !
Le protocole autorise la clôture du flot dans une direction
tandis que l'autre continue à être active. Le circuit
virtuel est rompu quand les deux parties ont clos le
flux.
La figure suivante montre la structure d'un en-tête TCP. Sa taille normale est de 20 octets, à moins que des options soient présentes.
figure VII.02 -- Structure de l'en-tête TCP
TCP numérote chaque octet transmis en incrémentant ce nombre
32 bits non signé. Il repasse à 0 après avoir atteint 232 - 1
(4 294 967 295).
Pour le premier octet des données transmis ce nombre est
incrémenté de un, et ainsi de suite...
Il doit s'accompagner du drapeau ACK (voir plus loin).
En fonctionnement normal un seul bit est activé à la fois mais
ce n'est pas une obligation. La RFC 1024 [Postel
1987] décrit l'existence de paquets tcp dénommés `` Christmas
tree '' ou `` paquet kamikaze '' comprenant les bits
SYN+URG+PSH+FIN !
Chaque partie annonce ainsi la taille de son buffer de
réception. Par construction, l'émetteur n'envoie pas plus
de données que le récepteur ne peut en accepter.
Cette valeur varie en fonction de la nature du réseau et
surtout de la bande passante devinée à l'aide de statistiques
sur la valeur du RTT. Nous y reviendrons au paragraphe
4.
Le mécanisme de transmission à l'application
dépend du système d'exploitation.
Les options utilisées :
Quand cette valeur n'est pas nulle, la taille de la
fenêtre est de
65535 x 2shift. Par exemple
si `` shift '' vaut 1 la taille de la fenêtre est de
131072 octets soit encore 128 ko.
2 Début et clôture d'une connexion
2.1 Établissement d'une connexion
L'établissement d'une connexion TCP s'effectue en trois temps, comme le schéma de la figure 3 l'explicite.
figure VII.03 -- Établissement d'une connexion
On suppose que l'émetteur du premier paquet avec le bit SYN a connaissance du couple (adresse IP du récepteur, numéro de port du service souhaité).
cm
L'émetteur du premier paquet est à l'origine de l'établissement du circuit virtuel, c'est une attitude généralement qualifiée de `` cliente ''. On dit aussi que le client effectue une `` ouverture active '' (active open).
cm
Le récepteur du premier paquet accepte l'établissement de la connexion, ce qui suppose qu'il était prêt à le faire avant que la partie cliente en prenne l'initiative. C'est une attitude de `` serveur ''. On dit aussi que le serveur effectue une `` ouverture passive '' (passive open).
cm
Une fois achevée cette phase nommée `` three-way handshake '', les deux applications sont en mesure d'échanger les octets qui justifient l'établissement de la connexion.
Un échange de trois segments est nécessaire pour l'établissement de la connexion ; il en faut quatre pour qu'elle s'achève de manière canonique (`` orderly release '').
cm
figure VII.04 -- Clôture d'une connexion
cm La raison est qu'une connexion TCP est `` full-duplex '', ce qui implique que les données circulent indépendamment dans un sens et dans l'autre. Les deux directions doivent donc pouvoir être interrompues indépendamment l'une de l'autre.
cm
L'application qui envoie un paquet avec le drapeau FIN indique à la couche TCP de la machine distante qu'elle n'enverra plus de donnée. La machine distante doit acquitter ce segment, comme il est indiqué sur la figure VII.04, en incrémentant d'une unité le `` sequence number ''.
cm
La connexion est véritablement terminée quand les deux applications ont effectué ce travail. Il y a donc échange de 4 paquets pour terminer la connexion.
cm
Au total, sans compter les échanges propres au transfert des données, les deux couches TCP doivent gérer 7 paquets, il faut en tenir compte lors de la conception des applications !
cm
Sur la figure on constate que le serveur continue d'envoyer des données bien que le client ait terminé ses envois. Le serveur a détecté cette attitude par la réception d'un caractère de EOF (en C sous Unix).
cm
Cette possibilité a son utilité, notamment dans le cas des traitements distants qui doivent s'accomplir une fois toutes les données transmises, comme par exemple pour un tri.
Au lieu d'un échange de quatre paquets comme précédement, un mécanisme de reset est prévu pour terminer une connexion au plus vite (abortive release).
cm
Ce type d'arrêt est typiquement géré par la couche TCP elle-même quand l'application est brutalement interrompue sans avoir effectué un appel à la primitive close(2), comme par exemple lors d'un appel à la primitive abort(2), ou après avoir rencontré une exception non prise en compte (`` core dump ''...).
cm
L'extremité qui arrête brutalement la connexion émet un paquet assorti du bit RST, après avoir (ou non) envoyé les derniers octets en attenteVII6. Ce paquet clôt l'échange. Il ne reçoit aucun acquittement.
cm
L'extrémité qui reçoit le paquet de reset (bit RST), transmet les éventuelles dernières données à l'application et provoque une sortie d'erreur du type `` Connection reset par peer '' pour la primitive de lecture réseau. Comme c'est le dernier échange, si des données restaient à transmettre à l'application qui a envoyé le RST elles peuvent être détruites.
figure VII.05 -- Émission d'un rst
Le bon acheminement des données applicatives est assuré par un mécanisme d'acquittement des paquets, comme nous avons déjà pu l'examiner partiellement au paragraphe précédent.
3.1 Mécanisme de l'acquittement
figure VII.06 -- Mécanisme de l'acquittement
Cette valeur limite est basée sur la constante MSLVII7 qui est un choix d'implémentation, généralement
de 30 secondes à 2 minutes. Le temps maximum d'attente est donc de
2 x MSL.
Il faut noter que le RTT est la somme des temps de transit entre
chaque routeur et du temps passé dans les diverses files
d'attente sur les routeurs.
Si on considère des délais de transmission de l'ordre de 500 ms (voire plus), un tel mécanisme est totalement inadapté au transfert de flux de données. On peut aussi remarquer qu'il sous-emploie la bande passante du réseau.
Cette attente de l'acquittement est pénalisante, sauf si on utilise un mécanisme de `` fenêtres glissantesVII9 '', comme le suggère la figure VII.07 :
figure VII.07 -- Principe de la fenêtre glissante
Elle change dynamiquement pour deux raisons :
Le datagramme IP a donc une taille égale au MSS augmentée
de 40 octets (20 + 20), en l'absence d'option de TCP.
Cette option apparait uniquement dans un paquet assorti
du drapeau SYN, donc à l'établissement de la
connexion.
Comme de bien entendu cette valeur est fortement
dépendante du support physique et plus particulièrement
du MTUVII12.
Sur de l'Ethernet la valeur maximale est
1500 - 2 x 20 = 1460, avec des trames
l'encapsultation 802.3 de l'IEEE un calcul similaire
conduit à une longueur de 1452 octets.
Chaque couche TCP envoie sa valeur de MSS
en même temps que le paquet de synchronisation, comme
une option de l'en-tête. Cette valeur
est calculée pour éviter absolument la fragmentation
de IP au départ des datagrammes.
figure VII.08 -- Détail de la fenêtre glissante
Le débit obtenu dépend de la taille de la fenêtre et bien sûr de la bande passante disponible. On conçoit aisément qu'entre la situation de la figure VII.06 et celle de la figure VII.07 l'usage de la bande passante s'améliore. Par contre l'agrandissement de la taille de la fenêtre ne se conçoit que jusqu'à une limite optimale au dela de laquelle des paquets sont perdus parcequ'envoyés trop rapidement pour être reçus par le destinataire. Or, pour fonctionner de manière optimale, TCP se doit de limiter au maximum la perte de paquets et donc leur réémission.
Cette taille limite optimale de la largeur de la fenêtre est, comme on peut le deviner, fonction de la bande passante théorique du réseau et surtout de son taux d'occupation instantanné. Cette dernière donnée est fluctuante, aussi TCP doit-il asservir continuement les tailles de fenêtre pour en tenir compte.
4 Compléments sur le fonctionnement de TCP
L'usage du protocole TCP diffère considérablement en fonction
des applications mises en
uvre et des réseaux à parcourir.
D'après [W. Richard Stevens], 10% des données échangées sur le réseau concernent des applications interactives et 90% des applications qui échangent des flux de données.
Si le protocole TCP reste le même pour tous, les algorithmes qui le pilotent s'ajustent en fonction de l'usage.
Pour le trafic en volume (`` bulk data ''), TCP tente d'utiliser des paquets les plus larges possibles pour maximiser le débit, alors que le trafic interactif utilise des paquets quasiment vides émis le plus souvent à la fréquence de frappe des utilisateurs ou au rythme des mouvements d'une souris.
Un exemple typique est celui de l'application telnet pour laquelle les caractères sont envoyés un à un dans un paquet différent, chaque caractère étant à l'origine de quatre paquets : émission d'un caractère, acquittement, retour de l'écho du caractère, acquittement.
Si ce comportement n'est absolument pas pénalisant sur un réseau rapide (LAN) par contre dès que la bande passante commence à être staturée il est préférable de regrouper un maximum d'octets (deux ou trois en pratique) dans un seul paquet pour en diminuer le nombre. C'est ce que fait l'algorithme de Nagle.
Pour réduire le trafic de ces `` tinygrams '' (RFC 896), l'algorithme de Nagle (1984) dit qu'une connexion TCP ne peut pas attendre plus d'un acquittement. Deux cas se présentent donc :
La qualité lent/rapide du réseau est calculée à partir du `` timestamp '' envoyé dans les options de TCP et qui est établi dès le premier échange (puis reévaluée statistiquement par la suite).
L'élégance de cet algorithme est qu'il est très simple et qu'il s'auto-régule suivant le délais de propagation.
Certaines applications désactivent cet algorithmeVII13 comme le serveur Apache ou le système de multi-fenêtrage X11.
Un paquet est reémis parcequ'il arrive corrompu ou parcequ'il
n'arrive jamais. Une réémission entraine un blocage de l'avancement de
la `` fenêtre glissante '', pénalisant pour le débit (cf conclusion
du chapitre page
).
TCP considère qu'un paquet perdu est la conséquence d'un routeur (ou plus) congestionné, c'est à dire pour lequel les files d'attente ne sont pas assez larges pour absorber tous les paquets entrantsVII14
Dans ce contexte, on comprend bien qu'il vaut mieux ne pas envoyer la totalité du contenu de la fenêtre dès le début de la connexion. Au contraire, TCP utilise un algorithme nommé `` slow start '' qui asservit l'émission des paquets au rythme de la réception de leurs acquittements, plutôt que de les émettre d'un coup aussi rapidement que l'autorise le système ou le débit théorique du réseau.
Ainsi, au début de chaque connexion ou après une période de calme (`` idle '') l'émetteur envoie un premier paquet de taille maximale (le `` mss '' du destinataire), et attend son acquittement. Quand celui-ci est reçu, il envoie deux paquets, puis quatre, et ainsi de suite jusqu'à atteindre l'ouverture maximale de la fenêtre.
Durant cette progression, si des paquets sont perdus, il y a congestion supposée sur l'un des routeurs franchis et l'ouverture de la fenêtre est réduite pour retrouver un débit qui minimise le taux de retransmission.
L'ouverture de la fenêtre est nommée fenêtre de congestion ou encore `` congestion window ''.
Le contrôle du flux évoqué précédement, pour éviter la congestion des routeurs, est implémenté à l'aide d'une variable (cwnd) nommée `` congestion window '' que l'on traduit par fenêtre de congestion.
Concrètement, le nombre maximum de segments de données ( x MSS en octets) que l'émetteur peut envoyer avant d'en recevoir le premier acquittement est le minimum entre cette variable (cwnd) et la taille de la fenêtre annoncée par le récepteur à chaque acquittement de paquet.
Le contenu de cette variable est piloté par les algorithmes de départ lent -- `` slow start '', voir 4.2 -- et d'évitement de congestion (`` congestion avoidance '') examiné ici.
La limite de croissance de la variable cwnd est la taille de la fenêtre annoncée par le récepteur. Une fois la capacité de débit maximale atteinte, si un paquet est perdu l'algorithme d'évitement de congestion en diminue linéairement la valeur (contrairement au `` slow start '' qui l'augmente exponentiellement).
Le premier exemple montre un échange de paquets de synchronisation (SYN) et de fin (FIN) entre la machine clnt.chezmoi et la machine srv.chezmoi. L'établissement de la connexion se fait à l'aide de la commande telnet sur le port discard (9) du serveur srv.chezmoi. La machine qui est à l'origine de l'établissement de la connexion est dite cliente, et celle qui est supposée prête à répondre, serveur. Pour information, le service discard peut être considéré comme l'équivalent du fichier /dev/null sur le réseau : les octets qu'on lui envoie sont oubliés (`` discard '').
L'utilisateur tape :
$ telnet srv discard Trying... Connected to srv.chezmoi. Escape character is '^]'. telnet> quit Connection closed.
Et l'outil d'analyse réseauVII15 permet la capture pour l'observation des échanges suivants. Le numéro qui figure en tête de chaque ligne a été ajouté manuellement, le nom de domaine `` chezmoi '' a été retiré, le tout pour faciliter la lecture :
0 13:52:30.274009 clnt.1159 > srv.discard: S 55104001:55104001(0)
win 8192 <mss 1460>
1 13:52:30.275114 srv.discard > clnt.1159: S 2072448001:2072448001(0)
ack 55104002 win 4096 <mss 1024>
2 13:52:30.275903 clnt.1159 > srv.discard: . ack 1 win 8192
3 13:52:33.456899 clnt.1159 > srv.discard: F 1:1(0) ack 1 win 8192
4 13:52:33.457559 srv.discard > clnt.1159: . ack 2 win 4096
5 13:52:33.458887 srv.discard > clnt.1159: F 1:1(0) ack 2 win 4096
6 13:52:33.459598 clnt.1159 > srv.discard: . ack 2 win 8192
Plusieurs remarques s'imposent :
À chaque échange la valeur entre parenthèses indique
le nombre d'octets échangés.
Le deuxième exemple montre une situation de transfert de fichier avec l'outil ftpVII16.
Il faut remarquer que l'établissement de la connexion TCP est ici à l'initiative du serveur, ce qui peut laisser le lecteur perplexe...L'explication est simple. En fait le protocole ftp fonctionne avec deux connexions TCP, la première, non montrée ici, est établie du client vers le serveur, supposé à l'écoute sur le port 21. Elle sert au client pour assurer le contrôle du transfert. Lorsqu'un transfert de fichier est demandé via cette première connexion, le serveur établit une connexion temporaire vers le client. C'est cette connexion que nous examinons ici. Elle est cloturée dès que le dernier octet demandé est transférré.
Extrait du fichier /etc/services, concernant ftp :
ftp-data 20/tcp #File Transfer [Default Data] ftp-data 20/udp #File Transfer [Default Data] ftp 21/tcp #File Transfer [Control] ftp 21/udp #File Transfer [Control]
Dans cette exemple nous pouvons suivre le fonctionnement du mécanisme des fenêtres glissantes. Les lignes ont été numérotées manuellement et la date associée à chaque paquet supprimée.
0 srv.20 > clnt.1158: S 1469312001:1469312001(0)
win 4096 <mss 1024> [tos 0x8]
1 clnt.1158 > srv.20: S 53888001:53888001(0) ack 1469312002
win 8192 <mss 1460>
2 srv.20 > clnt.1158: . ack 1 win 4096 [tos 0x8]
3 srv.20 > clnt.1158: P 1:1025(1024) ack 1 win 4096 [tos 0x8]
4 clnt.1158 > srv.20: . ack 1025 win 8192
5 srv.20 > clnt.1158: . 1025:2049(1024) ack 1 win 4096 [tos 0x8]
6 srv.20 > clnt.1158: . 2049:3073(1024) ack 1 win 4096 [tos 0x8]
7 clnt.1158 > srv.20: . ack 3073 win 8192
8 srv.20 > clnt.1158: . 3073:4097(1024) ack 1 win 4096 [tos 0x8]
9 srv.20 > clnt.1158: P 4097:5121(1024) ack 1 win 4096 [tos 0x8]
10 srv.20 > clnt.1158: P 5121:6145(1024) ack 1 win 4096 [tos 0x8]
11 clnt.1158 > srv.20: . ack 5121 win 8192
12 srv.20 > clnt.1158: P 6145:7169(1024) ack 1 win 4096 [tos 0x8]
13 srv.20 > clnt.1158: P 7169:8193(1024) ack 1 win 4096 [tos 0x8]
14 clnt.1158 > srv.20: . ack 7169 win 8192
15 srv.20 > clnt.1158: P 8193:9217(1024) ack 1 win 4096 [tos 0x8]
16 srv.20 > clnt.1158: P 9217:10241(1024) ack 1 win 4096 [tos 0x8]
17 clnt.1158 > srv.20: . ack 9217 win 8192
18 srv.20 > clnt.1158: P 10241:11265(1024) ack 1 win 4096 [tos 0x8]
19 srv.20 > clnt.1158: P 11265:12289(1024) ack 1 win 4096 [tos 0x8]
20 clnt.1158 > srv.20: . ack 11265 win 8192
... ... ...
21 srv.20 > clnt.1158: P 1178625:1179649(1024) ack 1 win 4096 [tos 0x8]
22 clnt.1158 > srv.20: . ack 1178625 win 8192
23 srv.20 > clnt.1158: P 1212417:1213441(1024) ack 1 win 4096 [tos 0x8]
24 srv.20 > clnt.1158: P 1213441:1214465(1024) ack 1 win 4096 [tos 0x8]
25 srv.20 > clnt.1158: P 1214465:1215489(1024) ack 1 win 4096 [tos 0x8]
26 clnt.1158 > srv.20: . ack 1213441 win 8192
27 clnt.1158 > srv.20: . ack 1215489 win 8192
28 srv.20 > clnt.1158: P 1215489:1215738(249) ack 1 win 4096 [tos 0x8]
29 srv.20 > clnt.1158: F 1215738:1215738(0) ack 1 win 4096 [tos 0x8]
30 clnt.1158 > srv.20: . ack 1215739 win 8192
31 clnt.1158 > srv.20: F 1:1(0) ack 1215739 win 8192
32 srv.20 > clnt.1158: . ack 2 win 4096 [tos 0x8]
Remarques :
Le positionnement de ce drapeau est à l'initiative de la
couche TCP
'emettrice et non à l'application.
).
figure VII.09 -- Exemple de fenêtre glissante
Le protocole TCP a été conçu à une époque où l'usage de la commande ligne était universel, et les applications graphiques utilisant le réseau très rares...!
Une trentaine d'années plus tard, on peut faire le constat pratiquement inverse : les applications textes interactives (beaucoup de petits messages applicatifs) disparaissent au profit d'applications moins interactives et qui sont plus orientées flux de données (vidéo, audio, téléphonie...) avec des échanges plus volumineux et des besoins en transport qui ont évolué.
Le principe de la fenêtre glissante, si performant qu'il soit pour assurer le bon acheminement des données, est bloquant pour certaines applications comme le web. En effet, si le paquet de données de tête n'est pas acquitté, les suivants, même reçus, sont en attente avant d'être délivrés à l'application.
Si la réponse comporte par exemple de nombreuses zones graphiques et textuelles différentes la fluidité de la consultation est considérablement amoindrie, et tenter de la compenser en établissant un grand nombre de connexions simultannées pour récupérer individuellement les éléments de la page, consomme beaucoup de ressources système et réseaux (celles de l'établissement des connexions) qui ne compense que partiellement ce soucis.
L'indépendance de TCP vis à vis de la structure des données est également un inconvénient dans certaines applications comme la téléphonie pour laquelle la notion de messages successifs est bien plus intéressante.
Depuis le début des années 2000 l'IETF met au point le protocole SCTP qui fournit des services similaires à ceux de TCP, en abandonne certains et apporte les nouvelles fonctionnalités adaptées aux nouveaux besoins.
Sans oublier :
Next: B Réseaux IP avancés
Up: A Introduction à la
Previous: VI Protocole UDP
Contents
Index
François Laissus
2009-02-27