使用Boost序列化和发送数据结构?

Posted

技术标签:

【中文标题】使用Boost序列化和发送数据结构?【英文标题】:Serialize and send a data structure using Boost? 【发布时间】:2010-10-13 17:23:12 【问题描述】:

我有一个如下所示的数据结构:

类型定义结构 无符号短 m_short1; 无符号短 m_short2; 无符号字符 m_character; 我的数据类型;

我想使用 boost::serialization 序列化这个数据结构,然后使用 boost::asio 通过 TCP/IP 传输它,然后让另一个应用程序接收数据并使用相同的 boost 库对其进行反序列化。

I'm trying to following boost::serialization tutorial, (as some other SO questions have suggested) 但该示例专门用于写入/读取文件,而不是使用 boost::asio 的套接字。

我很确定我有合适的工具来完成这项工作——我只需要帮助让它们一起工作。写入套接字与写入文件没有什么不同,对吧?

非常感谢任何建议。谢谢!

【问题讨论】:

【参考方案1】:

您进行序列化以获取构造函数参数的 boost::archive - 目标流,您将在其中保存数据。您可以使用 boost.iostreams 库定义您自己的流,该流将通过网络发送数据,而不是文件或仅使用 asio 套接字流 (http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/reference/ip__tcp/iostream.html)。这是一个好方法,我们在这方面做了类似的事情,但是我们的流(zip/encrypt/send)很少,并且所有操作都使用了 boost iostreams 库。

简单而虚拟的方式 - 将您的数据存储在临时文件中并发送此文件:)

【讨论】:

【参考方案2】:

asio 文档中有一个很好的序列化example:server.cpp、stock.hpp、connection.hpp。

这是一个sn-p:

std::ostringstream archive_stream;
boost::archive::text_oarchive archive(archive_stream);
archive << your_struct;
outbound_data_ = archive_stream.str();
boost::asio::async_write(socket_, 
    boost::asio::buffer(outbound_data_), handler);

【讨论】:

奇怪,从 boost 1.57 开始,我得到了‘class boost::archive::text_oarchive’ has no member named ‘str’ 你在做 archive_stream.str(); 还是 archive.str(); ?应该是前者【参考方案3】:

我怀疑你会想先存档到内存,然后将其写入套接字。

【讨论】:

【参考方案4】:

boost 序列化档案可以用任何流构建。因此,任何 oarchive 都可以使用任何 ostream,任何 iarchive 都可以使用任何 istream。因此,您可以归档到 ostringstream,使用 asio 传输字符串,并从中重建数据。

例如参考binary_oarchivehere。

【讨论】:

我认为您的意思是“任何 iarchive 都可以使用任何 istream”【参考方案5】:

对于如此简单的结构,boost::serialization 是多余的,而且开销很大。

做的更简单:

vector<uint16_t> net(3,0);

net[0]=htons(data.m_short1);
net[1]=htons(data.m_short2);
net[2]=htons(data.character);

asio::async_write(socket,buffer((char*)&net.front(),6),callback);

vector<uint16_t> net(3,0);
asio::async_read(socket,buffer((char*)&net.front(),6),callback);

callback:
data.m_short1=ntohs(net[0]);
data.m_short2=ntohs(net[1]);
data.character=ntohs(net[2]);

并且为 boost::serialization 节省了巨大的开销

如果您使用具有相同字节顺序的计算机工作的私有协议(大/小) 只是按原样发送结构——POD。

【讨论】:

我绝对同意你关于 boost::serialization 的开销。它把我的小数据结构变成了几乎 50 字节大的东西! 这并没有回答通常如何通过网络发送序列化数据的问题(连接 Boost Serialization 和 Asio)。这只是回答了如何通过 Boost::Asio 发送特定结构的问题【参考方案6】:

我想我会与任何尝试使用 Boost 序列化 C++ struct 的人分享这个。对于上面给出的示例,要使 struct 可序列化,您将添加一个 serialize 函数:

typedef struct

  unsigned short m_short1;
  unsigned short m_short2;
  unsigned char m_character;

  template <typename Archive>
  void serialize(Archive& ar, const unsigned int version)
  
    ar & m_short1;
    ar & m_short2;
    ar & m_character;
  
 MyDataType;

【讨论】:

如果我错了,请纠正我,但是当字节通过网络传输时,boost 会在数据报的开头添加一些额外的标识符垃圾。我想知道是否可以使用该序列化技术使用 boost 序列化来序列化结构,但我认为如果没有 boost 添加到流中的额外内容(以支持编组和解组),这可能是不可能的 我用这个方法序列化了一个结构体向量,效果很好!【参考方案7】:

编辑:我在下面收回我的答案,我提出的确实比 stringstream 解决方案具有时间和空间优势,但 asio::stream API 缺少一些长期需要的重要功能(例如定时中断)。


我原来的答案:

使用来自 boost::asio 的流,相比将其写入 std::stringstreams 然后一次性发送它具有时间和空间优势。方法如下:

客户端代码:

boost::asio::ip::tcp::iostream stream("localhost", "3000");

if (!stream)
  throw std::runtime_error("can't connect");

服务器代码:

boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint
  = boost::asio::ip::tcp::endpoint(ip::tcp::v4(), 3000);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
boost::asio::ip::tcp::iostream stream;

// Your program stops here until client connects.
acceptor.accept(*stream.rdbuf()); 

然后,在您连接到客户端或服务器流之后,只需执行以下操作:

MyDataType obj;

// Send the object.
boost::archive::text_oarchive archive(stream);
archive << obj;

// Or receive it.
boost::archive::text_iarchive archive(stream);
archive >> obj;

您当然需要将“序列化”功能添加到您的 MyDataType 中,正如 Tymek 在他的回答中所写的那样。

【讨论】:

完美的答案,除了它不起作用。当我尝试将存档附加到流时,我遇到了一个错误。真正的我的是一个二进制存档,但它仍然可以工作。 好的,我看到了我的问题,我需要输入 no_header 标志。我必须通过调试来解决这个问题,boost 标头本身和文档中都没有我可以简单地找出您实际上可能将哪些标志作为第二个参数传递给流构造函数的地方。 Boost 库的实现很棒,但文档很糟糕。

以上是关于使用Boost序列化和发送数据结构?的主要内容,如果未能解决你的问题,请参考以下文章

使用谷物序列化和boost :: asio的例子?

C++ 使用 Boost.asio 和 Beast 库在正文中发送数据

在 boost 中序列化二进制数据失败并出现“无效签名”错误

如何通过 C++ 中的 boost 套接字发送 ostream?

使用 boost::asio 通过 UDP 发送结构

MPI 发送自定义序列化对象(更通用的代码)