boost :: asio :: streambuf-如何重用缓冲区? [英] boost::asio::streambuf - how to reuse buffer?

查看:38
本文介绍了boost :: asio :: streambuf-如何重用缓冲区?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm implementing TCP server that uses both asio socket.async_read() and boost::asio::async_read_until() methods for asynchronous reading data from socket. Both use the same handler for reading data from boost::asio::streambuf.

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

The handler that perfectly works invoked via 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;
}

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

My server depending on processing of data may shutdown connection or continue reading via the same socket.

但是,如果从第二次boost :: asi :: async_read_until()调用中调用handle_read(),那么我在dataBytes中得到了零,然后有效数据就消失了.

But, if handle_read() is called from the 2-nd boost::asi::async_read_until() call, I'm getting a number of zero's in dataBytes and then valid data goes.

我尝试了一个简单的测试用例,发现在将数据写入streambuf并进行commit()+消耗()之后,streambuf中的数据仍保留先前的缓冲区.

I tried a simple test-case and found out that after writing data to streambuf, and commit() + consume() the data in streambuf still keeps previous buffer.

那么,有什么方法可以清除boost :: asio :: streambuf中的数据并在boost :: asio :: async_read_until()中重用?

So, is there any way to clear data in boost::asio::streambuf and reuse it in boost::asio::async_read_until() ?

Live Coliru

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

If compiled with USE_STREAM=1, the live example works fine. But what std::istream does different comparing with buffer consume() ?

推荐答案

在使用对streambuf进行操作的Boost.Asio操作或对使用streambuf的对象(例如std::ostreamstd::istream)进行流式处理时,基本的输入和输出序列将得到适当管理.如果将缓冲区提供给某个操作(例如,将prepare()传递给读取操作或将data()传递给写操作),则必须显式处理commit()consume().

When using Boost.Asio operations that operate on streambuf or stream objects that use a streambuf, such as std::ostream and std::istream, the underlying input and output sequences will be properly managed. If a buffer is provided to an operation instead, such as passing passing prepare() to a read operation or data() to a write operation, then one must explicitly handle the commit() and consume().

该示例中的问题是它违反了API约定,从而导致未初始化的内存被提交给输入序列. commit() 文档状态:

The issue in the example is that it violates the API contract, causing uninitialized memory to be committed to the input sequence. The commit() documentation states:

需要前面的调用prepare(x),其中x >= n,并且没有干预操作可修改输入或输出顺序.

Requires a preceding call prepare(x) where x >= n, and no intervening operations that modify the input or output sequence.

prepare()commit()之间使用std::ostream违反了此合同,因为它将修改输入顺序:

The use of the std::ostream between the prepare() and commit() violates this contract, as it will modify the input sequence:

// 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:


Here is a complete example demonstrating using streambuf with annotated comments:

#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

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

For more information on streambuf usage, consider reading this answer.

这篇关于boost :: asio :: streambuf-如何重用缓冲区?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆