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

C++ 长度未知时如何读取数据?,c++,c++11,boost-asio,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::buffe

我目前正在使用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));
                   });
}
autolistener::read(std::函数回调)noexcept->void{
m_缓冲区。调整大小(1);
m_buffer.收缩到_fit();
asio::async_read(*m_套接字,asio::buffer(m_buffer),asio::transfer_正好(1),
[&,回调](std::error_code ec,std::size_t length){
const auto available=m_socket->available();
分组tmp;
tmp.resize(可用);
asio::async_read(*m_套接字,asio::buffer(tmp),asio::transfer_精确(可用));
插入(tmp.begin(),std::make_move_迭代器(m_buffer.begin()),
std::make_move_迭代器(m_buffer.end());
回调(ec,std::move(tmp));
});
}
packet
std::vector

我不知道如何在没有临时文件的情况下创建这个。一开始我无法调整m_buffer的大小,因为我不知道有多少数据。我试图使用
m_buffer
仅在lambda中调整大小以匹配
可用的
+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]中,异步操作开始<代码>异步读取立即返回。然后我们有两个并发操作,第一个插入到
tmp
,第二个(异步操作)通过一些数据填充
tmp
。 您可以使用同步操作:
asio::read
而不是
asio::async\u read
,前者是阻塞功能,因此只有在读取数据时才执行
insert


如果不想使用连接向量、创建临时对象等,可以使用boost::asio::dynamic\u 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));
                   });
            });
}
struct侦听器{
向量m_缓冲区;
//其他成员
};
void listener::read(std::函数回调)
{
boost::asio::async_读取(m_套接字,boost::asio::dynamic_缓冲区(m_缓冲区),boost::asio::transfer_精确(1),
^^^^^^^^^^^^^
[&,回调](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_完全(可用),
[this,callback](常量boost::system::error\u code&ec,size\t)
{
回调(ec,std::move(m_buffer));
});
});
}

m_buffer
通过异步操作自动增加。你不需要手动操作。如您所见,我添加了新的处理程序->其中被称为
回调(ec,move(m_buffer))
。调用此处理程序时,我们知道读取操作结束。

数据包
这是有效的?@user463035818(但这是一个错误的命名选择)不熟悉boost的这一部分,但通常情况下,如果您不知道在数据传输之前有多少数据,那么发送方的设计就相当糟糕。理想情况下,发送方应该在数据前面加上数据长度,以便您可以相应地进行分配。如果这是不可能的,您基本上只需猜测,分配一大块内存,读取直到流结束或该块已满,将该块放在其他位置,然后重新开始读取缓冲区,重复步骤直到EOS,然后合并块。@rafix07这是您昨天回答的问题的读取结果。这是一个lambda。要回显@Prodigle,如果传输量有上限,可以调整大小到上限,一次读取,然后调整大小到接收中读取的大小。这就是std::size\u t length
的作用:我必须在第一次异步读取()之前调用m\u buffer.clear()。