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() ?
如果使用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::ostream
和std::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)
wherex >= 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.