你能为Asio的read_until设置一个字节限制吗?

时间:2017-01-17 21:09:11

标签: c++ boost boost-asio

我正在使用boost::asio::read_until从套接字读取,直到收到"<EOF>"为止。但是,有人可能会发送数十亿和数十亿字节,直到系统耗尽RAM并且必须关闭。

为避免这种情况,我想将限制设为read_until。喜欢&#34;阅读"<EOF>"或直到达到10MB&#34;。

使用read_until是否有一个简单的解决方案,或者我必须切换到read并在收到"<EOF>"时手动结束阅读?

3 个答案:

答案 0 :(得分:6)

@sehe有一个很好的答案,允许停止EOF或读取特定数量的字节。我的版本稍微复杂一些,但另外允许在任何分隔符上停止。

你可以使用max size参数construct你的boost :: asio :: streambuf:

  

basic_streambuf的构造函数接受size_t参数,该参数指定输入序列和输出序列的大小总和的最大值。在basic_streambuf对象的生命周期中,以下不变量成立:

     

size() <= max_size()

     

如果成功导致违反不变量的任何成员函数将抛出类std :: length_error的异常。

或者您可以使用此重载:

template<
    typename SyncReadStream,
    typename Allocator,
    typename MatchCondition>
std::size_t read_until(
    SyncReadStream & s,
    boost::asio::basic_streambuf< Allocator > & b,
    MatchCondition match_condition,
    boost::system::error_code & ec,
    typename enable_if< is_match_condition< MatchCondition >::value >::type *  = 0);

匹配条件函数看起来像这样:

using iterator = buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>;
/**
\brief Make read_until stop when either: 
    * the stop character was found
    * more than 100MB have been read
*/
pair<iterator, bool> match_condition(iterator begin, iterator end) {
   // to much data?
   if(end - begin > 100*1024*1024) {
      return std::make_pair(begin, true);
   }
   // try and find stop character
   for(auto i = begin; i < end; i++) {
      auto c = i.rdbuf()->sgetc();
      if(c == STOP_CHARACTER) {
         return std::make_pair(i, true);
      } 
   }

   return std::make_pair(begin, false);
}

(使用多字符分隔符进行此操作留给读者练习)

答案 1 :(得分:6)

只需使用停在EOF或缓冲区已满的transfer_exactly

auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);

<强> Live On Coliru

#include <boost/asio.hpp>
#include <iostream>
using namespace boost::asio;
using namespace ip;

int main() {
    boost::system::error_code ec;

    io_service svc;
    tcp::socket s(svc);
    s.connect(tcp::endpoint(address_v4::loopback(), 6767));

    streambuf sb;
    auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);

    std::cerr << "read " << transferred << " till " << ec.message() << "\n";
}

答案 2 :(得分:0)

我使用 streambuf 限制设置相同的限制。示例代码(使用协同程序):

dbCommand.CommandText = "ALTER TABLE USERS MODIFY (USER_ID NUMBER(18,0))";

多数民众赞成。您可以检查读取回调中的错误代码,并在读取缓冲区中找不到搜索元素时获取特定错误。