2

型情報をシリアル化せずにデータをシリアル化することは可能ですか? シリアルを使用してデータをパケットにシリアル化し、ネットワーク経由で送信しており、パケットサイズをできるだけ小さくしたいので、タイプ情報を含めないでください。

これが可能であると私が考える唯一の理由は、アプリケーションが送信側と受信側で型情報とそれがシリアル化された順序を既に知っているという事実によるものです。

実際の実装からデータをシリアル化および非シリアル化する方法を正確に理解するのは簡単です:

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

NetPacket.h で定義されている ReadData と WriteData からわかるように、データを読み書きするには、型情報をテンプレート関数に指定する必要があります。この要件により、型情報はリーダーとライターで認識され、どの順序で書き込まれたかがわかります。データをシリアル化するときに型情報を省略する方法はありますか?

大きな質問で申し訳ありません。この件についてお時間を割いていただき、誠にありがとうございます。

4

0 に答える 0