gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:22:23 26 4
gpt4 key购买 nike

我正在实现使用 asio socket.async_read() 和 boost::asio::async_read_until() 方法从套接字异步读取数据的 TCP 服务器。两者都使用相同的处理程序从 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;
}

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

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

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

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

Live Coliru

如果使用 USE_STREAM=1 进行编译,则实际示例运行良好。但是 std::istream 与 buffer consume() 相比有何不同?

最佳答案

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

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

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

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

这是一个完整的 demonstrating 示例,它使用带有注释注释的 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 用法的更多信息,请考虑阅读 this 答案。

关于c++ - boost::asio::streambuf - 如何重用缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37372993/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com