boost :: asio :: streambuf - 如何重用缓冲区?

dru*_*rus 5 c++ boost boost-asio

我正在实现TCP服务器,它同时使用asio socket.async_read()和boost :: asio :: async_read_until()方法从socket中异步读取数据.两者都使用相同的处理程序从boost :: asio :: streambuf读取数据.

完全通过async_read()调用的处理程序:

void handle_read(const boost::system::error_code& ec, std::size_t ytes_transferred) )
{
    m_request_buffer.commit(bytes_transferred);
    boost::asio::streambuf::const_buffers_type rq_buf_data = m_request_buffer.data();
    std::vector<uint8_t> dataBytes(boost::asio::buffers_begin(rq_buf_data), boost::asio::buffers_begin(rq_buf_data) + bytes_transferred);

    //process data here

    m_request_buffer.consume(bytes_transferred);
    bytes_transferred = 0;
}
Run Code Online (Sandbox Code Playgroud)

我的服务器取决于数据处理可能会关闭连接或继续通过相同的套接字读取.

但是,如果从第2次boost :: asi :: async_read_until()调用调用handle_read(),我会在dataBytes中得到一些零,然后有效数据就会出现.

我尝试了一个简单的测试用例,发现在向streambuf和commit()+ consume()写入数据之后,streambuf中的数据仍然保留了先前的缓冲区.

那么,有没有办法清除boost :: asio :: streambuf中的数据并在boost :: asio :: async_read_until()中重用它?

住Coliru

如果使用USE_STREAM = 1编译,则实时示例正常工作.但是什么std :: istream与缓冲区消耗()相比有什么不同?

Tan*_*ury 8

当使用Boost.Asio操作时,操作streambuf或使用a的对象流streambuf,例如std::ostreamstd::istream,将正确管理基础输入和输出序列.如果为操作提供缓冲区,例如传递prepare()给读操作或data()写操作,则必须显式处理commit()consume().

示例中的问题是它违反了API契约,导致未初始化的内存被提交到输入序列.该commit()文件规定:

需要先前调用prepare(x)where x >= n,并且不需要修改输入或输出序列的中间操作.

使用的std::ostream之间prepare()commit()违反合同,因为它会修改输入序列:

// Prepare 1024 bytes for the output sequence.  The input sequence is
// empty.
boost::asio::streambuf streambuf;
streambuf.prepare(1024);

// prepare() and write to the output sequence, then commit the written
// data to the input sequence.  The API contract has been violated.
std::ostream ostream(&streambuf);
ostream << "1234567890";

// Commit 10 unspecified bytes to the input sequence.  Undefined
// behavior is invoked.
streambuf.commit(10);
Run Code Online (Sandbox Code Playgroud)

这是一个完整的示例,演示如何使用带有注释注释的streambuf:

#include <iostream>
#include <vector>
#include <boost/asio.hpp>

int main()
{
  std::cout << "with streams:" << std::endl;
  {
    boost::asio::streambuf streambuf;

    // prepare() and write to the output sequence, then commit the written
    // data to the input sequence.  The output sequence is empty and
    // input sequence contains "1234567890".
    std::ostream ostream(&streambuf);
    ostream << "1234567890";

    // Read from the input sequence and consume the read data.  The string
    // 'str' contains "1234567890".  The input sequence is empty, the output
    // sequence remains unchanged.
    std::istream istream(&streambuf);
    std::string str;
    istream >> str;
    std::cout << "str = " << str << std::endl;

    // Clear EOF bit.
    istream.clear();

    // prepare() and write to the output sequence, then commit the written
    // data to the input sequence.  The output sequence is empty and
    // input sequence contains "0987654321".
    ostream << "0987654321";

    // Read from the input sequence and consume the read data.  The string
    // 'str' contains "0987654321".  The input sequence is empty, the output
    // sequence remains unchanged.
    istream >> str;
    std::cout << "str = " << str << std::endl;
  }

  std::cout << "with streams and manual operations:" << std::endl;
  {
    boost::asio::streambuf streambuf;

    // prepare() and write to the output sequence, then commit the written
    // data to the input sequence.  The output sequence is empty and
    // input sequence contains "1234567890".
    std::ostream ostream(&streambuf);
    ostream << "1234567890";

    // Copy 10 bytes from the input sequence.  The string `str` contains
    // "1234567890".  The output sequence is empty and the input
    // sequence contains "1234567890".
    auto data = streambuf.data();
    std::string str(boost::asio::buffers_begin(data),
                    boost::asio::buffers_begin(data) + 10);
    std::cout << "str = " << str << std::endl;

    // Consume 10 bytes from the input sequence.  The input sequence is
    // now empty.
    streambuf.consume(10);

    // prepare() and write to the output sequence, then commit the written
    // data to the input sequence.  The output sequence is empty and
    // input sequence contains "0987654321".
    ostream << "0987654321";

    // Copy 10 bytes from the input sequence.  The string `str` contains
    // "0987654321.  The output sequence is empty and the input
    // sequence contains "0987654321".    
    data = streambuf.data();
    str.assign(boost::asio::buffers_begin(data),
               boost::asio::buffers_begin(data) + 10);
    std::cout << "str = " << str << std::endl;

    // Consume 10 bytes from the input sequence.  The input sequence is
    // now empty.
    streambuf.consume(10);
  }
}
Run Code Online (Sandbox Code Playgroud)

输出:

with streams:
str = 1234567890
str = 0987654321
with streams and manual operations:
str = 1234567890
str = 0987654321
Run Code Online (Sandbox Code Playgroud)

有关streambuf使用的更多信息,请考虑阅读答案.