提升序列化二进制存档提供不正确的输出

时间:2014-10-24 20:57:13

标签: c++ boost boost-serialization binary-serialization

我正在尝试序列化一个类。

班级定义:

class StartPeerSessionRequest {
public:
    StartPeerSessionRequest();
    virtual ~StartPeerSessionRequest();
    void composeRequestwithHardCodeValues();
    void save();
    stringstream serializedRequest;
    /*boost::serialization::binary_object serlreq;*/

private:
    StartPeerSessionRequest(const StartPeerSessionRequest &);

    uint16_t mProtocolVersion;
    uint16_t mSessionFlags;
    uint16_t mMaxResponseLength;
    string   mMake;
    string   mModel;
    string   mSerialNumber;
    uint8_t  mTrackDelay;
    string   mHeadUnitModel;
    string   mCarModelYear;
    string   mVin;
    uint16_t mVehicleMileage;
    uint8_t  mShoutFormat;
    uint8_t  mNotificationInterval;

    friend class boost::serialization::access;
    template <typename Archive> void serialize(Archive &ar, const unsigned int version);
};

StartPeerSessionRequest::StartPeerSessionRequest() {

    mProtocolVersion      = 1 * 10000 + 14 * 100 + 4;
    mSessionFlags         = 1;
    mMaxResponseLength    = 0;
    mMake                 = "MyMake";
    mModel                = "MyModel";
    mSerialNumber         = "10000";
    mTrackDelay           = 0;
    mHeadUnitModel        = "Headunit";
    mCarModelYear         = "2014";
    mVin                  = "1234567980";
    mVehicleMileage       = 1000;
    mShoutFormat          = 3;
    mNotificationInterval = 1;
}

template <class Archive> void StartPeerSessionRequest::serialize(Archive &ar, const unsigned int version) {
    ar & mProtocolVersion;
    ar & mSessionFlags;
    ar & mMaxResponseLength;
    ar & mMake;
    ar & mModel;
    ar & mSerialNumber;
    ar & mTrackDelay;
    ar & mHeadUnitModel;
    ar & mCarModelYear;
    ar & mVin;
    ar & mVehicleMileage;
    ar & mShoutFormat;
    ar & mNotificationInterval;
}

void StartPeerSessionRequest::save() {
    boost::archive::binary_oarchive oa(serlreq, boost::archive::no_header);
    oa << (*this);
    /*cout<<"\n binary_oarchive :"<<serlreq.size();*/

    boost::archive::text_oarchive ota(serializedRequest, boost::archive::no_header);
    ota << (*this);
    cout << "\n text_oarchive :" << serializedRequest.str() << "size :" << serializedRequest.str().size();
}

serializedRequest.str.size()为我提供了87的长度

实际上它应该提供65个字节。 (我认为你可以从构造函数中找出答案)

我怀疑它在两者之间增加了长度。

我已尝试使用text_archive,但它也无效。

我需要的是简单地序列化类成员。

我想我需要使用一些特征或包装。

请告诉我

由于

2 个答案:

答案 0 :(得分:1)

好的,所以,为了看看我的表现,我试图达到我计算的最佳尺寸on the back of my napkin

  

我可以看到你期望57,63或75字节

mProtocolVersion      = 1*10000+14*100+4; // 2 bytes
mSessionFlags         = 1;                // 2 bytes
mMaxResponseLength    = 0;                // 2 bytes
mMake                 = "MyMake";         // 6 bytes + length
mModel                = "MyModel";        // 7 bytes + length
mSerialNumber         = "10000";          // 5 bytes + length
mTrackDelay           = 0;                // 1 byte
mHeadUnitModel        = "Headunit";       // 8 bytes + length
mCarModelYear         = "2014";           // 4 bytes + length
mVin                  = "1234567980";     // 10 bytes + length
mVehicleMileage       = 1000;             // 2 byte
mShoutFormat          = 3;                // 1 byte
mNotificationInterval = 1;                // 1 byte
// -------------------------------------- // 51 bytes + 6 x length

在这个例子中,我使用Boost Spirit创建了二进制序列化代码(Karma用于序列化,Qi用于反序列化)。我使长度字段的大小可配置(8,16,32或64位无符号)。

这是一个有效的概念证据: Live On Coliru

generate()

const生成成员函数将工作委托给一个单独的命名空间中的辅助函数:

template <typename Container>
bool generate(Container& bytes) const {
    auto out = std::back_inserter(bytes);

    using my_serialization_helpers::do_generate;
    return do_generate(out, mProtocolVersion)
        && do_generate(out, mSessionFlags)
        && do_generate(out, mMaxResponseLength)
        && do_generate(out, mMake)
        && do_generate(out, mModel)
        && do_generate(out, mSerialNumber)
        && do_generate(out, mTrackDelay)
        && do_generate(out, mHeadUnitModel)
        && do_generate(out, mCarModelYear)
        && do_generate(out, mVin)
        && do_generate(out, mVehicleMileage)
        && do_generate(out, mShoutFormat)
        && do_generate(out, mNotificationInterval);
}

请注意

  • do_generate重载可以根据未来类型的需要自由添加
  • 容器可以很容易地从例如std::vector<unsigned char>,例如boost::interprocess::containers::string<char, char_traits<char>, boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> >

parse()

parse方法非常相似,只是委托do_parse重载来完成工作。

测试

测试程序以所有可能的配置进行往返:

正如你所看到的那样,自然的Boost序列化解决方案would take 107 bytes on my system(它比我上一次配置只多8个字节)甚至 更令人愤慨。

另请注意,由于Karma生成器都采用任何输出迭代器,因此将其直接连接到 low-level Boost Archive operations 以获得性能并避免分配中间存储应该相对容易。 / p>

答案 1 :(得分:0)

您似乎对Boost Serialization如何序列化为其专有的非可移植二进制格式有一些非常具体的假设。

Boost序列化更高级,或多或少地专门设计用于处理非POD数据。如果你坚持,你应该能够直接序列化你的POD类型的数组。但是,在你的问题中,该类根本不是POD,因此无论如何都不是按位序列化的。

对于便携式存档,请参阅EOS Portable Archive。

Boost Archives有可选的标志,可以抑制格式标题:

enum archive_flags {
    no_header = 1,          // suppress archive header info
    no_codecvt = 2,         // suppress alteration of codecvt facet
    no_xml_tag_checking = 4 // suppress checking of xml tags - igored on saving
};

参见 Archive Models

这是一个背景资料,可以看到简单的按位序列化引入了什么: