Pergunta

Eu tenho uma pequena hierarquia de objetos que eu preciso para serializar e transmissão através de uma conexão socket. Eu preciso tanto serialize o objeto, então desserializá-lo com base em que tipo é. Existe uma maneira fácil de fazer isso em C ++ (como há em Java)?

Há algum C ++ serialização amostras de código on-line ou tutoriais?

EDIT: Só para ficar claro, eu estou à procura de métodos sobre a conversão de um objeto em um array de bytes, em seguida, voltar para um objeto. Eu posso lidar com a transmissão socket.

Foi útil?

Solução

Falando sobre a serialização, o impulso serialização API vem à minha mente. Como para transmitir os dados serializados sobre a rede, eu quer usar soquetes Berkeley ou o asio biblioteca .

Editar:
Se você quiser serializar seus objetos para um array de bytes, você pode usar o impulso serializer da seguinte maneira (retirado do site tutorial):

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

serialização real é então muito fácil:

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

Deserialization funciona de maneira análoga.

Existem também mecanismos que permitem lidar com a serialização de ponteiros (estruturas de dados complexas como árvores etc não são um problema), classes derivadas e você pode escolher entre serialização binária e texto. Além de todos os contêineres STL são suportados fora da caixa.

Outras dicas

Em alguns casos, quando se lida com os tipos simples, você pode fazer:

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

Isso é ok como uma prova de conceito ou primeiro-projecto, para que outros membros de sua equipe pode continuar trabalhando em outras partes.

Mas, mais cedo ou mais tarde, geralmente mais cedo , isso vai te machucar!

Você ter problemas com:

  • tabelas ponteiro virtuais serão corrompidos.
  • Ponteiros (para dados / membros / funções) será corrompido.
  • As diferenças de preenchimento / alinhamento em máquinas diferentes.
  • Big / Little-Endian questões byte de ordenação.
  • As variações na implementação de float / double.

(Além disso, você precisa saber o que você está desembalar em no lado receptor.)

Você pode melhorar esse através do desenvolvimento de seu próprio triagem / unmarshalling métodos para todas as classes. (Idealmente virtual, para que eles possam ser estendido em subclasses.) Algumas macros simples vai deixar você para escrever diferentes tipos básicos muito rapidamente em uma grande encomenda / little-endian-neutro.

Mas esse tipo de trabalho pesado é muito melhor e mais facilmente, tratada através o impulso biblioteca de serialização .

meios de serialização transformando o seu objeto em dados binários. Enquanto meio de desserialização recriar um objeto a partir dos dados.

Quando a serialização você está empurrando bytes dentro de um vector uint8_t. Quando unserializing você está lendo bytes de um vetor uint8_t.

Há certamente padrões que você pode empregar quando a serialização coisas.

Cada classe serializável deve ter um serialize(std::vector<uint8_t> &binaryData) ou função signatured similar que vai escrever sua representação binária para o vector fornecido. Em seguida, esta função pode passar este vector para baixo para funções de serialização-lo de membro para que eles possam escrever suas coisas para ele também.

Uma vez que a representação de dados pode ser diferente em diferentes arquiteturas. Você precisa descobrir um esquema de como representar os dados.

Vamos começar desde o básico:

Serializing inteiro de dados

Basta escrever os bytes em pouco de ordem endian. Ou representação uso VarInt se o tamanho importa.

A serialização em pouco de ordem endian:

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

Deserialization de pouca ordem endian:

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

Serializando flutuante dados de ponto

Tanto quanto eu sei o IEEE 754 tem o monopólio aqui. Eu não sei de qualquer arquitetura dominante que iria usar algo mais para carros alegóricos. A única coisa que pode ser diferente é a ordem de bytes. Algumas arquiteturas utilizam pouco endian, outros usam grande ordem de bytes endian. Isto significa que você precisa ter cuidado que para bem alto os bytes no fim de recepção. Outra diferença pode ser o manuseamento do denormal e infinito e valores NAN. Mas contanto que você evitar esses valores você deve estar OK.

A serialização:

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

Deserialization está fazendo isso para trás. Mente a ordem de bytes de sua arquitetura!

Serializando cordas

Primeiro você precisa concordar com uma codificação. UTF-8 é comum. Em seguida, armazená-lo como uma maneira comprimento prefixado:. Primeiro você armazenar o comprimento da corda usando um método que eu mencionei acima, em seguida, escrever a seqüência de byte a byte

Serializing matrizes.

Eles são o mesmo que um strings. É primeiro serializar um número inteiro que representa o tamanho da matriz, em seguida, serializar cada objecto no mesmo.

Serializando objetos inteiros

Como eu disse antes que eles devem ter um método serialize que o conteúdo add a um vector. Para unserialize um objeto, ele deve ter um construtor que recebe fluxo de bytes. Pode ser uma istream mas no caso mais simples, pode ser apenas um ponteiro uint8_t referência. O construtor lê os bytes que quer a partir do fluxo e configura os campos no objeto. Se o sistema é bem desenhado e seriar os campos na ordem de campo objeto, você pode apenas passar o fluxo para construtores do campo em uma lista de inicializador e tê-los desserializado na ordem correta.

Serializando gráficos de objetos

Primeiro, você precisa ter certeza de que esses objetos são realmente algo que você quer serialize. Você não precisa para serializar-los se exemplos desses objetos presentes no destino.

Agora você descobriu que você precisa para serializar o objeto apontado por um ponteiro. O problema de ponteiros que eles são válidos apenas o no programa que usa-los. Você não pode serializar ponteiro, você deve parar de usá-los em objetos. Em vez disso criar pools de objetos. Este conjunto de objetos é basicamente uma matriz dinâmica que contém "caixas". Estas caixas têm uma contagem de referência. contagem de referência diferente de zero indica um objeto vivo, zero indica um slot vazio. Então você cria ponteiro inteligente semelhante ao shared_ptr que não armazena o ponteiro para o objeto, mas o índice na matriz. Você também precisa concordar em um índice que denota o ponteiro nulo, por exemplo. -1.

Basicamente o que fizemos aqui é substituído os ponteiros com índices de matriz. Agora quando a serialização pode serializar este índice da matriz, como de costume. Você não precisa se preocupar com onde é que o object vai estar na memória no sistema de destino. Apenas certifique-se que eles têm o mesmo conjunto de objetos também.

Então, precisamos seriar as piscinas objeto. Mas quais? Bem, quando você serializar um gráfico de objeto que você não está serialização apenas um objeto, você está a serialização de um sistema inteiro. Isto significa que a serialização do sistema não deve começar a partir de partes do sistema. Esses objetos não deve se preocupar com o resto do sistema, eles só precisam de serializar os índices de matriz e é isso. Você deve ter uma rotina serializer sistema que organiza a serialização do sistema e passeios pelas piscinas de objetos relevantes e seriar todos eles.

Na extremidade receptora todas as matrizes de um dos objectos dentro são desserializadas, recriando o gráfico objecto desejado.

Serializando ponteiros de função

Não conservar ponteiros no objeto. Ter uma matriz estática que contém os ponteiros para essas funções e armazenar o índice no objeto.

Uma vez que ambos os programas têm esta tabela compilada em themshelves, usando apenas o índice deve funcionar.

Serializando tipos polimórficos

Uma vez eu disse que você deve evitar ponteiros em tipos serializáveis ??e você deve usar índices de matriz vez não, polimorfismo apenas pode trabalhar, porque requer ponteiros.

Você precisa trabalhar isso aí com marcas de tipo e sindicatos.

Versioning

Em cima de tudo o acima. Você pode querer diferentes versões do interoperam software.

Neste caso, cada objeto deve escrever um número de versão no início de sua serialização para indicar versão.

Ao carregar o objeto do outro lado os, objetos mais recentes talvez capaz de lidar com as representações mais velhos, mas os mais velhos podem não lidar com o mais recente de modo que deve lançar uma exceção a esse respeito.

Cada vez que um algo muda, você deve bater o número da versão.


Então, para acabar com isto, serialização pode ser complexa. Mas, felizmente, você não precisa de tudo o serialize em seu programa, na maioria das vezes apenas as mensagens do protocolo são serializados, que muitas vezes são simples estruturas antigas. Então você não precisa os truques complexos que eu mencionei acima demasiado frequentemente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top