2017-01-17 14 views
3

"<EOF>"を受け取るまで、ソケットからの読み取りにはboost::asio::read_untilを使用しています。しかし、システムがRAMを使い切ってシャットダウンするまで、何十億ものバイトを送信する可能性があります。Asioのread_untilにバイト制限を設定できますか?

これを回避するには、制限をread_untilに設定します。 「"<EOF>"まで、または10MBに達するまで読む」のように。

read_untilを使用すると簡単に解決策がありますか、またはを受け取ったときにreadに切り替えてマニュアルを終了する必要がありますか?

答えて

5

@seheには、EOFを停止したり、特定のバイト数を読み込んだりすることができます。私のバージョンは少し複雑ですが、さらに区切り文字を使用することもできます。


あなたの後押しをconstructでき:: 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

これは素晴らしいですが、実際は複雑すぎる、IYAM(私の答えを見てください) – sehe

+0

@あなたが正しいです、少し編集しました。私は "\ r \ n"を確認するためにそれを使用したので、OPは実際の文字 '<'、 'E'、 'O'、 'F'、 '>'を意味し、それを心に念頭に置いて答えを書きました – user45891

+0

実際これは、質問を読むための有効な方法です。その場合、これは最善の答えです。+1 – sehe

5

ただtransfer_exactlyを使用してくださいまた EOFの停止またはバッファフル:

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

Imが制限たstreambufを使用して、同じ制限を設定します。コード例(コルーチンを使用):

try { 
    boost::asio::streambuf req_buf(100 * 1024); //Limit memory for headers 
    boost::asio::async_read_until(*sock, req_buf, "\r\n\r\n", 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"); 
    //.. 
} 

それはそれです。読み込みコールバックでエラーコードをチェックし、検索バッファに読み込み要素が見つからなかった場合に特定のエラーが発生することがあります。

関連する問題