Les paquets TCP et UDP peuvent-ils être divisés en morceaux?

41

Les paquets TCP peuvent-ils arriver au destinataire par morceaux?

Par exemple, si j’envoie 20 octets en utilisant le protocole TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, et non 10 octets, puis 10 autres octets ou plus?

Et la même question pour le protocole UDP.
Je sais que UDP n'est pas fiable et que 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?

iamnp
la source
7
Une précision: cela s'appelle un segment TCP et un datagramme UDP. Ce ne sont pas des paquets. TCP = Segment, UDP = Datagram, IP = Paquet, Ethernet = Frame, Toutes les autres couches (AFAIK) sont simplement appelées PDU (unités de données de protocole).
joeqwerty

Réponses:

33

les paquets TCP peuvent-ils arriver au destinataire par morceaux?

Oui. IP prend en charge la fragmentation, bien que TCP tente généralement de déterminer le MTU du chemin et de garder ses paquets plus petits que cela pour des raisons de performances. La fragmentation augmente le taux de perte de datagramme de façon catastrophique. Si un chemin a un taux de perte de paquets de 10%, la fragmentation d'un datagramme en deux paquets augmente le taux de perte de datagramme à près de 20%. (Si l'un des paquets est perdu, le datagramme est perdu.)

Cependant, vous n'avez pas à vous en préoccuper, pas plus que la couche TCP. La couche IP rassemble les paquets en datagrammes entiers.

Exemple: si j'envoie 20 octets en utilisant le protocole TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, et non 10 octets, puis 10 autres octets ou plus?

Non, mais cela n'a rien à voir avec les paquets. Le protocole 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 qu'UDP n'est pas fiable et que les paquets ne peuvent pas arriver du tout ou arriver dans un ordre différent,

La même chose est vraie pour TCP. Les paquets sont des paquets. La différence est que TCP a des tentatives et des réordonnances intégrées au protocole, contrairement à UDP.

mais qu'en est-il 1 paquet? S'il arrive, puis-je être sûr que c'est un paquet complet, pas un morceau?

Non, mais ce n'est pas ton problème. Le protocole UDP gère le réassemblage du datagramme. Cela fait partie de son travail. (En réalité, le protocole IP le fait pour le protocole UDP. UDP le fait simplement en se superposant au-dessus d'IP.) Si un datagramme est divisé en deux paquets, le protocole IP le réassemblera pour le protocole UDP. verra les données complètes.

David Schwartz
la source
10
Cela vaut peut-être la peine de préciser le dernier bit pour les lecteurs novices: vous verrez les données complètes du datagramme en question . Si l'un des paquets divisés est perdu, le datagramme est perdu et la couche UDP ne le saura jamais. Tant que tous les paquets du datagramme sont reçus, ils seront assemblés au niveau de la couche IP puis transmis à la couche UDP. Cela n'exclut pas la possibilité de manquer des "morceaux" dans le flux de données. Ne pas être un pédant, mais quand j'ai appris ce truc, je n'ai pas expliqué la différence entre une perte d'IP et une perte d'UDP avant la deuxième ou la troisième traversée du manuel.
Justin ᚅᚔᚈᚄᚒᚔ
20

Vous ne pouvez pas être sûr qu'ils arrivent vraiment physiquement à la fois. Les couches de liaison de données situées sous TCP / UDP peuvent scinder votre paquet si elles le souhaitent. Surtout si vous envoyez des données via Internet ou des réseaux indépendants de votre volonté, il est difficile de prédire cela.

Mais peu importe si les données arrivent en un ou plusieurs paquets chez le destinataire. Le système d'exploitation doit extraire la concaténation de ces paquets. Par conséquent, pour votre application, tout se passe comme si tout était arrivé en même temps. Donc, à moins que vous ne soyez 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 effectue également des abstractions. Ainsi, l'application qui reçoit les données n'a pas besoin de savoir dans combien de paquets les données ont été transmises. Mais la différence avec TCP est qu’il n’ya aucune garantie que les données arrivent réellement. Il est également possible que les données soient divisées en plusieurs paquets. Certains arrivent, d'autres non. Pour l’application réceptrice, cela ressemble quand même à un flux de données, qu’elles soient complètes ou non.

rejouer
la source
Le pilote de la carte réseau ne s'occupe-t-il pas de réassembler les paquets, pas le noyau?
bluehallu
2
@Hallucynogenyc: À moins que les choses changent, le protocole Internet est conçu pour permettre aux paquets de plus de 576 octets d'être fractionnés à tout moment de leur voyage, mais n'attend que le destinataire final pour les recombiner. Je pense que l’idée est que l’utilisation de paquets plus volumineux était dans la plupart des cas un effort pour réduire les frais généraux; une fois qu'un paquet a été scindé à un moment donné de son parcours, les frais généraux ont déjà été générés. Il est donc inutile de se recombiner avant le destinataire final, ce qui peut être préjudiciable s'il peut être fractionné.
Supercat
Je pense que même si un paquet de plus de 576 octets peut être fractionné, les paquets dont la taille est inférieure à cette taille ne le peuvent pas; Les systèmes embarqués qui ne peuvent pas traiter les paquets divisés doivent éviter de demander une taille supérieure à celle-ci.
Supercat
1
@ mauro.stettler: J'ai écrit une pile TCP sur du "métal nu" (écrire le code pour communiquer directement avec un certain nombre de puces d'interface réseau). Pour le matériel qui communique avec un lien avec une limite de 576 octets pour diviser des paquets plus longs, la procédure est simple. Le réassemblage des paquets est beaucoup plus compliqué, d'autant plus qu'il est possible de recevoir des morceaux de nombreux paquets différents avant qu'ils ne soient intégralement reçus.
Supercat
On espère qu'il ne sera pas fractionné pour des charges utiles minuscules (environ 10 ou 20 octets devrait suffire), car une "taille maximale garantie" est requise pour chaque saut pour les paquets IP sur ipv4: au moins 68 octets (y compris En-têtes IP, sans compter les en-têtes de niveau inférieur). voir la 1ère table dans en.wikipedia.org/wiki/Maximum_transmission_unit . Différent des 576 octets de taille minimale requis de HOSTS (c'est-à-dire l'origine ou la fin de la transmission, pas tous les sauts intermédiaires). Et attention: la charge utile est encore plus basse (les en-têtes de chaque couche prenant de la place).
Olivier Dulac
14

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 ne sont pas nécessairement reçues du tout, mais les messages sont conservés dans leur intégralité.

Jim Cote
la source
5

Exemple: si j'envoie 20 octets en utilisant le protocole TCP, puis-je être sûr à 100% que je recevrai exactement 20 octets à la fois, et non 10 octets, puis 10 autres octets ou plus?

Non, TCP est un protocole de flux, il garde les données en ordre mais ne les groupe pas par message. D'autre part, UDP est orienté message, mais peu fiable. SCTP possède le meilleur des deux mondes, mais n'est pas utilisable en mode natif, car les NAT brisent Internet.

Changaco
la source
1

Il existe une certaine assurance que si vous envoyez 20 octets au tout début d'un flux TCP, celui-ci n'arrivera pas sous forme de deux morceaux de 10 octets. En effet, la pile TCP n'enverra pas de tels segments: il existe une taille minimale de MTU. Cependant, si l'envoi se trouve n'importe où au milieu d'un flux, tous les paris sont désactivés. Il se peut que votre pile de protocoles utilise 10 octets de données pour remplir un segment et l'envoyer, puis que les dix octets suivants passent à un autre segment.

Votre pile de protocoles divise les données en fragments et les place dans une file d'attente. Les tailles de bloc sont basées sur le MTU du chemin. Si vous effectuez une opération d'envoi et que des données sont toujours en attente, la pile de protocoles examine généralement le segment situé à la fin de la file d'attente et voit s'il y a suffisamment d'espace dans ce segment pour ajouter des données. La pièce peut être aussi petite qu'un octet, de sorte que même un envoi sur deux octets peut être divisé en deux.

Par ailleurs, 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 lorsqu'un seul segment arrive. Dans l’API des sockets largement implémentée, un appel reçu peut demander 20 octets, mais il peut en renvoyer 10. Bien entendu, il est possible de construire une couche de mise en mémoire tampon qui bloque jusqu’à ce que 20 octets soient reçus ou que la connexion soit interrompue. Dans le monde POSIX, cette API peut être le flux d’entrée / sortie standard: vous pouvez utiliser fdopenun descripteur de socket pour obtenir un FILE *flux et l’utiliser freadpour remplir un tampon de sorte que la demande complète soit satisfaite avec autant d’ readappels qu’elle prend. .

Les datagrammes UDP encadrent les données. Chaque appel envoyé 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 de socket, il doit spécifier un tampon suffisamment grand pour le contenir, sinon le datagramme sera tronqué). Les grands datagrammes sont fragmentés par fragmentation IP et sont réassemblés de manière transparente pour les applications. Si un fragment est manquant, 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 de spécifier un seul datagramme. Sous Linux, une socket peut être "bouchée" (envoi interdit). Bien qu’il soit bouché, les données écrites sont assemblées en une seule unité. Ensuite, lorsque la socket est "débouchée", un seul datagramme peut être envoyé.

Kaz
la source
C'est faux: si l'on envoie un paquet avec une charge utile de 10 ou 20 octets, cela générera 1 paquet, et (comme je l'ai dit plus haut), si vous utilisez ipv4, il devrait, même en ajoutant tous les en-têtes des autres couches de protocole, dans les 68 octets, assurant ainsi qu'il passe par tous les sauts dans 1 paquet. La pile TCP ne sera pas (comme indiqué dans votre premier paragraphe) "attendez que le MTU soit rempli (c.-à-d. Ajoutez plusieurs paquets pour en faire un correctement dimensionné)" pour envoyer un paquet! ... Ce comportement casserait beaucoup de choses ( même si ces "fragments" ont été envoyés de & à la même paire d’hôtes)
Olivier Dulac
@ OlivierDulac: C'est inexact. TCP génère généralement les paquets dont il a besoin, en essayant d'optimiser l'utilisation du réseau. Ainsi, 20 octets pourraient se retrouver dans deux paquets différents, comme expliqué par Kaz. Cela peut être contrôlé à l'aide de l' option de socket TCP_NODELAY , qui désactive l'algorithme Nagles qui distribue des octets en paquets, si votre application a besoin d'une mise en réseau TCP plus rapide. De plus, 68 octets n'est en aucun cas la norme de facto pour la longueur de paquet: 1500 octets est une valeur par défaut plus habituelle (cela varie vraiment entre les réseaux).
Jjmontes