Question

J'ai une petite hiérarchie d'objets que je dois sérialisation et transmettre via une connexion socket. Je dois à la fois sérialiser l'objet, désérialiser puis en fonction de quel type il est. Est-il un moyen facile de le faire en C ++ (comme il est en Java)?

Y a-t-il des exemples de code en ligne sérialisation C ++ ou tutoriels?

EDIT: Juste pour être clair, je suis à la recherche de méthodes sur la conversion d'un objet dans un tableau d'octets, puis de nouveau dans un objet. Je peux gérer la transmission de courant.

Était-ce utile?

La solution

En parlant de sérialisation, stimuler API sérialisation vient à l'esprit. En ce qui concerne la transmission des données sérialisés sur le net, je soit d'utiliser des sockets Berkeley ou bibliothèque asio .

Edit: Si vous souhaitez sérialiser vos objets à un tableau d'octets, vous pouvez utiliser le sérialiseur coup de pouce de la manière suivante (tirée du site tutoriel):

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
class gps_position
{
private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    int degrees;
    int minutes;
    float seconds;

public:
    gps_position(){};
    gps_position(int d, int m, float s) :
    degrees(d), minutes(m), seconds(s)
    {}
};

sérialisation réelle est alors assez facile:

#include <fstream>
std::ofstream ofs("filename.dat", std::ios::binary);

    // create class instance
    const gps_position g(35, 59, 24.567f);

    // save data to archive
    {
        boost::archive::binary_oarchive oa(ofs);
        // write class instance to archive
        oa << g;
        // archive and stream closed when destructors are called
    }

désérialisation fonctionne d'une manière analogue.

Il existe aussi des mécanismes qui vous permettent de gérer sérialisation des pointeurs (structures de données complexes comme tress etc sont pas de problème), les classes dérivées et vous pouvez choisir entre sérialisation binaire et texte. En plus de tous les conteneurs STL sont pris en charge hors de la boîte.

Autres conseils

Dans certains cas, lorsqu'ils traitent avec des types simples, vous pouvez faire:

object o;
socket.write(&o, sizeof(o));

C'est ok comme une preuve de concept ou du premier projet, afin que les autres membres de votre équipe peuvent continuer à travailler sur d'autres parties.

Mais tôt ou tard, habituellement plus tôt , cela vous vous blessez!

Vous rencontrez des problèmes avec:

  • tables de pointeur virtuel sera corrompu.
  • Pointeurs (à données / membres / fonctions) sera corrompu.
  • Les différences de remplissage / alignement sur des machines différentes.
  • Big / Little-endian des problèmes de classement.
  • Les variations dans la mise en œuvre du float / double.

(De plus, vous devez savoir ce que vous déballez dans le côté de la réception.)

Vous pouvez améliorer en développant vos propres méthodes / triages unmarshalling pour chaque classe. (Idéalement virtuelle, de sorte qu'ils peuvent être étendus dans les sous-classes.) Quelques macros simples vous permettent d'écrire différents types de base assez rapidement dans un ordre grand / petit-boutiste neutre.

Mais ce genre de travail de base est beaucoup mieux, et plus facilement, manipulés via bibliothèque de sérialisation de boost.

sérialisation signifie transformer votre objet en données binaires. Alors que désérialisation signifie recréer un objet à partir des données.

Lors de la sérialisation vous poussiez octets dans un vecteur de uint8_t. Lorsque vous lisez délinéarisation octets à partir d'un vecteur uint8_t.

Il y a certainement des modèles que vous pouvez utiliser lors de la sérialisation des choses.

Chaque classe sérialisable doit avoir une fonction similaire ou serialize(std::vector<uint8_t> &binaryData) qui va écrire signatured sa représentation binaire dans le vecteur fourni. Ensuite, cette fonction peut passer ce vecteur jusqu'à c'est des fonctions de sérialisation de membres afin qu'ils puissent écrire leurs trucs en trop.

Étant donné que la représentation des données peut être différent sur différentes architectures. Vous devez savoir comment un système pour représenter les données.

Commençons par les bases:

sérialisation des données de nombres entiers

Il suffit d'écrire les octets dans peu d'ordre endian. Ou utiliser la représentation varint si des questions de taille.

sérialisation dans peu d'ordre endian:

data.push_back(integer32 & 0xFF);
data.push_back((integer32 >> 8) & 0xFF);
data.push_back((integer32 >> 16) & 0xFF);
data.push_back((integer32 >> 24) & 0xFF);

Désérialisation de peu d'ordre endian:

integer32 = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);

sérialisation flottante données de point

Pour autant que je sais l'IEEE 754 a un monopole ici. Je ne connais pas d'architecture grand public qui utiliserait quelque chose d'autre pour les flotteurs. La seule chose qui peut être différent est l'ordre des octets. Certaines architectures utilisent peu endian, d'autres utilisent le grand ordre de endian. Cela signifie que vous devez être prudent quel ordre vous loud les octets sur l'extrémité de réception. Une autre différence peut être la manipulation de la denormal et l'infini et les valeurs NAN. Mais aussi longtemps que vous évitez ces valeurs que vous devriez être OK.

sérialisation:

uint8_t mem[8];
memcpy(mem, doubleValue, 8);
data.push_back(mem[0]);
data.push_back(mem[1]);
...

Désérialisation fait en arrière. Attention à l'ordre des octets de votre architecture!

chaînes Sérialisation

Vous devez d'abord d'accord sur un codage. UTF-8 est commun. Ensuite, mémorisez comme une manière préfixée de longueur. D'abord, vous stockez la longueur de la chaîne en utilisant une méthode je l'ai mentionné ci-dessus, puis écrire la chaîne octet par octet

tableaux sérialisation.

Ce sont les mêmes en tant que chaînes. Il faut d'abord sérialiser un nombre entier représentant la taille de la matrice puis sérialiser chaque objet en elle.

entiers Linéarisation des objets

Comme je l'ai dit avant qu'ils devraient avoir une méthode de serialize qui ajoutent du contenu à un vecteur. Pour désérialiser un objet, il doit avoir un constructeur qui prend flux d'octets. Il peut être un istream mais dans le cas le plus simple, il peut être juste un pointeur uint8_t de référence. Le constructeur lit les octets qu'il veut à partir du flux et met en place les champs dans l'objet. Si le système est bien conçu et sérialiser les champs afin de champ d'objet, vous pouvez simplement passer le flux aux constructeurs du terrain dans une liste d'initialiseur et les ont désérialisée dans l'ordre.

Sérialisation d'objets graphiques

D'abord, vous devez vous assurer que ces objets sont vraiment quelque chose que vous voulez sérialiser. Vous n'avez pas besoin de les sérialiser si les instances de ces objets présents sur la destination.

Maintenant, vous avez découvert que vous devez sérialiser cet objet pointé par un pointeur. Le problème des pointeurs qu'ils ne sont valables que le dans le programme qui les utilise. Vous ne pouvez pas sérialiser pointeur, vous devriez cesser de les utiliser dans les objets. Au lieu de cela créer des pools d'objets. Ce pool d'objets est essentiellement un tableau dynamique qui contient des « boîtes ». Ces boîtes ont un compte de référence. compte de référence de zéro indique un objet direct, zéro indique un emplacement vide. Ensuite, vous créez pointeur intelligent semblable à la shared_ptr qui ne stocke pas le pointeur sur l'objet, mais l'indice dans le tableau. Vous devez également se mettre d'accord sur un indice qui indique le pointeur NULL, par exemple. -1.

En fait ce que nous avons ici est remplacé les pointeurs avec des index de tableau. Maintenant, quand vous pouvez sérialisation sérialiser cet indice de tableau comme d'habitude. Vous n'avez pas besoin de vous soucier d'où vient le object sera en mémoire sur le système de destination. Assurez-vous qu'ils ont le même pool d'objets aussi.

Nous devons donc sérialiser les piscines d'objets. Mais ceux qui? Eh bien, lorsque vous sérialiser un graphe d'objet que vous n'êtes pas sérialisation seulement un objet, vous sérialisation tout un système. Cela signifie que la sérialisation du système ne doit pas commencer à partir de pièces du système. Ces objets ne doivent pas inquiéter le reste du système, ils ne doivent sérialiser les indices de tableau et c'est tout. Vous devriez avoir une routine sérialiseur système orchestrant la sérialisation du système et des promenades à travers les pools d'objets pertinents et sérialiser tous.

A l'extrémité de réception de toutes les rangées un des objets à l'intérieur sont désérialisé, recréer l'objet graphique souhaité.

Sérialisation des pointeurs de fonction

Ne pas stocker des pointeurs dans l'objet. Un tableau statique qui contient les pointeurs vers ces fonctions et stocker l'index dans l'objet.

Comme les deux programmes ont compilé ce tableau dans themshelves, en utilisant uniquement l'indice devrait fonctionner.

Sérialisation types polymorphes

Depuis que je dit que vous devriez éviter des pointeurs dans les types sérialisables et vous devez utiliser les index de tableau à la place, le polymorphisme ne peut pas fonctionner, car il nécessite des pointeurs.

Vous devez travailler ce autour avec des balises et des syndicats de type.

Versioning

En plus de tout ce qui précède. Vous voudrez peut-être différentes versions du logiciel interopérer.

Dans ce cas, chaque objet doit écrire un numéro de version au début de leur sérialisation pour indiquer la version.

Lors du chargement jusqu'à l'objet de l'autre côté, les objets plus récents peut-être en mesure de gérer les représentations anciennes, mais les plus âgés ne peuvent pas gérer la nouvelle, ils devraient jeter une exception à ce sujet.

Chaque fois que quelque chose change, vous devez changer le numéro de version.


Donc, pour envelopper tout ça, sérialisation peut être complexe. Mais heureusement, vous n'avez pas besoin de sérialisation tout dans votre programme, le plus souvent que les messages de protocole sont sérialisés, qui sont souvent simples vieux struct. Donc, vous n'avez pas besoin des trucs complexes dont j'ai parlé ci-dessus trop souvent.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top