c++ - 长度未知时如何读取数据?

标签 c++ c++11 boost-asio

我目前正在使用 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));
                   });
}

( packetstd::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]

在[1]异步操作开始。 async_read 立即返回。然后我们有两个并发操作,第一个插入 tmp,第二个(异步操作)用一些数据填充 tmp。 可以使用同步操作:asio::read代替asio::async_read,前者是阻塞函数,所以insert只有在数据已读取。


如果您不想尝试连接 vector 、创建临时对象等,您可以使用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异步操作 自动增加。你不用手动做。如您所见,我添加了新的处理程序 -> 称为 callback(ec,move(m_buffer)) 的地方。当调用此处理程序时,我们知道读取操作结束。

关于c++ - 长度未知时如何读取数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54554207/

相关文章:

c++ - 用于非虚拟和私有(private)函数的 Google Mock

c++ - 禁用非完全专用模板类的构造

c++ - boost 信号和插槽在不同线程中不工作(使用 boost::asio::io_service)

c++ - 在 VC++ 2005 中使用日期时间

c++ - 为什么没有默认的 move 分配/move 构造函数?

c++ - 模板函数和 vector 访问

c++ - boost::asio: "strand"类型的同步原语有什么名字吗?

ubuntu - stream_descriptor 的 boost::asio::async_read() 现在返回 EOF

c++ - 如何在资源文件中添加 Ⓒ 符号以支持日文 Windows 操作系统。

c++ - 使用 C++ 在 Windows 中更新 PATH 环境变量