9

パケットの送受信には、次の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ですか?もう1つの質問は、バッファオーバーフローを防ぐにはどうすればよいですか?

4

3 に答える 3

19

バッファのサイズを取得するには、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::streambufboost::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.    
      
于 2013-02-25T14:51:17.400 に答える
6

通常、通信プロトコルは、固定長のメッセージ、またはメッセージの長さを示すヘッダーを含むメッセージを使用します。

Boost.Asio のオンライン ドキュメントには多数の例とチュートリアルが含まれているため、おそらくそこから開始する必要があります。ウィキペディアは、データ転送の用語を説明するための優れた情報源ですが、boost asio のドキュメントでは説明されていません。

于 2013-02-25T05:39:13.060 に答える
1

あなたの質問は紛らわしいと思いますが、これが役立つかもしれません:

void receive() {
  enum { max_length = 1024 };
  char reply[max_length];
  size_t reply_length;
  std::cout << "Reply is: ";
  while ( (reply_length = ba::read(s, basio::buffer(reply, max_length))) > 0) {
    std::cout.write(reply, reply_length);
  }
  std::cout << "\n";
}
于 2013-02-25T05:39:03.367 に答える