1. ホーム
  2. c++

[解決済み] boost::asio::buffer。バッファサイズを取得し、バッファオーバーフローを防ぐ?

2022-02-16 11:50:25

質問内容

パケットを送受信するための以下の2つの関数があります。

void send(std::string protocol)
{
    char *request=new char[protocol.size()+1];
    request[protocol.size()] = 0;
    memcpy(request,protocol.c_str(),protocol.size());

    request_length = std::strlen(request);
    boost::asio::write(s, boost::asio::buffer(request, request_length));
}
void receive()
{
    char reply[max_length];
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length));
    std::cout << "Reply is: ";
    std::cout.write(reply, reply_length);
    std::cout << "\n";
}

質問はこの部分に関するものです boost::asio::buffer(reply, request_length) ここで、リクエストの長さはパケット送信時に初期設定された文字列の長さです。を知らずにバッファのサイズを確認するにはどうしたらいいでしょうか? request_length ? また、バッファオーバーフローを防ぐにはどうしたらよいでしょうか?

解決方法は?

バッファのサイズを取得するために boost::asio::buffer_size() 関数が使用できます。 しかし、あなたの例では、これはほとんど役に立たないでしょう。

バッファーで説明したように 概要 Boost.Asioはバッファを表現するためにバッファクラスを使用します。 これらのクラスは抽象化を提供し、バッファオーバーランからBoost.Asioの操作を保護します。 の結果は boost::asio::buffer() は操作に渡されますが、バッファのサイズやその基礎となる型などのメタデータは送信されません。 また、これらのバッファはメモリを所有しないので、バッファ抽象化の有効期間中、基礎となるメモリが有効であることを保証するのは、アプリケーションの責任です。

その boost::asio::buffer() 関数はバッファクラスを作成する便利な方法を提供し、バッファのサイズは可能な型から推論されます。 Boost.Asioがバッファの長さを推測できる場合、Boost.Asioの操作は結果のバッファタイプを使用してもバッファのオーバーフローを呼び出すことはありません。 しかし、アプリケーション・コードでバッファの大きさを boost::asio::buffer() その場合、そのサイズが基礎となるメモリより大きくないことを確認するのは、アプリケーションの責任です。

データを読み込む際には、バッファが必要です。 Boost.Asioがサイズを送信しない場合、どれくらいのメモリを確保すればよいのか、どうやって知ることができるのか、という根本的な疑問があります。 この問題に対しては、いくつかの解決策があります。

  • ソケットに、どれだけのデータが利用可能かを問い合わせるには socket::available() で、それに応じてバッファを確保します。

    std::vector<char> data(socket_.available());
    boost::asio::read(socket_, boost::asio::buffer(data));
    
    
  • Boost.Asioがメモリ内で成長できるクラス、例えば以下のようなものを使用します。 boost::asio::streambuf . などの一部の操作は boost::asio::read() 受け入れる streambuf オブジェクトをバッファとして使用し、操作に必要な分だけメモリを確保します。 しかし、完了条件を与えなければならない。さもなければ、操作はバッファが一杯になるまで続けられる。

    boost::asio::streambuf data;
    boost::asio::read(socket_, data,
                      boost::asio::transfer_at_least(socket_.available()));
    
    
  • として Öö Tiib は、通信プロトコルの一部として長さを組み込むことを提案しています。 Boost.Asioを確認する は、通信プロトコルの例です。 必ずしもBoost.Asioにこだわらず、プロトコルに着目してください。 API .

    • 固定サイズプロトコルでは、データ生産者と消費者の両方が同じサイズのメッセージを使用します。 読み手はメッセージのサイズを知っているので、あらかじめバッファを確保することができる。
    • 可変長プロトコルでは、メッセージはヘッダとボディの2つの部分に分けられることが多い。 ヘッダは通常固定サイズで、ボディの長さなど様々なメタ情報を含むことができる。 これにより、リーダーはヘッダを固定サイズのバッファに読み込んで、ボディの長さを抽出し、ボディ用のバッファを割り当て、それからボディを読み込むことができる。

      // Read fixed header.
      std::vector<char> data(fixed_header_size);
      boost::asio::read(socket_, boost::asio::buffer(data));
      
      protocol::header header(data);
      network_to_local(header); // Handle endianess.
      
      // Read body.
      data.resize(header.body_length());
      boost::asio::read(socket_, boost::asio::buffer(data));  
      
      protocol::body body(data);
      network_to_local(body); // Handle endianess.