2012-05-16 12 views
6

私はboostのasioライブラリを持つサーバを書いています。サーバーは、Connectionオブジェクトのコレクション(boost :: asio :: tcp :: socketのラッパークラス)を使用して多数の同時接続を処理します。 Connectionクラス内では、socket.async_read_some(...)を使用してソケットが絶えず読み込まれており、readハンドラが新しいデータで呼び出されたときはいつでも、すぐにsocket.async_read_some()が再度呼び出され、より多くのデータが読み込まれます。boost :: asio :: tcp :: socketハンドラを呼び出さずに閉じるとキャンセルする

サーバーは何らかの理由でクライアントの接続を解除することがあるため、connect.close()を呼び出してsocket.close()を呼び出すと、保留中のすべての非同期操作がキャンセルされる。これにより、boost :: asio :: error :: operation_abortedを使って読み込みハンドラ(Connectionクラス内のメソッドにバインドされている)が呼び出されます。そして私の問題は、私はこれが起こることを望んでいません。

socket.close()の後、ソケットと接続を破棄して、アクティブなクライアントのサーバーのリストからポインタを削除したいとします。しかし、readハンドラはio_service.run()の次の繰り返しまで呼び出されません。つまり、ハンドラが呼び出されるまでsocket.async_read_some()に渡されたソケットまたはreadハンドラをすぐに破棄することはできません。エラー。だから私は何とかそれらのオブジェクトの破壊を遅らせる必要があります。うざい。

  • に呼び出されるすべてのハンドラなし保留中の非同期操作をキャンセルし、私は安全にすぐsocket.close後にソケットを破壊することができます()、または
  • のいずれかに安全な方法がありますハンドラを呼び出すことができなくなったときに安全に知ってください

これはまったく間違った方法ですか?

答えて

4

async.operationが完了すると(successfulyまたはerror-with)、その完了ハンドラが呼び出されます。これは重要な保証であり、私はこれを "ハッキング"しようとするのは良い考えではないと思います。 あなたのユースケースで遭遇した問題は、通常、shared_ptr(shared_from_this idiom)を使用することによって疲れます:ハンドラにバインドshared_ptr<Connection>、operation_aborted(またはその他のエラー)が発生したときに別のasync_readを発行しないでください。接続オブジェクトはソケットで破棄されます。

+0

これは非常に良いですね。私はshared_ptrを十分に使用せず、enable_shared_from_thisについて知りませんでした。私はこれをやりました: "socket.async_connect(エンドポイント、boost :: bind(&Connection :: done_connect、this、_1))"これでバインドコールに追加の "shared_from_this()"を追加し、実際のshared_ptrがハンドラでも使用されなくても、追加のshared_ptrのメソッドシグニチャ?私。 shared_ptrはオブジェクトがまだ存在することを保証するためのものです。そうだね? – jlh

+0

少なくとも私はこの方法で実装しましたが、今はとてもうまく動作します。どうもありがとうございました! – jlh

+0

@jlh、shared_ptrが "ハンドラで使われない"と言っても間違いありません。メンバー関数をshared_ptrにバインドすると、それはバインダー(bind()で作成されたファンクタ)に格納され、ファンクタの呼び出しで参照解除されます。結果として、ポインターは、ファンクターが生存している限り生きています。 –

関連する問題