0

asioの使用に問題があります。私のクライアント/サーバー アプリケーションは、同期通信のみを必要とします。そこで、Boost のホームページのシンクロの例を使用して、データを送受信するための 2 つの手順をセットアップしました。コードは次のとおりです。

void vReceive(tcp::socket & socket, std::string & szDest){
    char szTmp_Buf [BUF_LEN + 1];
    szDest = "";
    std::cout << "Entering vReceive . . ." << std::endl;

    for (;;){
      char szBuf [BUF_LEN];
      boost::system::error_code error;
      uInt uiBytes_Recv = socket.read_some(boost::asio::buffer(szBuf), error);
      std::cout << " Read " << uiBytes_Recv << " bytes" << std::endl;
      if (error == boost::asio::error::eof)
         break; // Connection closed cleanly by peer.
      else if (error)
         throw boost::system::system_error(error); // Some other error.

      memcpy((void*) szTmp_Buf, (void*) szBuf, uiBytes_Recv );
      szTmp_Buf[ uiBytes_Recv ] = '\0';
      szDest += szTmp_Buf;
      };
      std::cout << "Received" << szDest << std::endl;
      std::cout << "Leaving vReceive . . ." << std::endl << std::endl;
   };

void vSend(tcp::socket & socket, std::string & szSrc){
    std::cout << "Entering vSend . . . " << std::endl;
    std::cout << "Sending " << szSrc << std::endl;
    boost::system::error_code ignored_error;
    boost::asio::write(socket, boost::asio::buffer(szSrc), boost::asio::transfer_all(), ignored_error);
    std::cout << "Leaving vSend . . . " << std::endl << std::endl;
    };

これらの手順は、boost の例から抽出されたコード行の単なるラッパーです。

私のテスト アプリケーションでは、クライアントが呼び出します

std::string szDate;
vReceive(socket, szDate);
vSend(socket, std::string("Chop Suey!") );
vReceive(socket, szDate);
vSend(socket, std::string("Halo"));

そしてサーバー呼び出し

std::string message = make_daytime_string();
std::string szReceived;
vSend(socket, message);
vReceive(socket, szReceived);
vSend(socket, message);
vReceive(socket, szReceived);

機能をテストするだけです。問題は、次の図に示すように、最初の情報交換後に両方のアプリケーションがフリーズすることです。サーバー側でvSend()が終了している間、クライアント側でvReceive()プロシージャが終了していないようです。それで、誰かが何か考えがありますか、何が間違っているのでしょうか?

誰かが問題を再現したい場合に備えて、ソースの完全なソースを同じサーバーにアップロードしました。このサーバーでは、写真が asio_problem.rar ファイルに含まれています (新しいメンバーとして、投稿ごとに 1 つのハイパーリンクを設定できます)。

よろしくお願いします、ダニエル。

4

1 に答える 1

1

あなたの問題はここにあると思います:

for (;;){
  /* snipped */

  if (error == boost::asio::error::eof)
     break; // Connection closed cleanly by peer.
  else if (error)
     throw boost::system::system_error(error); // Some other error.

  /* snipped */
}

接続が閉じるまで無限にループしています (ループから抜け出す唯一の方法は、ソケットから EOF エラーを受け取った場合です)vSendが、ソケットを閉じることはありません。これはvReceive、クライアントが永遠に待機し、常により多くのデータを期待していることを意味します。を入れるとsocket.close()うまくvSendいくはずです。

もちろん、これはクライアントとサーバーが と をそれぞれ呼び出すたびにソケットを再度開く必要があることを意味しvReceiveますvSend。それが望ましくない場合は、送信者が受信者にこれ以上データが送信されないことを通知する他の手段を使用することをお勧めします。

ネットワーク経由で送信されるデータに制約があるかどうかはわかりませんが、メッセージの先頭に「データ長」値を送信するか、最後に何らかの「データの終わり」のセンチネル値を送信しますより多くのデータのリッスンをいつ停止するかを示す、適切で明確な指標を提供します。

このアプローチには、ASIO read_until(または同様の) 機能を使用して、データの終わりを待つロジックを処理する理由を与えるという追加の利点があります。

于 2009-11-16T22:31:20.957 に答える