On 25/05/2018 02:59, Stephan Menzel wrote:
once again I find myself struggling with asio streambufs but wanted to ask here before chicken out to char buffers again. My problem is that I cannot read more than one protocol loop successfully. [...] asio::async_read_until(m_socket, m_streambuf, "\r\n", [...] asio::async_read(m_socket, m_streambuf, boost::asio::transfer_exactly(n_header_size),
Mixing read_until and read on the same socket is problematic, because the way they actually behave -- while not actually wrong -- is not what you first expect. There are two key bits of information you need to realise the problem: 1. async_read_until actually calls async_read_some under the hood to read an arbitrary amount of data from the socket. All the data is stored in the streambuf and only a *subset* of that length is returned to indicate where the terminator was found. 2. async_read just calls async_read_some directly with the specified length request. In particular, even if #1 already read the entire message into the streambuf, #2 will ignore that and still wait for the specified number of new incoming bytes -- even if you are reading into the same streambuf. The solution to this is pretty straightforward, once you realise that you need to do it: Instead of calling async_read with the total number of bytes you are expecting in the message body, first check how many bytes are already available in the streambuf (via size()), and only issue a read for the balance (and if the balance is 0 or negative, then obviously don't issue the read at all). In an ideal world, async_read would do this for you, but it doesn't. (And it does make sense that it doesn't, once you think about it -- otherwise multiple consecutive reads without consuming the data would just return the same data over and over instead of appending it.)