Les protocoles de la couche transport (UDP, TCP)
 

    Menu
 
 
 
        Après avoir vu le protocole IP et ses caractéristiques, il est temps de nous intéresser à un protocole de niveau supérieur, qui s’occupe du transport des données. Il faut un protocole capable de faire le lien entre la délivrance des datagrammes à la bonne machine et fournir les bonnes données à la bonne application pour que la liaison soit correctement établie. C’est le rôle des protocoles de transport. La couche IP doit connaître quel protocole de transport est utilisé pour le délivrer au bon. Le champ PROTOCOL dans l’en-tête IP est prévu à cet effet. Une fois que le protocole de transport reçoit les données, il doit savoir vers quelle application (cliente ou serveur) l’envoyer. Or, nous savons que lorsqu’une application cliente a besoin de joindre une application serveur, elle ouvre un port. Grâce à ce port, la couche transport va identifier l’application serveur concernée, et lui envoyer ses données. Pour pouvoir communiquer avec une application (cliente ou serveur), il faut donc connaître non seulement son adresse IP, mais aussi son numéro de port sur lequel la joindre.
 
Remarque : Alors qu’il est impossible de faire coexister deux services sur un même port, un service peut faire l’utilisation de plusieurs protocoles sur un même port. Dans ce cas la paire port + protocole permet sans ambiguïté de faire référence à la bonne session concernée (les serveurs peuvent entretenir plusieurs sessions utilisant des protocoles différents avec une même machine).
 
            A.   Le protocole UDP (User Datagram Protocol)

 

    Commençons par le protocole de transport le plus simple : UDP. Un paquet UDP est encapsulé dans les DATAS d’un datagramme IP (comme un message ICMP), et peut établir une communication directement avec le serveur :
 
 
 
 
 
 
Lorsqu’une machine désire communiquer avec une autre par UDP, elle envoie directement les données sans demande. Ce protocole est par exemple utilisé par les logiciels de chat tels que ICQ, MSN Messenger… La personne souhaitant alors dialoguer avec une autre envoie directement son message par le protocole UDP : la machine peut refuser le paquet ou l’accepter, sans en informer l’émetteur.
Pour bien comprendre les caractéristiques d’UDP, commençons par étudier son en-tête :
 
 
 
 
 
 
Les informations sont :
Ø      UDP SOURCE PORT : le port de la machine émettrice, pour que la machine réceptrice puisse joindre le bon port lors de la réponse éventuelle (non obligatoire).
Ø      UDP DESTINATION PORT : le port que l’on souhaite joindre sur la machine distante.
Ø      MESSAGE LENGTH : C’est la taille du paquet (en-tête + DATAS)
Ø      CHECKSUM : Ce champ non obligatoire permet de contrôler l’intégrité des données.
 
Nous pouvons nous rendre compte qu’un paquet UDP gère les ports, mais c’est tout !!! Il offre le strict minimum. Ici, aucune garantie que les données soient transmises dans leur intégralité, ni même dans le bon ordre. Il n’y a aucun retours à l’émetteur pour le renseigner sur d’éventuels erreurs de transmission. En fait, tous les défauts reconnus précédemment à IP, sont applicables à IP. C’est pourquoi on défini souvent UDP comme un protocole « non connecté » car en fait il n’y a pas besoin d’établir de connection avec le serveur pour qu’il accepte nos données (soit il les accepte, soit il les refuse, sans échange précédent). L’intérêt d’UDP est qu’il est extrêmement léger : son en-tête est très petite. Il va donc être d’une grande utilité pour les applications de chat (ICQ, MSN Messenger…), de même que pour les jeux en réseau où il faut privilégier la rapidité de transmission.
 
            B.   Le protocole TCP (Transport Control Protocol)

 

    Nous venons de voir les caractéristiques du protocole UDP, et nous pouvons en conclure qu’il ne doit en aucun cas être utilisé lorsque l’intégrité des données, et leur sécurité est une priorité. C’est pourquoi le protocole TCP est majoritairement utilisé aujourd’hui dans les communications réseaux et sur l’Internet. En effet, TCP est beaucoup plus élaboré qu’UDP : il a comme caractéristiques principales :
 
1.      Il permet le contrôle du bon acheminement des données pour fiabiliser la communication. De plus, les données sont acquittées d’un bout à l’autre de la communication par les deux correspondants.
 
2.      Contrairement à UDP qui est en mode « non connecté » TCP est en mode « connecté ». Un circuit virtuel fermé est établi entre les deux correspondants. Pour que ce circuit virtuel soit établi, il faut : l’adresse IP source, l’adresse IP distante, le port source, le port distant, ainsi que le protocole de transport. Ici, à l’opposition d’UDP, toutes ces informations sont obligatoires. Les caractéristiques d’une communication utilisant TCP pour le transport sont :
Ø      Toute communication entre deux machine commence par une mise au point de la connection : l’un prévient l’autre qu’il a l’intention de se connecter : l’autre peut la refuser ou l’accepter (contrairement à UDP où aucune demande n’est effectuée).
Ø      Les deux intervenants se mettent d’accord sur les paramètres de la connection : synchronisation des systèmes et des applications.
Ø      Une fois la connection établie, l’un prévient l’autre que la communication peut débuter.
Ø      Pendant la communication, les couches transport des deux correspondants communiquent entre elles pour s’assurer de la livraison correcte des données.
 
3.      TCP peut mémoriser les données :
Ø      La taille des données transmises n’est absolument pas fixe : de 0 octet à plusieurs millions.
Ø      A la réception, les données sont délivrées comme elles ont été transmises.
Ø      Comme IP, TCP peut fragmenter les paquets pour s’adapter au réseau traversé. Il doit alors réassembler les données et conserver leur ordre. Pour ce faire, il doit les conserver en mémoire, pour les restituer dans le bon ordre à l’application distante.
4.      TCP est indépendant vis-à-vis de la couche application : il ne s’occupe en rien du type de données transmises.
 
5.      La communication par TCP peut être qualifiée de Full duplex : les opérations et de lecture sont totalement indépendantes d’un bout à l’autre de la connection. De plus, un côté peut fermer la connection, alors que l’autre est encore actif : la fin d’une connection doit être acceptée par les deux parties.
 
Examinons maintenant la composition d’un en-tête IP :
 
 
 
 
 
 
Les paramètres sont :
Ø      TCP PORT SOURCE : le port de la machine émettrice, pour que la machine distante puisse répondre.
Ø      TCP DESTINATION PORT : le port que nous souhaitons joindre.
Ø      SEQUENCE NUMBER : nombre de 32 bits qui identifie la position des données que nous envoyons. A chaque paquet supplémentaire transmit, ce nombre est incrémenté du nombre représentant la taille des données émises. Lors de l’établissement d’une connection, ce champ a une valeur non nulle et très difficilement prévisible de préférence (des hackers peuvent arriver à désynchroniser une connection TCP si ils arrivent à prévoir la valeur de ce champ, en introduisant leur propres paquets usurpés). Cette valeur de départ est appelée ISN (Initial Sequence Number), car c’est elle qui sert à établir la connection. Il faut remarquer que sur Windows 95, 98, NT 4 et précédents, les ISN étaient générés de façon linéaire (compteur s’incrémentant toutes les 4 milli secondes), d’où un important risque de piratage, puisque ridiculement prévisibles.
Ø      ACKNOWLEDGEMENT NUMBER : Ce numéro sert à identifier la position des données que nous recevons. (doit être accompagné du flag ACK), il acquitte aussi les envois de l’autre machine.
Ø      OFFSET : il permet s’il y a des options de faire se déplacer la couche TCP à l’emplacement de ces options.
Ø      RESERVED : ces 6 bits ne sont pas utilisés : ils sont réservés à un usage futur.
Ø      CODE : ce champ de 6 bits représente en fait 6 options. Chaque bit est appelé flag (drapeau) :
o       URG : définit le paquet comme étant urgent (le champ URGENT POINTER doit être utilisé).
o       ACK : sert à répondre à l’affirmative à un paquet de type SYN, et lors de la communication, à acquitter les données (le champ ACKNOWLEDGEMENT NUMBER doit être utilisé).
o       PSH : sert à forcer les données latentes d’une communication à être émises immédiatement.
o       RST : Sert à répondre à la négative à un paquet de type SYN, ou à mettre fin d’une façon brutale une connection.
o       SYN : sert à demander s’il est possible d’ouvrir une communication avec une machine distante (un ISN doit être présent).
o       FIN : comme son nom l’indique, il permet de terminer une connection. Contrairement à RST qui la termine de façon brutale, FIN la termine plus proprement. Fin intervient lorsque l’émetteur des données a fini d’émettre.
Ø      WINDOW : c’est la mémoire en octets que TCP doit utiliser pour gérer la communication. Cette mémoire sert à gérer le flux de données d’un bout à l’autre de la connection.
Ø      CHECKSUM : Ce champ permet de vérifier l’intégrité de l’en-tête et des données.
Ø      OPTIONS : Lorsque l’OFFSET est supérieur à 5, les options sont repérées par TCP :
o        MSS (Maximum Segment Size) : c’est la taille maximale de données applicatives (sans l’en-tête) que l’émetteur accepte de recevoir. Lors de l’établissement d’une connection, les MSS sont synchronisés.
o       TIMESTAMP : pour calculer la durée d’un allé et retour.
o       WSCALE : pour augmenter la taille de la window si le champ WINDOW n’est pas assez grand (de 2^WSCALE).
o       NOP : Cette option codée sur 1 octet peut être utilisée entre deux options, par exemple pour aligner le début d'une option sur un début de mot de 16 bits. L'utilisation de ce séparateur n'est pas une obligation.
Ø      PADDING : pour compléter le mot de 4 octets comportant les options.
Ø      DATAS : a une valeur nulle lors de l’établissement de la connection, mais contient les données de la couche application par la suite.
 
Remarque : Les options peuvent avoir une taille variable. Elles doivent avoir une taille multiple de 32 bits. Ainsi, par exemple, si les options ont une taille de 180 octets, nous complèterons le champ PADDING de 12 bits à 0 pour aligner l’en-tête TCP sur un multiple de 32 bits.
 
            C.      Examen d’une connexion TCP

1.       Établissement d’une connexion

TCP dispose d’un mode de connexion assez fiable et très particulier. En effet, pour qu’une connexion soit établie entre deux machines, il faut que les deux soient d’accord sur l’établissement de la connexion. Le principe est le suivant :

Ø       La machine dite cliente (qui désire se connecter, et qui a l’initiative de la connexion) va formuler une demande à la machine dite serveur (qui fait tourner des services attendant des demandes de connexion). Pour cela, elle va envoyer un paquet vide dans lequel sera activé le flag SYN Dans l’en-tête TCP au serveur auquel elle souhaite se connecter. Pour accompagner le flag SYN, elle indiquera aussi son ISN, que l’on nommera x.

Ø       Lorsque le serveur reçoit la demande, deux possibilités s’offrent à lui : soit il la refuse : il le fait savoir au client en lui envoyant un paquet TCP avec le flag RST d’activé. Ou alors, il accepte la demande. Il va alors répondre par un paquet avec le flag ACK (il accepte), et également acquitter le paquet précédent (la demande du client). Pour acquitter ce paquet, il va mettre dans le champ ACKNOWLEDGEMENT NUMBER l’ISN du client, incrémenté de 1 : x + 1. La connexion s’établissant dans les deux sens, il va lui aussi formuler sa demande en activant le flag SYN et en fournissant son propre ISN : y.

Ø       Le client va alors accepter la demande du serveur. Pour cela, il va activer le flag ACK, et également acquitter le paquet précédent en incrémentant l’ISN du serveur de 1 : y + 1. De même, pour identifier ce paquet, il va mettre comme numéro de séquence son ISN + 1.

 

Ce mode de connexion est appelé le « three hand shake » : poignée de main en trois temps. Une fois cette procédure achevée, les deux machines sont connectées et vont pouvoir échanger des informations.

On peut résumer cela par ce schéma :

 
Client  à           SYN seq = x (ISN-Client)    à           Serveur
Serveur    à   ACK num = x + 1 | SYN seq = y (ISN-Serveur) à    Client
Client     à   ACK num = y + 1 | seq = x + 1     à           Serveur

 

2.       Mécanisme de contrôle du transport et acquittement

Pour transmettre des données de façon assez sure, TCP comporte un mécanisme d’acquittement, comme nous avons pu l’entrevoir dans la partie précédente. A chaque envoi de données d’une machine, l’autre répond en acquittant les données, et ainsi l’informant de la bonne transmission. En fait à chaque envoi de paquet, une horloge se déclenche. Si l’acquittement ne parvient pas avant que l’horloge ait atteint une certaine valeur, le paquet est retransmit. Il faut donc que les machines conservent une partie de leurs paquets pour être capable de les retransmettre si un problème survient.

Il faut également donner quelques précisions sur un mécanisme appelé de « fenêtre glissante ». En fait, à chaque paquet envoyé, la machine réceptrice ne va pas envoyer d’acquittement : cela surchargerait inutilement le réseau. Comme nous l’avons vu dans la description de l’en-tête, il existe un champ WINDOW, qui permet d’informer l’autre machine du nombre de données que l’on est capable de recevoir sans acquittement. Ce principe évite aussi d’autres problèmes. Il est normal qu’une machine réceptrice mette plus de temps à traiter les données que la machine émettrice. Il ne faut donc pas que la machine émettrice envoie trop de paquets en très peu de temps. Cela provoquerait la perte de données. Grâce à ce mécanisme, la machine émettrice envoie un certain nombre d’octets, et attend l’acquittement de la machine réceptrice pour continuer son envoi.

 

Après une connexion, la fin de l’établissement de la connection, la communication se passe ainsi :

Ø       Le client souhaite envoyer des données (par exemple 40 octets) au serveur. Le serveur a défini une taille de WINDOW de 20 octets (cette mise au point des WINDOW s’est effectuée pendant la connexion, et peut être remise à jour à chaque paquet envoyé par l’une ou l’autre des parties). Le client envoie des paquets contenant 10 octets de données. Il va alors former 4 paquets contenant 10 octets de données chacun. Il va ensuite envoyer le premier paquet. Ce paquet aura comme numéro de séquence ISN-Client+1. Le premier octet de données contenu dans un paquet a toujours comme numéro de séquence ISN-Client+1. Il faut noter qu’une fois la connexion établie, le flag ACK, et le numéro d’acquittement sont toujours renseignés. Le client mettra alors dans ce paquet le flag ACK à 1, et comme numéro d’acquittement le prochain numéro de séquence du serveur que le client s’attend à recevoir. Soit ici ISN-Serveur+1 (en effet, dans cet exemple, le serveur n’envoie pas de données).

Ø       Comme le serveur est capable de recevoir 20 octets de données sans acquittement, le client va envoyer un deuxième paquet contenant également 10 octets de données. Ce paquet aura comme numéro de séquence (ISN-Client+1)+10. En effet à ce moment, le client a envoyé 10 octets de plus, donc le numéro de séquence sera incrémenté de 10. Ce paquet contiendra également le flag ACK et comme numéro d’acquittement ISN-Serveur+1

Ø       Une fois ces deux paquets envoyés, le client a envoyé au tampon du serveur la taille de la fenêtre. Il n’envoie alors plus de données, et attend l’acquittement du serveur. Le serveur acquitte les données qu’il a reçues en envoyant un paquet sans données, contenant comme seul flag : ACK. Le numéro d’acquittement sera alors ((ISN-Client+1)+10)+10, puisque le client s’attend à recevoir le 21ème octet de donnée, dans le prochain paquet. Le paquet contiendra également comme numéro de séquence ISN-Serveur+1, le serveur n’envoyant pas de données.

Ø       Ce processus va alors continuer jusqu’à ce que le client n’ait plus de données à émettre, et que le serveur ait envoyé son dernier acquittement.

 

Nous pouvons résumer le processus comme suit, en reprenant une connection du paragraphe précédent :

 
Client à      ACK num = y + 1 | seq = x + 1 | Data = 10      à   Serveur
 Client à     ACK num = y + 1 | seq = (x+1) + datalength (10)    à     Serveur
 Serveur  à    ACK num = ((x+1)+10) + 10 | seq = y + 1         à   Client
Etc.

 

Remarque : En fait, ce processus a été grandement simplifié. Un transfert de données s’effectue à l’aide d’un protocole applicatif tel que ftp, mais ce schéma reflète exactement le mécanisme réel. Il faut ajouter que lorsque le client a fini d’émettre, il va utiliser le flag PUSH, pour que la machine distante transmette immédiatement à l’application serveur les données. Ainsi, le serveur sait lorsqu’un segment de données est terminé (mais pas forcément la connection).

 

3.       Clôture d’une connection

Nous avons vu comment se déroule une connexion, ainsi qu’un échange de données. Il faut maintenant aborder un point important : la clôture de connection. Celle-ci peut se dérouler de deux manières fondamentalement différentes.

 

1.        Clôture cordiale

Ce principe est le même qu’une connection. Pour établir la connection, il faut que les deux parties acceptent de se connecter à l’autre : la connection s’effectue dans les deux sens. Dans le même principe, une clôture de connection s’effectue dans les deux sens. Le mécanisme est le suivant :

Ø       Le client a fini d’émettre les données en direction du serveur. Il va alors le signaler au serveur en lui envoyant un paquet vide avec le flag FIN activé. Ce paquet est vide, mais il contiendra le numéro de séquence précédent, incrémenté de la taille des données du paquet précédent (en effet le client n’envoie plus de données, mais il faut différencier le paquet-ci du paquet précédent, donc il aura comme position celle venant juste après les données). Il acceptera également le précédent paquet du serveur, avec le flag ACK, ainsi que le numéro d’acquittement ayant pour valeur la même que le précédent paquet : encore une fois, le serveur n’a jamais envoyé de données.

Ø       Le serveur, à réception de ce paquet va alors l’acquitter. Il va donc envoyer un paquet ayant le flag ACK et le numéro d’acquittement sera le précédent numéro de séquence envoyé par le client incrémenté de 1. En effet, il faut différencier cet acquittement des précédents, donc comme dans la phase de connection, on l’incrémente de 1. Le numéro de séquence sera le même que le précédent, puisqu’il n’y a pas de données présentes.

Ø       Le serveur va alors faire savoir au client que lui aussi ferme la connection, avec un paquet FIN (le flag ACK est aussi positionné), ayant un numéro de séquence et d’acquittement identique par rapport au précédent (il n’y a pas eu d’envoi de données).

Ø       Le client va alors accepter ce paquet avec un paquet comportant le flag ACK et un numéro d’acquittement ayant pour valeur celle du dernier numéro de séquence envoyé par le serveur, incrémenté de 1. Il contiendra également un numéro de séquence : le même que le précédent paquet qu’il a envoyé incrémenté de 1.

 

C’est donc un mécanisme en 4 étapes qui permet de clôturer une connection.

 

Résumons cette phase :

 

 Client   à           ACK num = j | seq = k | FIN    à     Serveur

Serveur  à           ACK num = k + 1 | seq = j    à  Client

 Serveur  à           ACK num = k + 1 | seq = j | FIN   à   Client

Client  à           ACK num = j + 1 | seq = k + 1       à  Serveur

 

 

Remarque : Vous pouvez vous demander pourquoi le serveur n’émet pas juste après avoir reçu le paquet FIN du client un paquet ACK+FIN pour signaler en un seul paquet qu’il accepte la fin de connexion du client et que lui aussi décide de fermer sa connexion. Seulement pour simplifier l’étude, nous avions un envoi de données unidirectionnel. La fermeture s’est donc effectuée canoniquement. Mais il se peut, lors d’une communication bidirectionnelle, que l’une des parties ait fini d’émettre avant l’autre. Elle va alors envoyer un paquet FIN pour faire savoir à l’autre qu’elle a fini d’émettre. La machine réceptrice du paquet FIN, va acquitter le paquet, puis continuer ses envois sans que cela ne gêne l’envoi. Il faut noter que la machine réceptrice ne peut plus envoyer de données, puisqu’elle a envoyé le paquet FIN : la connection n’est plus établie que dans un sens. Une fois que toutes les données vont être envoyées, la machine finissant son envoi va alors le signaler à l’autre par un paquet FIN, que la machine destinataire acquittera. Ceci marque la fin de la connection. Donc les fermetures respectives doivent se dérouler en deux échanges chacune pour garantir un fermeture de connexion « propre ».

 

2.        Clôture brutale

Ce type de fermeture est exceptionnel, et ne doit arriver le moins possible. Il faut préférer les fermetures cordiales. Mais dans certains cas elles sont impossibles. Ce principe consiste à envoyer un paquet avec le flag RST. Ceci aura pour effet de réinitialiser immédiatement la connection.

B.      Conclusion sur le transport

Après avoir observé les deux protocoles de transport radicalement différents que sont TCP et UDP, nous pouvons conclure que leur choix dépend de ce qu’un développeur de logiciel souhaite : s’il souhaite de la sécurité (authentification + confidentialité) soit il veut un protocole applicatif relativement simple et léger, dans ce il fait confiance au mode de connection TCP. Ou alors, il opte pour UDP, dans ce cas il développe un protocole applicatif robuste, capable de gérer les différents points de sécurité. Au contraire, s’il n’a que faire de la sécurité, que seul compte la rapidité et le faible coût en bande passante, alors il choisira UDP sans aucun doute.

Menu