Boost.Asio c++ネットワークプログラミング翻訳(27)


streambufクラス
streambufはstd::streambufから継承されていると前に言いました.std::streambuf自体のように、構造をコピーすることはできません.
さらに、次のような追加の方法があります.
streambuf([max_size,][allocator]):この方法はstreambufオブジェクトを構築します.最大のbufferサイズと必要に応じてメモリを割り当て/解放するためのディスペンサを指定できます.
prepare(n):この方法は、連続するn文字を収容するためのサブbufferを返します.読み取りまたは書き込みに使用できます.メソッドが返す結果は任意のBoost.Asioがread/writeを処理する自由関数では、streambufオブジェクトを処理する方法だけではありません.
data():この方法はbuffer全体を連続した文字列形式で返し、書き込みに使用します.メソッドが返す結果は任意のBoost.Asioはstreambufオブジェクトを処理する方法だけでなく、書き込みを処理する自由関数で使用されます.
comsume(n):この方法では、入力キューからデータが除去される(read操作から)
commit(n):この方法では、出力キューからデータが除去され(write操作から)、入力キューに追加される(read操作の準備).
size():このメソッドはstreambufオブジェクト全体のサイズをバイト単位で返します.
max_size():このメソッドは、保存できる最大バイト数を返します.
最後の2つの方法を除いて、他の方法はそんなに簡単には理解できません.まず、streambufを次のコードクリップで示すように、read/write自由関数にパラメータで渡す時間がほとんどです.
  • read_until(sock, buf, "
    "); // buf write(sock, buf); // buf

  • 前のコードクリップが示すようにbuffer全体を自由関数に伝えたい場合は、bufferの入出力ポインタが指す位置を増加させることを保証します.つまり、データを読む必要がある場合は、それを読むことができます.例:
  • read_until(sock, buf, '
    '); std::cout << &buf << std::endl;

  • 上記のコードはsocketから書いたばかりのものを出力します.次のコードは何も出力されません.
    read(sock, buf.prepare(16), transfer_exactly(16) );
       std::cout << &buf << std::endl;
    

    バイトは読み込まれましたが、入力ポインタは移動していません.次のコードクリップに示すように、自分で移動する必要があります.
    read(sock, buf.prepare(16), transfer_exactly(16) );
       buf.commit(16);
       std::cout << &buf << std::endl;
    

    同様に、streambufオブジェクトから書き込む必要があるとします.write自由関数を使用する場合は、次のようにする必要があります.
    streambuf buf;
       std::ostream out(&buf);
       out << "hi there" << std::endl;
       write(sock, buf);
    

    次のコードはhi thereを3回送信します.
    streambuf buf;
       std::ostream out(&buf);
       out << "hi there" << std::endl;
       for ( int i = 0; i < 3; ++i)
    
           write(sock, buf.data());
    

    発生した原因はbufferが消費されたことがないためで、データがまだあるためです.消費したい場合は、次のコードクリップを使用します.
    streambuf buf;
       std::ostream out(&buf);
       out << "hi there" << std::endl;
       write(sock, buf.data());
       buf.consume(9);
    

    総じてstreambufインスタンス全体を処理することを選択したほうがいいです.調整が必要な場合は、上記の方法を使用します.
    読み取りと書き込み操作で同じstreambufを使用することができますが、2つを別々に使用することをお勧めします.1つは別の書き込みを読むことをお勧めします.それは簡単で、はっきりしています.同時に、多くのバグを避けることができます.
    streambufオブジェクトのフリー関数の処理
    次のリストはBoost.を示しています.Asioのフリー関数はstreambufオブジェクトを処理することもできます.
  • read(sock,buf[,completion_function]):この方法では、socketからstreambufオブジェクトにコンテンツを読み込みます.completionメソッドはオプションです.ある場合、read操作が成功するたびに呼び出され、Boost.に通知されます.Asioこの操作が完了したかどうか(ない場合は読み取りを続行します).フォーマットはsize_t completion(const boost::system::error_code&err,size_t bytes_transfered);completionメソッドが0を返す場合、read操作は完了したと考えられます.0でない場合、streamを次回呼び出すread_を表します.someメソッドで読み出す最大バイト数
  • read_at(random_stream,offset,buf[,completion_function]):この方法はランダム読み出しをサポートするstreamから読み出す.SOcketには適用されていないことに注意してください(ランダムに読み込まれたモデルがないため、一方向で、まっすぐ前に進んでいます).
  • read_until(sock,buf,char|string|regex|match_condition):この方法は1つの特性を満たす条件まで読まれます.charタイプのデータが読み込まれたり、文字列が読み込まれたり、現在読み込まれている文字列が一致する正規表現やmatch_conditionメソッドは、このメソッドを終了する必要があることを示します.match_conditionメソッドのフォーマットは、pairmatch(iterator begin,iterator end);iteratorはbuffersを表します.iterator.一致する場合は、pair(passed_end_of_matchがtrueに設定されている)を返す必要があります.一致しない場合は、pair(beginがfalseに設定されている)を返す必要があります.
  • write(sock,buf[,completion_function]):このメソッドはstreambufオブジェクトのすべての内容を書き込む.completionメソッドはオプションであり、read()のcompletionメソッドと同様に、write操作が完了すると0を返すか、次のstreamを呼び出すwrite_を表す0以外の数を返すsomeメソッドに書き込む最大バイト数.
  • write_at(random_stream,offset,buf[,completion_function]):この方法は、ランダムストレージをサポートするstreamに書き込むために使用されます.同様にsocketには適用されません.
  • async_read(sock,buf[,compection_function],handler):この方法はread()の非同期実装であり、handlerのフォーマットはvoid handler(const boost::system::error_code,size_t bytes)である.
  • async_read_at(radom_stream,offset,buf[,completion_function],handler):この方法はread_at()の非同期実装.
  •  async_read_until(sock,buf,char|string|regex|match_condition,handler):この方法はread_until()の非同期実装.
  • async_write(sock,buf[,completion_function],handler):この方法はwrite()の非同期実装である.
  • async_write_at(random_stream,offset,buf[,completion_function],handler):この方法はwrite_at()の非同期実装.

  • アクセントアルファベットをずっと読む必要があるとします.
  • streambuf buf;
       bool is_vowel(char c) {
    
           return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
       }
    
       size_t read_complete(boost::system::error_code, size_t bytes) {
           const char * begin = buffer_cast<const char*>( buf.data());
           if ( bytes == 0) return 1;
           while ( bytes > 0)
    
               if ( is_vowel(*begin++)) return 0;
    
               else --bytes;
           return 1;
    
       }
       ...
       read(sock, buf, read_complete);
    

  • ここで注意しなければならないことはread_にアクセスすることです.complete()のbuffer、すなわちbuffer_cast<>とbuf.data.
    正則を使用したい場合は、上記の例のほうが簡単です.
    read_until(sock, buf, boost::regex("^[aeiou]+") ); 
    例を修正してmatch_conditionメソッドが動作します.
       streambuf buf;
       bool is_vowel(char c) {
    
           return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
       }
    
       typedef buffers_iterator<streambuf::const_buffers_type> iterator;
       std::pair<iterator,bool> match_vowel(iterator b, iterator e) {
    
           while ( b != e)
               if ( is_vowel(*b++)) return std::make_pair(b, true);
    
           return std::make_pair(e, false);
       }
    
       ...
       size_t bytes = read_until(sock, buf, match_vowel);
    

    read_を使用するとuntil、ここに難点があります.下位レベルのbufferがread()を使用する場合とは異なるバイト数を多く読み取る可能性があるため、読み取り済みのバイト数を覚えておく必要があります.例:
    std::cout << &buf << std::endl;
    

    上記のコード出力のバイトはread_よりもuntilは読み取りが多い.