Столкнулся с такой особенностью.
Есть сокет и стиримбуфер:
asio::ip::tcp::socket m_socket;
asio::streambuf m_readbuf;
Сначала я читаю заголовок функцией async_read_until():
asio::async_read_until(m_socket, m_readbuf, delim,
[this](const asio::error_code& e, std::size_t bytes)
{
//...
});
asio::async_read(m_socket, m_readbuf, asio::transfer_exactly(nBytes),
[this](const asio::error_code& e, std::size_t bytes)
{
//...
});
Если последовательно запустить async_read_until(), то получим прочитанные данные корректно, то есть хэндлеры будут вызваны и значения bytes будут правильными. Пробовал запускать async_read() первой, в этом случае поведение ожидаемое: вызов хэндлера с запрошенным количеством прочитанных байт.
Для реализации ожидаемого поведения, то есть возвращения запрошенного количества байт в хэндлере, сделал я свою функцию read() следующим образом:
void Connection::read(unsigned int nBytes, std::function<OnReadCompleted> handler)
{
asio::async_read(m_socket, m_readbuf, asio::transfer_exactly(nBytes),
[nBytes, handler, this](const asio::error_code& e, std::size_t bytes)
{
std::vector<char> data;
if (e == asio::error::eof)
{
std::size_t size = (nBytes <= m_readbuf.size() ) ? nBytes : m_readbuf.size();
if (size > 0)
{
std::istream in(&m_readbuf);
data.resize(size, 0);
if (in.read( (char*)&data[0], size) )
{
asio::error_code ec;
handler(ec, data);
}
else
{
handler(asio::error::fault, data);
}
}
else
{
handler(asio::error::eof, data);
}
}
else
{
if (bytes > 0)
{
std::istream in(&m_readbuf);
data.resize(bytes, 0);
if ( !in.read( (char*)&data[0], bytes) )
{
data.clear();
}
}
handler(e, data);
}
});
}