Boost序列化:如何预测序列化结果的大小

Boost Serialization : How To Predict The Size Of The Serialized Result?

本文关键字:序列化 结果 何预测 Boost      更新时间:2023-10-16

我是这样使用boost序列化的:

Header H(__Magic, SSP_T_REQUEST, 98, 72, 42, Date(), SSP_C_NONE);
Header Z;
std::cout << H << std::endl;
std::cout << std::endl;
char serial_str[4096];
std::memset(serial_str, 0, 4096);
boost::iostreams::basic_array_sink<char> inserter(serial_str, 4096);
boost::iostreams::stream<boost::iostreams::basic_array_sink<char> > s(inserter);
boost::archive::binary_oarchive oa(s);
oa & H;
s.flush();
std::cout << serial_str << std::endl;
boost::iostreams::basic_array_source<char> device(serial_str, 4096);
boost::iostreams::stream<boost::iostreams::basic_array_source<char> > s2(device);
boost::archive::binary_iarchive ia(s2);
ia >> Z;
std::cout << Z << std::endl;

它工作得很好。

然而,我需要在套接字上发送这些数据包。我的问题是,我怎么知道在另一边我需要读取多少字节?序列化结果的大小不是常量,而且比struct的sizeof要大。

我如何确保另一边的数据是完整的?我使用循环缓冲区,但序列化怎么办?

谢谢所有的

一般来说,这是无法预测的。这(很大程度上)取决于存档格式。但是使用对象跟踪可以省略完整的子图,而使用动态类型信息可以添加大量数据。

如果你可以为序列化的数据提供临时缓冲区,你可以先序列化到一个缓冲区,然后在发送有效负载之前发送大小(现在你知道了)。

将会有

的开销
  • 对象跟踪(通过指针/引用序列化)
  • 动态多态性(通过(智能)指针到基序列化)
  • 版本控制(除非您为涉及的类型禁用它)
  • 存档头文件(除非已禁用)
  • 代码转换(除非禁用)

这里有一些答案,可以为您提供有关这些调整点的更多信息:

  • Boost c++序列化开销
  • Boost序列化二进制存档给出不正确的输出
  • 矢量 Boost序列化
  • 调整事物(boost::archive::no_codecvt, boost::archive::no_header,禁用跟踪等)

如果您的所有数据都是POD,则很容易预测大小。

开箱即用

如果您在同一台机器上共享IPC,并且您已经在使用循环缓冲区,请考虑将循环缓冲区放入共享内存。

我有很多答案(搜索managed_shared_memorymanaged_mapped_file)的例子。

下面是一个具体的例子,关注无锁的单生产者/单消费者场景:共享内存IPC同步(无锁)

即使你选择/需要流消息(例如通过网络),你仍然可以使用例如Managed External Buffers。因此,即使不要求所有数据都是POD,也可以避免进行任何序列化。(诀窍是在内部使用offset_ptr<>代替原始指针,使所有引用都是相对的)。

创建自己的流媒体类并覆盖xsputn方法。

class counter_streambuf : public std::streambuf {
public:
    using std::streambuf::streambuf;
    size_t size() const { return m_size; }
protected:
    std::streamsize xsputn(const char_type* __s, std::streamsize __n) override 
    { this->m_size += __n; return __n; }
private:
    size_t m_size = 0;
};

用法:

Header H(__Magic, SSP_T_REQUEST, 98, 72, 42, Date(), SSP_C_NONE);
counter_streambuf csb;
boost::archive::binary_oarchive oa(csb, boost::archive::no_header);
oa & H;
cout<<"Size: "<<csb.size();