Serialize and send a data structure using Boost?

EDIT: I take back my answer below, what I proposed does have the time and space advantages over the stringstream solution but the asio::stream API is lacking some important functionality that will be needed in a long run (e.g. timed interruption).


My original answer:

Use streams from boost::asio, it has time and space advantages over writing it into std::stringstreams and then sending it in one go. Here is how:

Client code:

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

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

Server code:

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

And then, after you are connected with either client or server stream just do:

MyDataType obj;

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

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

You of course need to add the 'serialize' function into your MyDataType as Tymek wrote in his answer.


I thought I'd share this with anyone who was trying to serialize a C++ struct using Boost. For the example given above, to make the struct serializable you would add a serialize function:

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;

For such simple structure, boost::serialization is overkill and huge overhead.

Do simpler:

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

And Save yourself HUGE overhead that boost::serialization has

And if you private protocol where computers with same order of bytes work (big/little) that just send structure as is -- POD.


There is a good serialization example in the asio documentation: server.cpp, stock.hpp, connection.hpp.

Here's a snippet:

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