长度未知时如何读取数据?
How to read data when length is unknown?
我目前正在使用 boost::asio 跨网络连接读取数据,但我选择了一种我认为无效的模式:
auto listener::read(std::function<void(std::error_code ec, packet packet)> callback) noexcept -> void {
m_buffer.resize(1);
m_buffer.shrink_to_fit();
asio::async_read(*m_socket, asio::buffer(m_buffer), asio::transfer_exactly(1),
[&, callback](std::error_code ec, std::size_t length) {
const auto available = m_socket->available();
packet tmp;
tmp.resize(available);
asio::async_read(*m_socket, asio::buffer(tmp), asio::transfer_exactly(available));
tmp.insert(tmp.begin(), std::make_move_iterator(m_buffer.begin()),
std::make_move_iterator(m_buffer.end()));
callback(ec, std::move(tmp));
});
}
(packet
是 std::vector<unsigned char>
)
我不确定如何在没有临时文件的情况下创建它。一开始我无法调整 m_buffer
的大小,因为我不知道有多少数据来了。我尝试使用 m_buffer
仅在 lambda 中调整大小以匹配 available
+ 1 但我最终丢失了存储在 m_buffer
.
中的第一个字节
当期待未知长度的数据包时,是否有更有效的方法来执行此操作?
首先,你不能这样做:
asio::async_read(*m_socket, asio::buffer(tmp), asio::transfer_exactly(available)); //[1]
tmp.insert(tmp.begin(), std::make_move_iterator(m_buffer.begin()),
std::make_move_iterator(m_buffer.end())); // [2]
in [1] 异步操作开始。 async_read
returns 立即。然后我们有两个并发操作,第一个插入 tmp
,第二个(异步操作)用一些数据填充 tmp
。
可以使用同步操作:asio::read
代替asio::async_read
,前者是阻塞函数,所以insert
只在数据读完后执行。
如果你不想玩连接向量、创建临时对象等,你可以使用 boost::asio::dynamic_buffer:
struct listener {
vector<char> m_buffer;
// others members
};
void listener::read(std::function<void(std::error_code ec, packet p)> callback)
{
boost::asio::async_read(m_socket, boost::asio::dynamic_buffer(m_buffer), boost::asio::transfer_exactly(1),
^^^^^^^^^^^^^
[&, callback](std::error_code ec, std::size_t length)
{
const auto available = m_socket.available();
boost::asio::async_read(m_socket, boost::asio::dynamic_buffer(m_buffer),
^^^^^^^^^^^^^
boost::asio::transfer_exactly(available),
[this,callback](const boost::system::error_code& ec, size_t)
{
callback(ec, std::move(m_buffer));
});
});
}
m_buffer
由 异步操作 自动增加。你不用手动做。如您所见,我添加了新的处理程序 -> where is called callback(ec,move(m_buffer))
。当调用此处理程序时,我们知道读取操作结束。
我目前正在使用 boost::asio 跨网络连接读取数据,但我选择了一种我认为无效的模式:
auto listener::read(std::function<void(std::error_code ec, packet packet)> callback) noexcept -> void {
m_buffer.resize(1);
m_buffer.shrink_to_fit();
asio::async_read(*m_socket, asio::buffer(m_buffer), asio::transfer_exactly(1),
[&, callback](std::error_code ec, std::size_t length) {
const auto available = m_socket->available();
packet tmp;
tmp.resize(available);
asio::async_read(*m_socket, asio::buffer(tmp), asio::transfer_exactly(available));
tmp.insert(tmp.begin(), std::make_move_iterator(m_buffer.begin()),
std::make_move_iterator(m_buffer.end()));
callback(ec, std::move(tmp));
});
}
(packet
是 std::vector<unsigned char>
)
我不确定如何在没有临时文件的情况下创建它。一开始我无法调整 m_buffer
的大小,因为我不知道有多少数据来了。我尝试使用 m_buffer
仅在 lambda 中调整大小以匹配 available
+ 1 但我最终丢失了存储在 m_buffer
.
当期待未知长度的数据包时,是否有更有效的方法来执行此操作?
首先,你不能这样做:
asio::async_read(*m_socket, asio::buffer(tmp), asio::transfer_exactly(available)); //[1]
tmp.insert(tmp.begin(), std::make_move_iterator(m_buffer.begin()),
std::make_move_iterator(m_buffer.end())); // [2]
in [1] 异步操作开始。 async_read
returns 立即。然后我们有两个并发操作,第一个插入 tmp
,第二个(异步操作)用一些数据填充 tmp
。
可以使用同步操作:asio::read
代替asio::async_read
,前者是阻塞函数,所以insert
只在数据读完后执行。
如果你不想玩连接向量、创建临时对象等,你可以使用 boost::asio::dynamic_buffer:
struct listener {
vector<char> m_buffer;
// others members
};
void listener::read(std::function<void(std::error_code ec, packet p)> callback)
{
boost::asio::async_read(m_socket, boost::asio::dynamic_buffer(m_buffer), boost::asio::transfer_exactly(1),
^^^^^^^^^^^^^
[&, callback](std::error_code ec, std::size_t length)
{
const auto available = m_socket.available();
boost::asio::async_read(m_socket, boost::asio::dynamic_buffer(m_buffer),
^^^^^^^^^^^^^
boost::asio::transfer_exactly(available),
[this,callback](const boost::system::error_code& ec, size_t)
{
callback(ec, std::move(m_buffer));
});
});
}
m_buffer
由 异步操作 自动增加。你不用手动做。如您所见,我添加了新的处理程序 -> where is called callback(ec,move(m_buffer))
。当调用此处理程序时,我们知道读取操作结束。