我有特定格式的数据流,我需要在网络中读/写。目前,我在 boost::asio 中使用
boost::asio::streambuf
和 async_* 函数。有时,我需要尽快读取 ssl 套接字上可用的所有数据,但我不明白如何正确地做到这一点。
现在我正在像这样从 ssl 套接字读取数据:
// m_ssl_stream is ssl socket stream
// m_buffer is a boost::asio::streambuf
boost::asio::async_read(ssl_stream, m_buffer, boost::asio::transfer_at_least(1), callback);
但是有一个问题。例如,我在 ssl 套接字中有 20.000 个可用字节,但我无法在一次读取操作中读取所有这些数据,因为完成条件
boost::asio::transfer_at_least(1)
通常返回 512 个字节。结果,我在 35-40 次读取操作中读取所有可用数据,而不是 1-2 次。
m_buffer 还用于其他异步操作,可以安排从与其他 async_* 函数相同的数据流中读取。例如,在使用
boost::asio::async_read(ssl_stream, m_buffer, boost::asio::transfer_at_least(1), callback);
读取数据后,如果我的流状态发出信号,我可以使用 boost::beast::http::async_read_header
“去”读取 http 标头。在这种情况下,标头必须出现在boost::asio::streambuf
中才能在其他异步操作中成功读取标头。
我认为可以使用 m_ssl_stream.async_read_some 操作来完成,但是这个操作不能接受
boost::asio::streambuf
作为缓冲区。
有人知道我该如何实现吗?
我认为可以使用 m_ssl_stream.async_read_some 操作来完成
我认为相反。事实上,所有组合读取操作(如
asio::async_read
)都是 always 根据一个或多个 s.async_read_some
操作指定的,这实际上是 AsyncReadStream
概念上指定的唯一操作。
你需要做的是明确你的意图。当您期望 20'000 字节时,为什么
transfer_at_least(1)
?
async_read(ssl_stream, m_buffer, asio::transfer_at_least(1), callback);
可能是
async_read(ssl_stream, m_buffer, asio::transfer_exactly(20'000), callback);
此外,当您不知道有效负载的预期大小(例如
Content-Length
)时,您通常可以使用具有合适条件/模式的async_read_until
:
async_read_until(ssl_stream, m_buffer, "\r\n\r\n", callback);
请注意,所有具有动态缓冲区的版本都可能比满足完成条件读取更多。然而,在完成时,
bytes_transferred
反映了满足条件的字节数。因此通常的模式是:
void callback(error_code ec, size_t bytes_transferred) {
if (ec.failed()) {
// handle...
return;
}
// use m_buffer...
m_buffer.consume(bytes_transferred); // keeps remaining buffer content
}