繁体   English   中英

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

[英]boost::asio::streambuf - how to reuse buffer?

我正在实现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;
}

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

但是,如果从第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与缓冲区消耗()相比有什么不同?

当使用上操作Boost.Asio的操作streambuf使用一个或流对象streambuf ,如std::ostreamstd::istream ,底层的输入和输出序列将进行适当的管理。 如果为操作提供了缓冲区,例如将prepare()传递给read操作或者将data()传递给write操作,则必须显式处理commit()consume()

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

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

prepare()commit()之间使用std::ostream违反了这个契约,因为它将修改输入序列:

// 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);

这是一个完整的示例, 演示如何使用带有注释注释的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);
  }
}

输出:

with streams:
str = 1234567890
str = 0987654321
with streams and manual operations:
str = 1234567890
str = 0987654321

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM