Arne Kjetil Andersen
Arne Kjetil Andersen

Reputation: 483

boost asio streambuf garbage after all data received from client

I'm writing a small boost asio tcp server and client that sends and receives plain text. The communication is more or less request response. During testing I figured I'd just spam the server with data, sending it 100.000 requests.

The message sent from the client to the server:

\n=BEGIN 1,test\n
Hello World: 1
\n=END\n

In the above message the counter goes from 0 to 99.999 (in the above example it is 1 as in "BEGIN 1" and "Hello World: 1").

As stated, this works fine and all 100.000 messages are received by the server, but once all is transferred, the read-handler is invoked up to several times more, although no data is sent from the client.

Reading the data from the streambuf object yields remnants of older messages as in:

IN 61868,test\n
Hello World: 61868
\n=END\n

And:

=END\n
=END\n

The weird thing is that it only seems to happen when the number of messages exceeds a certain amount, but it's not consistent, leading me to believe there is some overflow or UB going on somewhere, and as such I clearly have done something wrong, but I cannot seem to be able to figure out what. The code for reading is:

 typedef boost::shared_ptr<boost::asio::streambuf>       asio_streambuf_ptr;
 typedef boost::shared_ptr<boost::asio::ip::tcp::socket> asio_socket_ptr;

 ...

 void on_read(const asio_socket_ptr& s, const asio_streambuf_ptr& b,
     const boost_error_code& e, size_t length) {

   if ( !e ) {

       std::string temp(boost::asio::buffer_cast<const char*>(b->data()), length);
       //process temp

       b->consume(length);
   } else {
       //Handle the error - or close the socket if disconnected
       handle_error(s, e);
   }

   read(s, b);
 }

 void read(const asio_socket_ptr& s, const asio_streambuf_ptr& buf) {

     if (s->is_open()) {
       boost::asio::async_read_until(*s, *buf, "\n=END\n",
           boost::bind(on_read, s, buf, boost::asio::placeholders::error,
             boost::asio::placeholders::bytes_transferred));
     }
 }

My first implementation of the on_read function used std::istream and std::getline to read each message line by line, but the problem was present there as well, and since the streams are hard to inspect in gdb i rewrote it to make it easier to look into.

Now I must stress that I am new to boost-asio, and that this is my first attempt at making something useful with that part of boost, and as such I do accept that I could well be missunderstanding several of concepts of the asynchronous io system.

So my question: Has anyone experienced this before or have any suggestion to what I'm doing wrong?

I've made an SSCCE, but as it involves a fair amount of code being a server and a client, I think I'll wait to post it here until someone requests it.

Update: The issue seems to be that the client writes messages faster than the server can read them. Throttling the client slightly fixed the issue. Note: Changing the internal buffer sizes did not help, so it seems that the client flooded some os-network buffers or something to that effect.

Upvotes: 3

Views: 1260

Answers (1)

David Feurle
David Feurle

Reputation: 2787

You shouldn't continue reading in case of an error -> only when no error is detected. Perhaps you continue reading after the EOF? Move the call to read in the function on read in the if.

Upvotes: 1

Related Questions