I have client-server application. I have no trouble when I sent a few KBs of data, but when the data grow to 2-4 MB data transfer speed was extremely reduced. I modified an example and use text_archive(because of this) to serialize my data structures, but its didn't help me. It appears that to write 2-4 MB to text_archive takes 6-7 seconds, and read from text_archive takes 10-18 seconds. My structs consisted of few vectors and had more data, but common implementation looked like this:
template <typename Archive>
void serialize(Archive& ar, const unsigned int version)
{
ar & code;
ar & name;
...
}
But why it takes so long? I have no idea. I was obliged to reject this approach.
I searched the solution, and probably I found it. It is std::istream/ostream. But my implementation seems a kind of crutch. Here is my code:
class connection
{
private:
/// The underlying socket.
boost::asio::ip::tcp::socket socket_;
/// binary stream in
boost::asio::streambuf readStreambuf;
std::istream readStream;
/// binary stream out
boost::asio::streambuf writeStreambuf;
std::ostream writeStream;
public:
/// Constructor.
connection(boost::asio::io_service& io_service)
: socket_(io_service), readStream(&readStreambuf), writeStream(&writeStreambuf)
{
}
...
/// Asynchronously write a data structure to the socket.
template <typename T, typename Handler>
void async_write(const T& t, Handler handler)
{
writeStream.clear();
writeStream << t;
writeStream << "Close connection \r\n\r\n";
//is it make sense?
socket_.set_option(boost::asio::ip::tcp::no_delay(true));
boost::system::error_code ec;
socket_.set_option(boost::asio::socket_base::send_buffer_size(1024 * 1024 * 5), ec);
//
boost::asio::async_write(socket_, writeStreambuf, handler);
}
/// Asynchronously read a data structure from the socket.
template <typename T, typename Handler>
void async_read(T& t, Handler handler)
{
void (connection::*func)(const boost::system::error_code&, T&, boost::tuple<Handler>) = &connection::handle_read_stream<T, Handler>;
boost::asio::async_read_until(socket_, readStreambuf, "Close connection \r\n\r\n", boost::bind(func, this, boost::asio::placeholders::error, boost::ref(t), boost::make_tuple(handler)));
}
template <typename T, typename Handler>
void handle_read_stream(const boost::system::error_code& e,
T& t, boost::tuple<Handler> handler)
{
if (e)
{
boost::get<0>(handler)(e);
}
else
{
try
{
readStream.clear();
readStream >> t;
}
catch (std::exception& e)
{
// Unable to decode data.
boost::system::error_code error(boost::asio::error::invalid_argument);
boost::get<0>(handler)(error);
return;
}
// Inform caller that data has been received ok.
boost::get<0>(handler)(e);
}
}
writeStream << t
and readStream >> t
works pretty fast, but I have a bad feeling about writeStream << "Close connection \r\n\r\n"
. Is it right?
It works, but I think it works wrong.
Should I pass the number of bytes instead? But how? How do it properly?