2017-08-07 95 views
1

使用独立asio,我使用read_some实现了一个服务器。我的服务器循环会从套接字中累积所有收到的数据。下面的精简代码不能正常工作,但我可以通过将inbuf.prepare()语句移入循环来修复它。asio streambuf可变缓冲区类型 - 如何使用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); 
} 

当制备()是环路和读由于连接用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()的作用,为什么需要重复调​​用它?

回答

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); 
    ... 
} 

警告:这取决于频率的总数,这可能变得非常低效的“追加”由于内存分配和移动/副本。但由于我不知道你想要处理的数据,这是我能想到的最好的。

+0

在我的情况下,我可以估计在读取第一个数据块后预期的总数据大小,因此我可以调用cumulative_data.reserve()以避免频率存储器重新分配。 – edj

0

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

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

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