2

Is it possible to serialize data without serializing the type information? I ask because I'm using Cereal to serialize data into packets and sending them across the network and want to minimize the packet size as much as possible thus not including type information would help.

The only reason I think this is possible is due to the fact that on the sending and receiving end the application already knows the type information and in which order it was serialized.

It's easier to understand exactly how i'm serializing and unserializing data from my actual implementation:

NetPacket.h

#pragma once

#include <cereal\archives\portable_binary.hpp>
#include <cereal\types\polymorphic.hpp>
#include <cereal\types\memory.hpp>
#include <cereal\types\vector.hpp>
#include <cereal\types\string.hpp>
#include <sstream>

class NetVar_ {
protected:
    virtual void MakeMePolymorphic() {}
public:
    template <class Archive> void serialize(Archive & archive) {}
};

class NetPacket;

template <class VARTYPE> class NetVar : public NetVar_
{
public:
    NetVar(void) {}

    NetVar(VARTYPE Value)
    {
        Var = Value;
    }

    template <class Archive> void serialize(Archive & archive)
    {
        archive(Var);
    }

private:
    friend class NetPacket;
    VARTYPE Var;
};


class NetPacket
{
private:
    ENetHost* Host;
    enet_uint8 ChannelNumber;
    unsigned int ThisMessageID;
    std::vector<std::shared_ptr<NetVar_>> PacketData;

    std::string SerializePacket();

public:
    NetPacket(ENetHost* iHost, const unsigned int MessageID, enet_uint8 ChannelNum);

    NetPacket(const char* Data, size_t Size);

    template <class DATATYPE> void WriteData(DATATYPE AddData)
    {
        PacketData.push_back(std::make_shared<NetVar<DATATYPE>>(AddData));
    }

    template <class DATATYPE> DATATYPE ReadData(const unsigned int VarNum) const
    {
        std::shared_ptr<NetVar_> Content = PacketData[VarNum];
        std::shared_ptr<NetVar<DATATYPE>> Temp = std::static_pointer_cast<NetVar<DATATYPE>>(Content);
        return Temp->Var;
    }

    void Send(const bool Reliable);

    void Send(NetClient* Client, const bool Reliable);

    unsigned int GetMessageID(void) const;

    enet_uint8 GetChannelNumber(void) const;

};

NetPacket.cpp

#include <enet\enet.h>
#include "NetClient.h"

#include "NetPacket.h"
// Register Types here that you want to
// read and write to packets

CEREAL_REGISTER_TYPE(NetVar<bool>);

CEREAL_REGISTER_TYPE(NetVar<unsigned int>);
CEREAL_REGISTER_TYPE(NetVar<int>);

CEREAL_REGISTER_TYPE(NetVar<float>);

CEREAL_REGISTER_TYPE(NetVar<std::string>);


std::string NetPacket::SerializePacket()
{
    std::ostringstream SData;
    {
        cereal::PortableBinaryOutputArchive Archive(SData);
        Archive(ThisMessageID, PacketData);
    }
    return SData.str();
}

NetPacket::NetPacket(ENetHost* iHost, const unsigned int MessageID, enet_uint8 ChannelNum)
{
    Host = iHost;
    ThisMessageID = MessageID;
    ChannelNumber = ChannelNum;
}

NetPacket::NetPacket(const char* Data, size_t Size)
{
    std::istringstream SData(std::string(Data, Size));
    {
        cereal::PortableBinaryInputArchive Archive(SData);
        Archive(ThisMessageID, PacketData);
    }
}

void NetPacket::Send(const bool Reliable)
{
    auto Out = SerializePacket();
    ENetPacket* Packet;
    if (Reliable)
    {
        Packet = enet_packet_create(Out.data(), Out.size(), ENET_PACKET_FLAG_RELIABLE);
    }
    else {
        Packet = enet_packet_create(Out.data(), Out.size(), ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
    }
    enet_host_broadcast(Host, ChannelNumber, Packet);
}

void NetPacket::Send(NetClient* Client, const bool Reliable)
{
    auto Out = SerializePacket();
    ENetPacket* Packet;
    if (Reliable)
    {
        Packet = enet_packet_create(Out.data(), Out.size(), ENET_PACKET_FLAG_RELIABLE);
    }
    else {
        Packet = enet_packet_create(Out.data(), Out.size(), ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
    }
    enet_peer_send(Client->GetPeer(), ChannelNumber, Packet);
}

unsigned int NetPacket::GetMessageID(void) const
{
    return ThisMessageID;
}

enet_uint8 NetPacket::GetChannelNumber(void) const
{
    return ChannelNumber;
}

As you can see from ReadData and WriteData defined in NetPacket.h, to read and write data you are required to specify the type information into the template function. Due to this requirement, type info is known on the reader and the writers end and in which order it was written. Is there any way to omit type info when serializing the data?

I apologize for the large question and I very much appreciate your time on this matter.

KKlouzal
  • 732
  • 9
  • 32
  • Not to mention that for templated classes, like your `NetVar` class, you have to list all possible template variations. This can be quite a lot for classes having more than one template parameter. – Some programmer dude Jul 18 '14 at 02:42
  • The code as-is compiles fine since I moved the implementation away from the .cpp into the .h file for the ReadData and WriteData functions. If I had left them inside the .cpp that would have required me to define a function for each type, but since it's in the .h file it works just fine. I just want to remove serializing the type information since I already have it on the receiving end. – KKlouzal Jul 18 '14 at 02:53

0 Answers0