提升 ASIO streambuf

Boost ASIO streambuf

我对boost中的输入序列和输出序列感到困惑asio::streambuf 类。

根据文档中的代码示例(用于发送数据),表示输入序列的缓冲区似乎用于写入套接字,而表示输出序列的缓冲区用于读取。

例子-

boost::asio::streambuf b;
std::ostream os(&b);
os << "Hello, World!\n";
// try sending some data in input sequence
size_t n = sock.send(b.data());
b.consume(n); // sent data is removed from input sequence

现在,有命名问题吗?

"Everything is relative"

Albert Einstein

documentation 说:

Characters written to the output sequence of a basic_streambuf object are appended to the input sequence of the same object.

streambuf 的角度来看,它将从其输出序列中读取并写入其输入序列,这可能看起来有点颠倒,但您可以将 streambuf 视为pipe 让事情变得有意义。

现在从用户(任何使用 streambuf 的东西,包括套接字)的角度来看,您将写入 streambuf 的输出序列并从其输入序列中读取这似乎更多自然。

所以是的,左右颠倒的方式相同,具体取决于您面对的是什么,输入和输出也会颠倒,具体取决于您从哪一侧看它。

"Don't believe every quote you read on the internet, because I totally didn't say that"

Albert Einstein

boost::asio::streambuf 的命名法类似于 C++ 标准中定义的命名法,并在标准模板库中用于各种 类,其中数据被写入输出流,并且从输入流中读取数据。例如,可以使用 std::cout.put() 写入输出流,使用 std::cin.get() 从输入流读取。

手动控制streambuf输入输出序列时,数据的一般生命周期如下:

  • 为输出序列分配 prepare() 缓冲区。
  • 数据写入输出序列的缓冲区后,数据将被commit()编辑。此已提交的数据将从输出序列中删除并附加到可从中读取的输入序列。
  • 数据从通过 data() 获得的输入序列缓冲区中读取。
  • 读取数据后,可以通过 consume() 从输入序列中删除它。

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

这是示例代码的注释版本,它直接从 streambuf 写入套接字:

// The input and output sequence are empty.
boost::asio::streambuf b;
std::ostream os(&b);

// 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 "Hello, World!\n".
os << "Hello, World!\n";

// Read from the input sequence, writing to the socket.  The input and
// output sequences remain unchanged.
size_t n = sock.send(b.data());

// Remove 'n' bytes from the input sequence. If the send operation sent
// the entire buffer, then the input sequence would be empty.
b.consume(n);

这里是从套接字直接读取到 streambuf 的注释示例。注释假定单词 "hello" 已在套接字上收到,但尚未读取:

boost::asio::streambuf b;

// prepare() 512 bytes for the output sequence.  The input sequence
// is empty.
auto bufs = b.prepare(512);

// Read from the socket, writing into the output sequence.  The
// input sequence is empty and the output sequence contains "hello".
size_t n = sock.receive(bufs);

// Remove 'n' (5) bytes from output sequence appending them to the
// input sequence.  The input sequence contains "hello" and the
// output sequence has 507 bytes.
b.commit(n);

// The input and output sequence remain unchanged.
std::istream is(&b);
std::string s;

// Read from the input sequence and consume the read data.  The string
// 's' contains "hello".  The input sequence is empty, the output
// sequence remains unchanged.
is >> s;

注意在上面的例子中,steam 对象是如何处理提交和消耗 streambuf 的输出和输入序列的。但是,当使用缓冲区本身时(即 data()prepare()),代码需要显式处理提交和使用。