1

シングルスレッド アプリケーション。

毎回ではなく、1.5 時間の高負荷後にのみ発生します。

  1. tcp::socket::async_connect
  2. tcp::socket::close (deadline_timer による)
  3. async_connect_handler は成功の error_code (100 万回のうちの 1 つ) を返しますが、ソケットは (2) によって閉じられます。99.999% の確率で errno=125 (ECANCELED) が返されます。

ソケットの実装またはブーストasioが何らかの形でこれを行うことは可能ですか:

  1. async_connect
  2. 非同期の成功が io_service に投稿されました
  3. タイマーで閉じる
  4. クローズの影響を受けず、私が処理した非同期の成功

現在、受け入れの成功を無視して、変数に状態を保存することで解決しました。

Linux 2.6 (フェドーラ)。ブースト 1.46.0

PS: 当然のことですが、私の側ではバグの可能性があります...しかし、これがなければ何日もスムーズに動作します。

4

2 に答える 2

5

Igorがコメントで述べているように、完了ハンドラーはすでにキューに入れられています。

このシナリオは、操作が実行されてからハンドラーが呼び出されるまでの時間の分離の結果です。、、、およびのドキュメントはio_service::run()、操作ではなく、ハンドラーに言及するためのものです。シナリオでは、操作と操作は同じイベントループの反復で完了します。これにより、両方のハンドラーが不特定の順序で遅延呼び出し用に追加されます。io_service::run_one()io_service::poll()io_service::poll_one()socket::async_connect()deadline_timer::async_wait()io_service

シナリオを強調する次のスニペットについて考えてみます。

void handle_wait(const boost::system::error_code& error)
{
  if (error) return;
  socket_.close();
}

timer_.expires_from_now(boost::posix_time::seconds(30));
timer_.async_wait(&handle_wait);
socket_.async_connect(endpoint_, handle_connect);
boost::this_thread::sleep(boost::posix_time::seconds(60));
io_service_.run_one();

io_service_.run_one()呼び出されると、との両方socket::async_connect()deadline_timer::async_wait()操作が完了し、不特定の順序で内部からの呼び出しの準備ができている可能性がhandle_waitあります。この不特定の順序を適切に処理するには、操作のステータス()だけに依存するのではなく、内部から追加のロジックを実行して現在の状態を照会し、他のハンドラーが呼び出されたかどうかを判断する必要があります。handle_connectio_servicehandle_wait()handle_connect()error_code

他のハンドラーが呼び出したかどうかを判断する最も簡単な方法は次のとおりです。

  • で、handle_connect()でソケットがまだ開いているかどうかを確認しますis_open()。ソケットがまだ開いている場合は、handle_timer()呼び出されていません。handle_timer()実行されたことを示すクリーンな方法handle_connect()は、有効期限を更新することです。
  • handle_timer()、有効期限が経過しているかどうかを確認します。これが当てはまる場合は、handle_connect()実行されていないので、ソケットを閉じます。

結果のハンドラーは次のようになります。

void handle_wait(const boost::system::error_code& error)
{
  // On error, return early.
  if (error) return;

  // If the timer expires in the future, then connect handler must have
  // first.
  if (timer_.expires_at() > deadline_timer::traits_type::now()) return;

  // Timeout has occurred, so close the socket.
  socket_.close();
}

void handle_connect(const boost::system::error_code& error)
{
  // The async_connect() function automatically opens the socket at the start
  // of the asynchronous operation. If the socket is closed at this time then
  // the timeout handler must have run first.
  if (!socket_.is_open()) return;

  // On error, return early.
  if (error) return;

  // Otherwise, a connection has been established.  Update the timer state
  // so that the timeout handler does not close the socket.
  timer_.expires_at(boost::posix_time::pos_infin);
}

Boost.Asioは、タイムアウトを処理するためのいくつかのを提供します。

于 2013-01-29T21:19:41.783 に答える