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

时间:2009-03-16 21:19:53

标签: c++ serialization boost boost-asio

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

typedef struct
{
  unsigned short m_short1;
  unsigned short m_short2;
  unsigned char m_character;
} MyDataType;

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

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

我很确定我有适合工作的工具 - 我只是需要帮助才能让它们协同工作。写入套接字与写入文件不一样,对吗?

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

7 个答案:

答案 0 :(得分:29)

asio文档中有一个很好的序列化exampleserver.cppstock.hppconnection.hpp

这是一个片段:

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

答案 1 :(得分:21)

我想我会与那些试图使用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;

答案 2 :(得分:6)

对于这样简单的结构,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。

答案 3 :(得分:4)

编辑:我收回下面的答案,我提出的建议确实比字符串流解决方案具有时间和空间优势,但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;

你当然需要在Tymek的答案中写下你的MyDataType中的'serialize'函数。

答案 4 :(得分: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库进行所有操作。

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

答案 5 :(得分:1)

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

例如,请参阅binary_oarchive here的参考。

答案 6 :(得分:0)

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