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