asio streambuf可变缓冲区类型 - 如何使用prepare()

时间:2017-08-07 17:39:17

标签: asio

使用独立的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()的作用,以及为什么需要反复调用它?

2 个答案:

答案 0 :(得分:1)

streambuf实现为具有自定义分配器的std::vector<char>prepare只需分配请求的内存量。它不需要被多次调用。

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

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

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

答案 1 :(得分:0)

Asio :: buffer只是一个容器。 有关更多详细信息,请访问here

当调用asio :: buffer时,OS和Complier不知道应该为它分配多少内存。所以buffer.prepare(/ * Memory Size * /)被称为成员函数来提供该空间。

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