首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >boost::asio::streambuf -如何重用缓冲区?

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

Stack Overflow用户
提问于 2016-05-22 10:12:27
回答 1查看 11.6K关注 0票数 7

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

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

代码语言:javascript
复制
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;
}

我的服务器依赖于对数据的处理,可能会关闭连接或通过同一个套接字继续读取。

但是,如果handle_read()是从第二个boost::asi::async_read_until()调用中调用的,我将在dataBytes中得到一个零的值,然后有效的数据就会出现。

我尝试了一个简单的测试用例,发现在将数据写入streambuf之后,并提交()+消费(),streambuf中的数据仍然保留先前的缓冲区。

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

活Coliru

如果使用USE_STREAM=1进行编译,则该活生生的示例可以正常工作。但是,与缓冲区消耗()相比,istream有什么不同呢?

EN

回答 1

Stack Overflow用户

发布于 2016-05-23 00:54:35

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

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

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

std::ostreamprepare()commit()之间的使用违反了该契约,因为它将修改输入序列:

代码语言:javascript
复制
// 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:

代码语言:javascript
复制
#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);
  }
}

输出:

代码语言:javascript
复制
with streams:
str = 1234567890
str = 0987654321
with streams and manual operations:
str = 1234567890
str = 0987654321

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

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37372993

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档