Les paquets TCP peuvent-ils arriver au récepteur par morceaux?)
Par exemple, si j'envoie 20 octets en utilisant TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, pas 10 octets puis 10 octets environ?)
Et la même question pour le protocole UDP.
Je sais que UDP n'est pas fiable et les paquets ne peuvent pas arriver du tout ou arriver dans un ordre différent, mais qu'en est-il d'un seul paquet? S'il arrive, puis-je être sûr que c'est un paquet complet, pas un morceau?
les paquets TCP arrivent-ils par morceaux au récepteur?
Oui. IP prend en charge la fragmentation, bien que TCP essaie généralement de déterminer le chemin MTU et de garder ses paquets plus petits que cela pour des raisons de performances. La fragmentation augmente le taux de perte de datagrammes de manière catastrophique. Si un chemin a une perte de paquets de 10% taux, la fragmentation d'un datagramme en deux paquets rend le taux de perte de datagramme près de 20% (si l'un ou l'autre des paquets est perdu, le datagramme est perdu).
Cependant, vous n'avez pas à vous en préoccuper, et la couche TCP. La couche IP réassemble les paquets en datagrammes entiers.
Par exemple: si j'envoie 20 octets en utilisant TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, pas 10 octets puis 10 octets environ?)
Non, mais cela n'a rien à voir avec les paquets. TCP est, fondamentalement, un protocole de flux d'octets qui ne préserve pas les limites des messages d'application.
Et la même question pour le protocole UDP. Je sais que UDP n'est pas fiable et les paquets ne peuvent pas arriver du tout ou arriver dans un ordre différent,
Il en va de même pour TCP. Les paquets sont des paquets. La différence est que TCP a des tentatives et des réorganisations intégrées dans le protocole alors que UDP ne le fait pas.
mais qu'en est-il d'un paquet? S'il arrive, puis-je être sûr que c'est un paquet complet, pas un morceau?
Non, mais ce n'est pas votre problème. Le protocole UDP gère le réassemblage des datagrammes. Cela fait partie de son travail. (En réalité, le protocole IP fait cela pour le protocole UDP, donc UDP le fait simplement en étant superposé sur IP.) Si un datagramme est divisé en deux paquets, le protocole IP le réassemble pour le protocole UDP, donc vous verra les données complètes.
Vous ne pouvez pas être sûr qu'ils arrivent vraiment physiquement à la fois. Les couches de liaison de données sous TCP/UDP peuvent diviser votre paquet si elles le souhaitent. Surtout si vous envoyez des données sur Internet ou sur des réseaux hors de votre contrôle, il est difficile de le prévoir.
Mais peu importe si les données arrivent dans un paquet ou plusieurs paquets au niveau du récepteur. L'OS devrait résumer la concaténation de ces paquets, donc pour votre application, il semble toujours que tout est arrivé en même temps. Donc, sauf si vous êtes un pirate du noyau, dans la plupart des cas, vous n'avez pas à vous inquiéter si ces données sont transférées dans un ou plusieurs paquets.
Pour UDP, le système d'exploitation fera également une certaine abstraction, de sorte que l'application qui reçoit les données n'a pas à savoir dans combien de paquets les données ont été transmises. Mais la différence avec TCP est qu'il n'y a aucune garantie que les données arrivent réellement. Il est également possible que les données soient divisées en plusieurs paquets, et certains d'entre eux arrivent et d'autres non. Pour l'application réceptrice, cela ressemble de toute façon à un flux de données, qu'il soit complet ou non.
Exemples. Les blocs de caractères contigus correspondent aux appels send ():
TCP:
Send: AA BBBB CCC DDDDDD E Recv: A ABB B BCC CDDD DDDE
Toutes les données envoyées sont reçues dans l'ordre, mais pas nécessairement dans les mêmes morceaux.
UDP:
Send: AA BBBB CCC DDDDDD E Recv: CCC AA E
Les données ne sont pas nécessairement dans le même ordre, et pas nécessairement reçues du tout, mais les messages sont conservés dans leur intégralité.
Par exemple: si j'envoie 20 octets en utilisant TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, pas 10 octets puis 10 octets environ?)
Non, TCP est un protocole de flux, il garde les données en ordre mais il ne les regroupe pas par message. D'un autre côté, UDP est orienté message, mais peu fiable. SCTP a le meilleur des deux mondes mais n'est pas utilisable nativement car les NATs brisent Internet.
Il y a une certaine assurance que si vous envoyez 20 octets au tout début d'un flux TCP, il n'arrivera pas sous la forme de deux pièces de 10 octets. En effet, TCP = la pile n'enverra pas de si petits segments: il y a une taille MTU minimale. Cependant, si l'envoi se situe n'importe où au milieu d'un flux, tous les paris sont désactivés. Il se peut que votre pile de protocole prenne 10 octets de données à remplir un segment et l'envoyer, puis dix octets suivants aller à un autre segment.
Votre pile de protocoles divise les données en morceaux et les place dans une file d'attente. Les tailles de blocs sont basées sur le chemin MTU. Si vous effectuez une opération d'envoi et qu'il y a toujours des données en attente, la pile de protocoles examine généralement le segment qui se trouve à la fin de la file d'attente et voit s'il y a de la place dans ce segment pour ajouter plus de données. La pièce peut être aussi petite qu'un octet, donc même un envoi de deux octets peut être divisé en deux.
À l'autre extrémité, la segmentation des données signifie qu'il peut y avoir des lectures partielles. Une opération de réception peut potentiellement se réveiller et obtenir des données lorsque seulement un segment arrive. Dans l'API sockets largement implémentée, un appel de réception peut demander 20 octets, mais il peut revenir avec 10. Bien sûr, une couche tampon peut être construite dessus qui bloquera jusqu'à ce que 20 octets soient reçus ou que la connexion soit interrompue. Dans le monde POSIX, cette API peut être les flux d'E/S standard: vous pouvez fdopen
un descripteur de socket pour obtenir un FILE *
stream, et vous pouvez utiliser fread
dessus pour remplir un tampon de telle sorte que la demande complète soit satisfaite avec autant d'appels read
qu'il le faut.
Les datagrammes UDP encadrent les données. Chaque appel d'envoi génère un datagramme (mais voir ci-dessous à propos du bouchage). L'autre côté reçoit un datagramme complet (et, dans l'API socket, il doit spécifier un tampon suffisamment grand pour le contenir, sinon le datagramme sera tronqué). Les gros datagrammes sont fragmentés par fragmentation IP et sont réassemblés de manière transparente aux applications. Si un fragment manque, le datagramme entier est perdu; il n'y a aucun moyen de lire des données partielles dans cette situation.
Il existe des extensions à l'interface permettant plusieurs opérations pour spécifier un seul datagramme. Sous Linux, un socket peut être "bouché" (empêché d'envoyer). Pendant le bouchage, les données écrites sont assemblées en une seule unité. Ensuite, lorsque le socket est "débouché", un seul datagramme peut être envoyé.