La sérialisation/Désérialisation d'une structure à un char* en C
J'ai un struct
struct Packet {
int senderId;
int sequenceNumber;
char data[MaxDataSize];
char* Serialize() {
char *message = new char[MaxMailSize];
message[0] = senderId;
message[1] = sequenceNumber;
for (unsigned i=0;i<MaxDataSize;i++)
message[i+2] = data[i];
return message;
}
void Deserialize(char *message) {
senderId = message[0];
sequenceNumber = message[1];
for (unsigned i=0;i<MaxDataSize;i++)
data[i] = message[i+2];
}
};
J'ai besoin de convertir ce pour un char* , longueur maximale MaxMailSize > MaxDataSize pour les transmettre sur le réseau, puis le désérialiser à l'autre bout
Je ne peux pas utiliser tpl ou toute autre bibliothèque.
Est-il possible de faire mieux, je ne suis pas à l'aise avec cela, ou est-ce le mieux que nous puissions faire.
OriginalL'auteur Ankur Chauhan | 2009-10-31
Vous devez vous connecter pour publier un commentaire.
puisque c'est d'être envoyées sur un réseau, je vous conseille fortement de convertir ces données dans l'ordre des octets de réseau avant de les transmettre, et à l'arrière dans l'ordre des octets de l'hôte lors de la réception. c'est parce que l'ordre des octets est pas le même partout, et une fois que votre octets ne sont pas dans le bon ordre, il peut devenir très difficile de revenir en arrière (selon le langage de programmation utilisé sur le côté de réception). octet de commande fonctions sont définies avec les sockets, et sont nommés
htons()
,htonl()
,ntohs()
etntohl()
. (dans ces nom: h signifie "hôte" ou de votre ordinateur, n signifie "réseau", s signifie "court" ou 16 bits, la valeur, l signifie "long" ou valeur 32 bits).alors vous êtes sur votre propre avec la sérialisation, le C et le C++ ont pas de moyen automatique de l'effectuer. certains logiciels peuvent générer du code pour le faire pour vous, à l'instar de l'ASN.1 mise en œuvre asn1c, mais ils sont difficiles à utiliser, car elles impliquent beaucoup plus que juste de la copie de données sur le réseau.
OriginalL'auteur Adrien Plisson
Vous pouvez avoir une classe reprensenting l'objet que vous utilisez dans votre logiciel avec toutes les subtilités et membre func et tout ce dont vous avez besoin. Ensuite, vous avez un "sérialisé' struct c'est plus d'une description de ce que sera la fin de la place sur le réseau.
Pour assurer le compilateur va faire ce que vous lui dites de faire, vous avez besoin de le charger d' 'pack' de la structure. La directive que j'ai utilisé ici est pour gcc, consultez votre compilateur doc si vous n'êtes pas à l'aide de gcc.
Puis le sérialiser et désérialiser de routine, il suffit de convertir entre les deux, en veillant à l'ordre des octets et des détails comme ça.
delete ptr
? Son été un moment depuis que j'ai travaillé en C++, mais puisque vous êtes à l'allocation de mémoire dans la mémoire, vous aurez besoin de libérer quelque part.Mmmm, non, probablement pas (au moins pas garanti). C'est probablement mieux d'utiliser malloc() et utiliser free ().
Ou encore mieux, oubliez l'allocation de la mémoire sur le tas; il suffit d'utiliser le même interne mémoire tampon de la pile pour la sérialisation et la désérialisation
Comment cela peut-il fonctionner lorsque la signature est un void* dans la mise en œuvre, char* dans le ralentissement, mais s, la variable de retour, est un SerializedPacket?
Je veux l'utiliser pour le transfert de données sur le réseau. Il n'y aura aucune question par rapport à endian différences?
OriginalL'auteur 246tNt
En fonction de si vous avez assez de place ou pas... vous pouvez tout simplement utiliser les cours d'eau 🙂
Je l'admets, il prend plus de place... ou qu'il pourrait.
En fait, sur une architecture 32 bits un
int
couvrent généralement de 4 octets (4 caractères). La sérialisation d'entre eux à l'aide de flux de seulement prendre plus de 4 'char' si la valeur est supérieure à 9999, ce qui donne généralement un peu de place.Notez également que vous devez probablement inclure quelques gardes dans votre flux, juste pour vérifier, lorsque vous obtenez de retour qu'il va bien.
Le contrôle de version est probablement une bonne idée, il ne coûte pas cher et permet imprévue ultérieure de développement.
OriginalL'auteur Matthieu M.
Vous êtes en écrasant les valeurs ici. senderId et sequenceNumber sont deux entiers et va prendre plus que sizeof(char) octets sur la plupart des architectures. Essayez quelque chose comme ceci:
EDIT:
fixe code écrit dans un état de stupeur. Aussi, comme indiqué dans un commentaire, un tel paquet n'est pas portable en raison de endian différences.
memcpy(message + offset, &senderId, sizeof(senderId))
. Aussi, vous n'avez pas besoin de la dernière memcpy, commedata
n'a pas besoin d'être sérialisé, puisque c'est simplement la mémoire tampon utilisée pour unserialization.Il n'est pas d'écraser n'importe quoi lors de l'attribution d'une
int
à unchar
. Il est (peut-être) tronquer leurs valeurs.-1 L'utilisation de
memcpy
poursenderId
etsequenceNumber
n'est pas portable, que vous ne pouvez pas garantir l'ordre des octets pour ces valeurs. Mieux de le faire avec le décalage et le masquage.J'ai clairement ne pas répondre aux questions de manière à tard dans la nuit. @Charles, je sais qu'il a été à tronquer les valeurs, mais je pense, en termes de son intention et avait été à l'aide de ces décalages avec memcpy, il aurait été d'écraser les 3 derniers octets de senderId
OriginalL'auteur Jherico
Pour répondre à votre question en général, le C++ n'a pas de mécanisme de réflexion, et ainsi de manuel serialize et unserialize fonctions définies sur une fonction de la classe est le meilleur que vous pouvez faire. Cela étant dit, la sérialisation de la fonction que vous avez écrit, va marquer vos données. Voici une mise en œuvre correcte:
OriginalL'auteur Charles Salvia
Comme indiqué dans d'autres posts,
senderId
etsequenceNumber
sont tous deux de typeint
, qui est susceptible d'être plus grande que char, de sorte que ces valeurs seront tronqués.Si c'est acceptable, alors le code est OK. Si non, alors vous avez besoin de les diviser en leurs constituants octets. Étant donné que le protocole que vous utilisez spécifier l'ordre des octets de multi-octets des champs, le plus portable et le moins ambiguë, la façon de le faire est par le biais de changements de vitesse.
Par exemple, disons que
senderId
etsequenceNumber
sont à la fois 2 octets de long, et le protocole exige que l'octet de poids fort va d'abord:Je recommande aussi le remplacement de la
for
boucle avecmemcpy
(si disponible), car il est peu probable d'être moins efficace, et ça rend le code plus court.Enfin, tout cela suppose que
char
est un octet de long. Si ce n'est pas le cas, alors toutes les données devront être masquées, par exemple:OriginalL'auteur Steve Melnikoff
Vous pouvez utiliser des Tampons de Protocole pour la définition et la sérialisation des structures et des classes. C'est ce que google utilise en interne, et a une très petite mécanisme de transfert.
http://code.google.com/apis/protocolbuffers/
OriginalL'auteur Stef