1

使用独立的 asio,我用 read_some 实现了一个服务器。我的服务器循环累积从套接字接收到的所有数据。下面的精简代码不能正常工作,但我可以通过将 inbuf.prepare() 语句移动到循环中来修复它。

asio::streambuf inbuf;
asio::streambuf::mutable_buffers_type inbufs = inbuf.prepare(4096);
while( connected )
{
    asio::error_code ec;
    size_t bytes_read = Socket().read_some(inbufs,ec);
    inbuf.commit(bytes_read);
    std::string s = std::string(asio::buffers_begin(inbufs),
            asio::buffers_begin(inbufs) + inbuf.size());
    inbuf.consume(bytes_read);
}

当 prepare() 在循环之外并且自建立连接以来读取的总字节数越过 4096 边界时,字符串 s 将仅具有到达该边界的数据。换句话说,s 将比 bytes_read 短。我推测如果我想将 prepare() 保留在循环之外,我需要一个如下所示的消费循环,但这也不起作用。

asio::streambuf inbuf;
asio::streambuf::mutable_buffers_type inbufs = inbuf.prepare(4096);
while( connected )
{
    asio::error_code ec;
    size_t bytes_read = Socket().read_some(inbufs,ec);
    while(bytes_read > 0)
    {
        inbuf.commit(bytes_read);
        std::string s = std::string(asio::buffers_begin(inbufs),
            asio::buffers_begin(inbufs) + inbuf.size());
        inbuf.consume(inbuf.size());
        bytes_read -= s.size();
    }
}

谁能澄清 prepare() 的作用,以及为什么需要重复调​​用它?

4

2 回答 2

1

streambufstd::vector<char>使用自定义分配器实现。prepare只是分配请求的内存量。它不需要多次调用。

为了保留所有接收到的数据,您只需将累加器移到主循环之外:

std::string accumulated_data;
while (connected) {
  ...
  accumulated_data.append(
      boost::asio::buffers_begin(inbufs),
      boost::asio::buffers_begin(inbufs) + bytes_read);
  ...
}

警告:这可能会变得非常低效,具体取决于由于内存分配和移动/复制而导致的“追加”的频率和总数。但由于我不知道你想用这些数据做什么,这是我能想到的最好的。

于 2017-08-17T17:31:23.393 回答
0

Asio::buffer 只是一个容器。欲了解更多详细信息,请访问这里

当 asio::buffer 被调用时,操作系统和编译器不知道应该分配多少内存给它。因此 buffer.prepare(/* Memory Size */) 被称为成员函数来提供该空间。

总是建议分配一定大小的内存来缓冲,如果没有接收或传输的数据可能会出现乱码。

于 2017-08-20T04:00:11.227 回答