Frage

Ich habe eine kleine Hierarchie von Objekten, die ich brauche über eine Socketverbindung zu serialisieren und zu übertragen. Ich muss sowohl das Objekt serialisiert, deserialisieren es dann basierend auf welche Art es sich handelt. Gibt es eine einfache Möglichkeit, dies in C ++ zu tun (wie es in Java ist)?

Gibt es C ++ Serialisierung Online-Code-Beispiele oder Tutorials?

EDIT: Just klar zu sein, ich bin auf der Suche nach Methoden, die auf ein Objekt in ein Array von Bytes umwandelt, dann zurück in ein Objekt. Ich kann die Buchse Übertragung behandeln.

War es hilfreich?

Lösung

Im Gespräch über die Serialisierung, die Serialisierung API steigern kommt mir in den Sinn. Wie für die serialisierten Daten über das Netz zu übertragen, würde ich entweder Berkeley Sockets verwenden oder die Asio Bibliothek .

Bearbeiten
Wenn Sie Ihre Objekte in einem Byte-Array serialisiert werden mögen, können Sie den Boost-Serializer in der folgenden Art und Weise verwenden (aus der Tutorial-Website entnommen):

#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)
    {}
};

Die tatsächliche Serialisierung ist dann recht einfach:

#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
    }

Deserialisierung arbeitet in analoger Weise.

Es gibt auch Mechanismen, die Sie Serialisierung von Zeigern behandeln lassen (komplexe Datenstrukturen wie Tress usw. sind kein Problem), abgeleiteten Klassen und Sie können zwischen Binär- und Text Serialisierung wählen. Außerdem sind alle STL-Container sind aus der Box unterstützt.

Andere Tipps

In einigen Fällen, wenn sie mit einfachen Typen tun haben, können Sie tun:

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

Das ist in Ordnung, als ein Proof-of-Concept-oder First-Entwurf, so dass die anderen Mitglieder Ihres Teams halten können auf andere Teile arbeiten.

Aber früher oder später, in der Regel früher , dieses Sie sich verletzen!

Sie führen in Probleme mit:

  • Virtuelle Zeiger Tabellen beschädigt werden.
  • Pointers (auf Daten / Mitglieder / Funktionen) beschädigt werden.
  • Unterschiede in padding / Ausrichtung auf verschiedenen Maschinen.
  • Big / Little-Endian Byte-Reihenfolge Fragen.
  • Variationen bei der Umsetzung von Float / Double.

(plus müssen Sie wissen, was Sie in auf der Empfangsseite sind Auspacken.)

Sie können durch die Entwicklung Ihrer eigenen Rangier- / unmarshalling Methoden für jede Klasse auf diese verbessern. (Im Idealfall virtuell, so können sie in Unterklassen erweitert werden.) Ein paar einfachen Makros können Sie verschiedene Grundtypen sehr schnell schreiben, in einer großen / Little-Endian-neutral Ordnung.

Aber diese Art von Grunzen Arbeit ist viel besser und leichter gehandhabt über boost der Serialisierung Bibliothek .

Serialisierung bedeutet, dass Ihr Objekt in binäre Daten drehen. Während der Deserialisierung bedeutet ein Objekt aus den Daten neu zu erstellen.

Wenn die Serialisierung Sie Bytes in einen uint8_t Vektor drängen. Wenn Deserialisierens Sie Bytes von einem uint8_t Vektor lesen.

Es gibt sicherlich Muster, die Sie verwenden können, wenn Sachen Serialisierung.

Jede serializable Klasse sollte eine serialize(std::vector<uint8_t> &binaryData) oder ähnliche signatured Funktion hat, die seine binäre Darstellung in den bereitgestellten Vektor schreiben. Dann kann diese Funktion dieses Vektors überliefern, um es Serialisierung der Member-Funktionen ist, so dass sie ihre Sachen in sie schreiben.

Da die Datendarstellung unterschiedlich auf unterschiedliche Architekturen sein. Sie müssen ein System finden, wie die Daten zu repräsentieren.

Lassen Sie sich von den Grundlagen beginnen:

Serialisierung Integer-Daten

Sie einfach die Bytes in Little-Endian-Reihenfolge schreiben. Oder VarInt Darstellung, wenn die Größe ankommt verwenden.

Serialisierung in Little-Endian-Reihenfolge:

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

Deserialisierung von Little-Endian-Reihenfolge:

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

Serialisierung von Gleitkomma-Daten

Soweit ich weiß, dass das IEEE 754 ein Monopol hier. Ich weiß nicht, jede Mainstream-Architektur, die etwas anderes für Schwimmer verwenden würde. Das einzige, was anders sein kann, ist die Byte-Reihenfolge. Einige Architekturen verwenden Little-Endian, andere verwenden Big-Endian-Byte-Reihenfolge. Das heißt, Sie, die um Sie laut auf die Bytes auf dem empfangenden Ende vorsichtig sein müssen. Ein weiterer Unterschied kann die Handhabung des denormal und Unendlichkeit und NAN Werte sein. Aber solange Sie diese Werte vermeiden, sollten Sie in Ordnung sein.

Serialisierung:

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

Deserialisierung wird es rückwärts zu tun. Achten Sie auf die Byte-Reihenfolge der Architektur!

Serialisierung Strings

Als erstes müssen Sie auf einer Codierung vereinbaren. UTF-8 ist üblich. Dann speichern Sie es als eine Länge voran Weise. Zuerst speichern Sie die Länge der Zeichenfolge unter Verwendung eines Verfahrens ich oben erwähnt habe, dann schreiben Sie den String-Byte-für-Byte

Serialisierung von Arrays.

Es ist die gleiche als Strings. Sie zuerst eine ganze Zahl serialisieren die Größe des Arrays darstellt, dann in sie jedes Objekt serialisieren.

Serialisierung ganze Objekte

Wie gesagt, bevor sie ein serialize Verfahren haben sollten, die Inhalte zu einem Vektor hinzufügen. Um unserialize ein Objekt, sollte es einen Konstruktor, die Byte-Strom nimmt. Es kann ein istream sein, aber im einfachsten Fall kann es nur eine Referenz uint8_t Zeiger sein. Der Konstruktor liest den Bytes aus dem Stream will und setzt die Felder in dem Objekt auf. Wenn das System gut ausgebildet ist und die Felder im Objektfeld, um serialisiert, können Sie einfach den Strom zu dem Konstrukteuren Feld passieren in einer Initialisierungsliste und haben sie in der richtigen Reihenfolge deserialisiert.

Serialisierung von Objektgraphen

Zuerst müssen Sie sicherstellen, wenn diese Objekte sind wirklich etwas, das Sie serialisieren möchten. Sie brauchen sie nicht zu serialisiert, wenn Instanzen dieser Objekte auf dem Ziel präsentieren.

Jetzt fand man heraus, Sie das Objekt durch einen Zeiger gezeigt serialisiert müssen. Das Problem der Zeiger, die sie nur gültig, die in dem Programm, die sie verwendet. Sie können nicht Zeiger serialisiert werden, sollten Sie mit ihnen in Objekte stoppen. Stattdessen Objekt-Pools erstellen. Diese Aufgabe Pool ist im Grunde ein dynamisches Array, die „Boxen“ enthält. Diese Boxen haben einen Referenzzähler. Nicht-Null-Referenzzähler zeigt ein Live-Objekt, Null zeigt einen leeren Schlitz. Dann sind Sie intelligente Zeiger verwandt mit dem Shared_ptr erstellen, die nicht den Zeiger auf das Objekt speichern, aber den Index im Array. Sie müssen auch auf einen Index einigen, die den Null-Zeiger bezeichnet, z. B. -1.

Im Grunde, was wir hier haben die Zeiger mit Array-Indizes ersetzt. Nun, wenn die Serialisierung können Sie dieses Array-Index wie gewohnt serialisiert. Sie brauchen nicht zu befürchten, wo tut die object wird auf dem Zielsystem in Erinnerung sein. So stellen Sie sicher, dass sie das gleiche Objekt Pool haben auch.

So müssen wir die Objekt-Pools serialisiert. Aber welche? Nun, wenn Sie ein Objekt Graph serialisiert Sie nicht nur ein Objekt serialisieren, Sie ein ganzes System Serialisierung. Dies bedeutet, dass die Serialisierung des Systems nicht von Teilen des Systems gestartet werden soll. Diese Objekte sollten nicht über den Rest des Systems kümmern, brauchen sie nur die Array-Indizes serialisiert werden und das ist es. Sie sollten ein System Serializer Routine haben, die die Serialisierung des Systems orchestriert und Wanderungen durch die relevanten Objektpools und serialisiert alle.

auf der Empfängerseite all Arrays mit einem der Objekten innerhalb deserialisiert werden, um die gewünschten Objektgraphen neu erstellt.

Serialisierung Funktionszeiger

Speichern Sie keine Zeiger im Objekt. Haben Sie ein statisches Array, das die Zeiger auf diese Funktionen enthält und speichern Sie den Index im Objekt.

Da beide Programme haben diese Tabelle in themshelves zusammengestellt, nur über den Index sollte funktionieren.

Serialisierung polymorphe Typen

Da ich gesagt, Sie Zeiger in serializable Typen sollten es vermeiden, und Sie sollten stattdessen Array-Indizes verwenden, Polymorphismus kann einfach nicht funktionieren, weil es Zeiger erfordert.

Sie müssen dies Umgehen mit Typ-Tags und Gewerkschaften.

Versioning

Am Anfang aller oben. Sie könnten verschiedene Versionen der Software interoperabel werden sollen.

In diesem Fall jedes Objekt soll eine Versionsnummer am Anfang ihrer Serialisierung schreibt Version anzuzeigen.

Wenn das Objekt auf der anderen Seite Laden bis die neueren Objekte vielleicht in der Lage, die älteren Darstellungen zu handhaben, aber die Ältere können die neuere nicht umgehen, so dass sie eine Ausnahme darüber werfen sollten.

Jedes Mal, wenn ein etwas ändert, sollten Sie die Versionsnummer stoßen.


So wickeln diese nach oben, Serialisierung komplex sein kann. Aber zum Glück müssen Sie nicht alles, was in Ihrem Programm serialisiert werden, meist nur die Protokollnachrichten werden serialisiert, die oft nur alte Strukturen. Sie müssen also nicht die komplexen Tricks, die ich oben zu oft erwähnt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top