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



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

为了避免这种情况,我想将限制设置为 read_until .就像"读取直到"<EOF>"或直到达到 10MB"。

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

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

<小时 />

你可以用一个最大大小参数来构造你的 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);
}

(使用多字符分隔符完成这项工作留给读者练习)

只需使用transfer_exactly,它也会在EOF或缓冲区满时停止:

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

住在科里鲁

#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";
}

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

try {
     boost::asio::streambuf req_buf(100 * 1024); //Limit memory for headers
     boost::asio::async_read_until(*sock, req_buf, "rnrn", yield);
}catch(boost::system::system_error &e) {
    if( e.code() == boost::asio::error::make_error_code(boost::asio::error::misc_errors::not_found) )
        log("HTTP Connection close: cannot find headers end");
     //..
}

就是这样。您可以在读取回调中检查错误代码,并在读取缓冲区中找不到搜索元素时出现特定错误。

最新更新