Question

Ce type est d'une branche hors de mon autre question . Lisez si vous voulez, mais il est pas nécessaire.

En fait, je me suis aperçu que pour utiliser efficacement C # 's BeginReceive () sur les grands messages, je dois (a) lire la longueur du paquet, puis lire exactement que le nombre d'octets ou (b) utiliser un hors d'usage delimiter de paquets. Ma question est, sont l'une de ces présentes dans les tampons de protocole? Je ne l'ai pas encore utilisé, mais aller sur la documentation, il ne semble pas comme il y a une tête de longueur ou un séparateur.

Dans le cas contraire, que dois-je faire? Devrais-je construire le message alors préfixe / suffixe avec l'en-tête de longueur / delimiter EOP?

Était-ce utile?

La solution

Vous devez inclure la taille ou marqueur de fin dans votre protocole. Rien ne se construit dans des douilles à base de flux (TCP / IP) autres que l'appui d'un flux d'octets indéfini arbitrairement divisé en paquets séparés (et les paquets peuvent être déversé pendant le transport aussi bien).

Une approche simple serait pour chaque « message » à un en-tête de taille fixe, inclure à la fois une version de protocole et une taille de charge utile et d'autres données fixes. Ensuite, le contenu du message (charge utile).

En option, un pied de page de message (taille fixe) pourrait être ajoutée avec une somme de contrôle ou même une signature cryptographique (en fonction de votre fiabilité / exigences de sécurité).

La connaissance de la taille de la charge utile vous permet de garder la lecture d'un certain nombre d'octets qui sera suffisant pour le reste du message (et si une lecture complète avec moins, faire une autre lecture pour les octets restants jusqu'à ce que le message entier a été reçu) .

Avoir un indicateur de message final fonctionne également, mais vous devez définir comment gérer votre message contenant cette même séquence d'octets ...

Autres conseils

Toutes mes excuses pour arriver en retard à la fête. Je suis l'auteur de protobuf-net, l'une des implémentations de C #. Pour l'utilisation du réseau, vous devez prendre en compte les « [De] SerializeWithLengthPrefix » méthodes - de cette façon, il se chargera automatiquement les longueurs pour vous. Il existe des exemples dans la source.

Je ne vais pas entrer dans les détails sur grand un ancien poste, mais si vous voulez en savoir plus, ajoutez un commentaire et je vais vous revenir.

Je suis d'accord avec Matt qu'un en-tête est mieux qu'un pied de page pour Buffers Protocole, pour la raison principale que PB est un protocole binaire, il est difficile de trouver un pied de page qui ne serait pas aussi une séquence de message valide. Un grand nombre de protocoles basés sur le pied de page (généralement ceux EOL) travaillent parce que le contenu du message est dans une plage définie. (Généralement 0x20 - 0x7F ASCII)

Une approche utile est d'avoir votre code de niveau le plus bas juste de lire des tampons hors de la douille et les présenter à une couche de cadrage qui assemble des messages complets et se souvient de ceux partiels (je vous présente une approche async à ce (à l'aide du CCR) < a href = "http://iodyner.spaces.live.com/blog/cns!7B505254340D5E9A!180.entry" rel = "nofollow noreferrer"> ici , mais pour un protocole de ligne).

Par souci de cohérence, vous pouvez toujours définir votre message comme un message PB avec trois champs: un int fixe la longueur, un ENUM comme le type, et une séquence d'octets qui contient les données réelles. Cela permet de maintenir l'ensemble de votre transparent protocole réseau.

TCP / IP, ainsi que UDP, les paquets comprennent une référence à leur taille. tête IP contient un champ de 16 bits qui spécifie la longueur de l'en-tête IP et données en octets. tête TCP rel="nofollow href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol" contient un champ de 4 bits qui spécifie la taille de l'en-tête TCP dans 32- mots de bits. contient un champ de 16 bits qui spécifie la longueur de l'en-tête UDP et données en octets.

Voici la chose.

En utilisant la norme d'exécution de l'usine- prises dans Windows, si vous utilisez l'espace de noms System.Net.Sockets en C # ou la substance Winsock natif dans Win32, vous ne voyez jamais les IP / TCP / UDP-têtes. Ces têtes sont supprimés de sorte que ce que vous obtenez lorsque vous lisez la prise est la charge utile réelle, à savoir les données qui a été envoyé.

Le modèle typique de tout ce que j'ai jamais vu et fait en utilisant des sockets est que vous définissez un en-tête au niveau de l'application qui précède les données que vous souhaitez envoyer. Au minimum, cet en-tête doit inclure la taille des données à suivre. Cela vous permettra de lire chaque « message » dans son intégralité sans avoir à deviner à sa taille. Vous pouvez obtenir autant de fantaisie que vous voulez avec, par exemple, des modèles de synchronisation, CRC, la version, le type de message, etc., mais la taille du « message » est tout ce que vous vraiment besoin.

Et pour ce que ça vaut, je suggère d'utiliser un en-tête au lieu d'un séparateur de fin de paquet. Je ne sais pas s'il y a un inconvénient signficant au delimiter EOP, mais l'en-tête est l'approche utilisée par la plupart des protocoles IP que j'ai vu. De plus, il me semble plus intuitif pour traiter un message depuis le début plutôt que d'attendre un certain modèle apparaisse dans mon flux pour indiquer que mon message est complet.

EDIT: Je viens seulement de prendre conscience du projet Buffers Protocole Google. D'après ce que je peux dire, il est un système binaire sérialisation / désérialisation pour WCF (je suis sûr que c'est une schématisation grossière). Si vous utilisez WCF, vous n'avez pas à vous soucier de la taille des messages envoyés parce que la plomberie WCF prend soin de ce dans les coulisses, ce qui est probablement la raison pour laquelle vous ne trouvez pas tout ce qui concerne la longueur du message dans le protocole documentation buffers. Toutefois, dans le cas des prises, sachant la taille va aider énormément comme discuté ci-dessus. Je suppose que vous sérialiser vos données en utilisant le protocole buffers puis virer de bord sur quelque tête application que vous venez avec avant de l'envoyer. Sur le côté réception, vous retirer l'en-tête puis désérialiser le reste du message.

scroll top