Question

I have a data structure that looks like this:

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

I want to use boost::serialization to serialize this data structure, then use boost::asio to transmit it via TCP/IP, then have another application receive the data and de-serialize it using the same boost libraries.

I'm trying to following boost::serialization tutorial, (as some other SO questions have suggested) but the example is specifically for writing/reading to a file, not to a socket using boost::asio.

I'm pretty sure I've got the right tools for the job -- I just need help making them work together. Writing to a socket can't be that different from writing to a file, right?

Any suggestions are very much appreciated. Thanks!

Was it helpful?

Solution

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.

OTHER TIPS

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

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;

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.

You doing serialization to boost::archive which get constructor parameter - destination stream, where you will save data. You could use boost.iostreams library for define your own stream which will send data over network, instead file or just use asio socket streams (http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/reference/ip__tcp/iostream.html). It is a good way, we did something similar on this, but we have few streams (zip/encrypt/send) and used boost iostreams library for all operation.

Easy and dummy way - store your data in temporary file and send this file :)

The boost serialization archives can be constructed with any stream. Thus any oarchive can use any ostream, and any iarchive can use any istream. Thus you can archive to an ostringstream, transmit the string with asio, and reconstruct the data from that.

See the reference of binary_oarchive here, for example.

I suspect you'll want to archive to memory first, and then write that to the socket.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top