2009-08-11 9 views
1

Pour une application en réseau, la façon dont nous avons transmis des données dynamiques consiste à mémoriser une structure dans un (void *). Cela pose quelques problèmes, comme quand cela est fait pour une chaîne std :: string. Les chaînes peuvent être de longueur dynamique, alors comment l'autre partie saura quand la chaîne se termine? Une idée que j'avais était d'utiliser quelque chose de similaire à DataOuputStream de Java, où je pouvais juste passer toutes les variables et il pourrait ensuite être mis dans un (void *). Si cela ne peut pas être fait, alors c'est cool. Je n'aime pas vraiment mémoriser une structure. Quelque chose à ce sujet ne semble pas tout à fait raison.Flux d'octets C++

Merci,
Robbie

+1

Cette question n'est pas très claire (Ou mon esprit ne fonctionne pas). La chaîne std :: est-elle copiée dans IN ou OUT? Quel est le problème avec le terminateur null comme une explication de la longueur? Pourquoi ne pas transmettre la longueur en premier? Qu'est-ce qui ne va pas avec memcpy'ing une structure? Pourquoi n'utilisez-vous pas une structure de paquets appropriée avec un identifiant qui vous indique le type du paquet afin que les deux parties sachent qu'elles envoient et reçoivent? – Goz

+0

La chaîne std :: est en cours de copie et d'écriture. L'analyse des paquets à la réception des deux extrémités ne prend pas en charge la recherche du terminateur null. La longueur est transmise en premier, mais il y a un int et trois chaînes de longueur variable transmises. La longueur est le total pour chacun d'eux. Memcpying une structure pour une raison quelconque ne semble pas juste. Je me trompe probablement, mais c'est comme ça que ça se sent. Et nous avons une structure de paquets correcte, c'est la longueur variable qui m'apporte. – Robbie

Répondre

2

rien de mal à memcpy sur une struct - comme lng que le struct est rempli de tampons de taille fixe. Mettez une variable dynamique là-dedans et vous devez la sérialiser différemment.

Si vous avez une structure avec std :: strings, créez un opérateur de flux et utilisez-le pour formater un tampon. Vous pouvez ensuite mémcpy ce tampon au transport de données. Si vous avez boost, utilisez Boost::serialize qui fait tout cela pour vous (ce lien a aussi des liens vers des librairies de sérialisation alternatives)

Notes: la façon habituelle de passer un tampon de taille variable est de commencer par envoyer la longueur, puis de nombreux octets de données. Parfois, vous voyez des données transférées jusqu'à ce qu'un délimiteur soit reçu (et les champs de ces données sont eux-mêmes délimités par un autre caractère, par exemple une virgule).

+0

Il y a quelque chose qui cloche avec memcpy() - une structure sur le réseau ... différents compilateurs rempliront la structure différemment, et donc les données risquent d'être mal interprétées du côté de la réception. Même le même compilateur peut tamponner les choses différemment en fonction de la version du compilateur et/ou des paramètres d'optimisation. Le seul moyen sûr de transmettre les données est de rassembler manuellement chaque variable membre de la structure dans un tampon d'octets, de sorte que vous puissiez contrôler précisément la disposition des octets. –

0

Je vois deux parties de cette question: - sérialisation de données sur un réseau - comment passer des structures dans une pile de réseau

Pour sérialiser données sur un réseau, vous aurez besoin d'un protocole. Ne doit pas être difficile; pour ASCII même un cr/lf comme fin de paquet peut faire. Si vous utilisez un framework (comme MFC), il peut vous fournir des fonctions de sérialisation; Dans ce cas, vous devez vous soucier de la façon d'envoyer ceci dans les paquets. Un packetization qui fonctionne souvent bien pour moi:

<length><data_type>[data....][checksum] 

Dans ce cas, la somme de contrôle est facultatif, et aussi zéro des données est possible, par exemple si le signal est transporté dans le data_type (c.-à-Ack pour acklnowedgement)

Si vous travaillez sur le memcpy avec des structures, vous devez considérer que memcpy ne fait qu'une copie superficielle. Un pointeur est sans valeur une fois transmis sur un réseau; instand vous devez transmettre les données à partir de ce pointeur (c'est-à-dire le contenu de votre exemple de chaîne)

0

Pour l'envoi de données dynamiques sur le réseau, vous disposez des options suivantes.

Première option dans le même paquet.

void SendData() 
{ 
    int size; 
    char payload[256]; 

    Send(messageType) 
    Send(size); 
    Send(payload) 
} 

Deuxième possibilité:

void SendData() 
{ 
    char payload[256]; 

    Send(messageType) 
    Send(payload) 
} 

Bien que dans les deux cas, vous serez confronté à plus d'un choix de conception. Dans le premier exemple, vous enverriez le type de message, la taille de la charge utile et aussi la charge utile.

La deuxième option que vous avez est que vous pouvez envoyer le type de message, puis vous pouvez envoyer la chaîne qui a un délimiteur de terminateur null.

Bien que l'une ou l'autre option ne couvre pas entièrement le problème de votre face je pense.Premièrement, vous devez déterminer si vous construisez un jeu quel type de protocole vous utiliserez, UDP? TCP? Le deuxième problème auquel vous serez confronté est la taille maximale des paquets. En plus de cela, vous devez avoir le cadre en place afin que vous puissiez calculer la taille optimale des paquets qui ne seront pas fragmentés et perdus pour l'inter web. Après cela, vous avez le contrôle de la bande passante en ce qui concerne la quantité de données que vous pouvez transmettre et recevoir entre le client et le serveur.

Par exemple, la façon dont la plupart des jeux abordent cette situation est que chaque paquet est identifié par ce qui suit. Dans le cas où vous devez envoyer des données dynamiques, vous enverriez une série de paquets et pas une seule. Par exemple si vous deviez envoyer un fichier à travers le réseau, la meilleure option serait d'utiliser TCP/IP parce que c'est un protocole de streaming et il efface que le flux complet arrive en toute sécurité à l'autre extrémité. D'autre part, UDP est un protocal basé sur les paquets et ne vérifie pas que tous les paquets sont arrivés dans l'ordre ou pas du tout à l'autre extrémité.

Donc en conclusion.

  1. Pour les données dynamiques, envoyer plusieurs paquets, mais avec un drapeau spécial dire plus de données est d'arriver à remplir ce message. Restez simple et si votre travail avec C++ ne suppose pas le paquet ou les données contiendra un terminateur null et vérifier la taille par rapport à la charge utile si vous décidez d'utiliser un terminateur null.
Questions connexes