Search code examples
boost-asioasio

Server written using asio (non boost) library gets the data only after a client disconnects


This is my server session code that should read the incoming client data asynchronously. I am using a free standing read function. When I tested this using Google Test(using local host, and both client and server on same computer), it worked fine. I was able to connect to server using my test client and server used to establish connection and read the data coming from client.

But when I tested in client and server running on different computers, I observed that after connection is established, Server only receives first of the N data items sent by client. And that too when client disconnects after it has finished writing.

My head is spinning and I am not able to find out why. Any help is much appreciated.

Thanks

void ServerSession::doRead()
    {
        asio::async_read(socket_, asio::buffer(data_,maxLength),
        [this](std::error_code ec, std::size_t length)
        {
            if(!ec || ec == asio::error::eof)
            {
                std::string msg{data_, length};
                
                addMessageToQueue(std::move(msg));
                
            }
            else
            {
                  socket_.close(); //force close the socket upon read error.
            }
        });
    }

Solution

  • async_read is documented as:

    This function is used to asynchronously read a certain number of bytes of data from a stream. It is an initiating function for an asynchronous operation, and always returns immediately. The asynchronous operation will continue until one of the following conditions is true:

    • The supplied buffers are full. That is, the bytes transferred is equal to the sum of the buffer sizes.
    • An error occurred.

    Apparently neither condition is satisfied until the client disconnects (which satisfies the criteria with the asio::error::eof error code).

    Usually you need to

    • use an application protocol with framing (such as \r\n\r\n, Content-Length or chunked encoding for HTTP) and an CompletionCondition that expresses that. You can also use one of the overloads of async_read_until which allows some common completion conditions.

    • Alternatively you can reduce the maxLength to be practically much smaller than the expected payload so you will likely get an earlier completion

    • Finally you can "de-optimize" by using the lowlevel AsyncReadStream operation async_read_some directly. As e.g. the documentation for tcp::socket::async_read_some highlights, this is rarely what you want:

      The read operation may not read all of the requested number of bytes. Consider using the async_read function if you need to ensure that the requested amount of data is read before the asynchronous operation completes)