2010-03-05 3 views
14

Dans une application client/serveur, des données texte de longueur variable seront envoyées entre le client et le serveur, comment marquer la fin d'un paquet envoyé? Par exemple, lorsque le serveur reçoit des données de paquets d'un client, comment le serveur sait-il que le paquet client a été entièrement reçu?Comment marquer la fin d'un paquet TCP?

Est-il plus commun de dire au serveur la longueur totale du paquet qu'il va recevoir avant les données ou d'avoir quelque chose marquant la fin du paquet?

Certaines des données envoyées ne comporteront que quelques caractères et d'autres des milliers de caractères.

+2

Je suppose que ce ne sont pas les paquets TCP qui vous inquiètent, ce sont les messages au niveau de l'application dans le flux TCP, n'est-ce pas? –

Répondre

23

TCP fournit un flux continu de données. TCP est implémenté en utilisant des paquets mais le point entier de TCP est de les cacher. Pensez-y comme s'il s'agissait d'un mur sur lequel vous voulez dessiner. Le mur est fait de briques. Les briques sont collées avec du mortier, et le plâtre est appliqué pour que la surface du mur devienne lisse. Les briques sont les paquets IP, TCP est le plâtre. Maintenant, vous avez votre tunnel TCP plâtré lisse, et vous voulez ajouter une certaine structure dedans. Vous voulez dessiner des boîtes, afin que vos dessins soient séparés les uns des autres. C'est ce que vous voulez faire: ajouter un peu de structure "administrative" (encadrés autour des dessins) à vos données.

De nombreux protocoles utilisent le concept packet, qui est un groupe de données commençant par un en-tête administratif au format fixe. L'en-tête contient suffisamment d'informations pour décider où le paquet se termine; par exemple, il comprend la longueur du paquet. HTTP fait cela, avec un Content-Length en-tête, ou (avec HTTP/1.1) avec le "codage de transfert chunked" où les données sont divisées en un ou plusieurs mini-paquets, chacun avec un en-tête simple consistant en une indication de longueur de paquet .

Une autre façon est d'avoir une séquence de terminaison spéciale qui ne peut pas apparaître dans les "données normales". Si vos données sont du texte, vous pouvez utiliser un octet de valeur zéro comme terminateur.

Encore une autre façon consiste à utiliser des données auto-terminées. Ce sont des données structurées de telle manière que vous puissiez savoir à tout moment si la fin de l'élément a été atteinte. Par exemple, les données XML sont organisées en paires imbriquées de marqueurs tels que <foo>...</foo>. Lorsque le marqueur de fin (</foo>) est atteint, vous savez que l'élément est terminé.

3

Structurez votre paquet de manière à inclure un champ de longueur au début.

1

Prenez vos repères à partir de HTTP.

Utilisez une séquence de caractères de terminaison ou spécifiez une longueur quelque part dans l'en-tête du message ou utilisez une combinaison intelligente des deux.

Comme le fait HTTP: les en-têtes se terminent par CR-LF-CR-LF. S'il y a des données après les en-têtes, la longueur des données est dans l'un des en-têtes.

+1

Les séquences de terminaison deviennent difficiles lorsque vous devez envoyer des données arbitraires, car les données peuvent (par coïncidence) contenir la séquence de terminaison, ce qui pourrait perturber l'analyseur récepteur. Vous pouvez éviter cela en implémentant un certain type de protocole de code d'échappement, mais à ce stade, les choses sont plus compliquées que l'envoi d'un champ de longueur en premier, alors il vaut mieux simplement envoyer le champ longueur et garder les choses simples. –

2

Si l'expéditeur connaît la longueur, l'expéditeur doit fournir la longueur initiale en tant que champ de taille fixe, suivi des données de taille variable. L'avantage par rapport à un marqueur de queue est que le récepteur peut optimiser la quantité de données attendue, par ex. allouer un tampon de la taille correcte. Par exemple, le stockage sur des protocoles TCP/IP a le même problème sur TCP/IP que vous. Dans ces cas, les en-têtes fournissent la longueur des données attendues par la suite.

Plus tard sur la route, vous pouvez trouver d'autres bits à mettre dans votre "en-tête". Vous serez heureux d'avoir une structure en place pour développer votre propre protocole de couche 5.

1

Si vous vous sentez particulièrement audacieux, vous pouvez utiliser les sockets SCTP au lieu des sockets TCP.

1

Méfiez-vous des déchets si vous codez la longueur au début. Par exemple, si vous utilisez 4 octets binaires pour la longueur et qu'une sonde externe envoie une requête HTTP, vous finirez probablement avec un nombre énorme et attendez toujours (sans parler de l'allocation d'un tampon qui pourrait planter votre programme). J'envoie la longueur deux fois chacun à travers une fonction différente et les compare (par exemple ~ len et len ​​xor 0x139AF321). Vous devriez également définir un maximum au cas où quelqu'un essaye activement de planter votre programme. Si j'ai une mauvaise longueur, je ferme la connexion.

Ceci est au-dessus d'un HMAC si votre trafic est crypté.

Questions connexes