2009-07-28 11 views
4

プロジェクト用のコアNIOサーバーのネットワークコードを書き直しています。将来の使用のために接続情報をいつ保存するべきかを把握しようとしています。たとえば、クライアントが通常の方法で接続すると、そのクライアントにSocketChannelオブジェクトを格納して関連付けて、いつでもそのクライアントにデータを書き込むことができます。一般的には、クライアントのIPアドレス(ポートを含む)をSocketChannelオブジェクトにマップするHashMapのキーとして使用します。そうすれば、私は自分のIPアドレスを簡単に検索し、そのSocketChannel経由で非同期にデータを送信することができます。Java NIO:OP_ACCEPTとOP_READの関係?

これは最善の方法ではないかもしれませんが、プロジェクトは大きすぎて基本的なネットワークコードを変更することはできませんが、私は提案を検討します。しかし、私の主な質問は次のとおりです。

将来の使用のためにSocketChannelをどのような場所に保存する必要がありますか?私は、接続が受け入れられると(OP_ACCEPTを介して)SocketChannelへの参照を格納しています。 OP_READイベントが発生したときにマップエントリがすでに存在していると仮定できるため、これは効率的なアプローチです。そうでなければ、OP_READが発生するたびに計算上高価なHashMapのチェックを行う必要があります。 OP_ACCEPTより多くのものがクライアントのために発生します。私の恐れは、受け入れられる(OP_ACCEPT)いくつかの接続がありますが、決してデータを送信しない(OP_READ)ことがあります。おそらく、これはファイアウォールの問題やクライアントまたはネットワークアダプタの機能不全のために可能です。これはアクティブではないが、クローズメッセージを受け取ることのない「ゾンビ」接続につながる可能性があると私は思う。

私のネットワークコードを書き直す私の理由の一部は、まれには、私は奇妙な状態になっているクライアント接続を取得することです。私はOP_ACCEPT対OP_READを処理した方法を考えています。接続を「有効」と仮定して格納することができ、間違っている可能性があるという情報も含まれます。

私の質問はより具体的ではありません。SocketChannelが本当に有効かどうかを判断する最も効率的な方法を探しています。助けてくれてありがとう!

答えて

4

セレクタとノンブロッキングIOを使用している場合は、NIO自身がチャネルとそのステートフルデータとの関連付けを追跡できるようにすることを検討してください。 SelectionKey.register()を呼び出すと、3つの引数を持つフォームを使用して、「添付ファイル」を渡すことができます。将来、SelectionKeyはいつもあなたが提供した添付ファイルオブジェクトを返します。 (これは、OSレベルのAPIの "void * user_data"型の引数に非常によく似ています)。

その添付は状態データを保持するのに便利な場所です。いいところは、チャンネルから鍵へのマッピングからNIOへのすべてのマッピングがすでに処理されているため、簿記が少なくて済みます。 Map lookupsのような簿記は、IOレスポンダループの内部で実際に害を及ぼすことがあります。

追加機能として、後で添付ファイルを変更することもできます。そのため、プロトコルのフェーズごとに異なる状態オブジェクトが必要な場合は、SelectionKeyでもその状態を追跡できます。

奇妙な状態については、あなたの接続があることがわかります。あなたを噛んでいる可能性のあるNIOとセレクタの使用にはいくつかの微妙な点があります。たとえば、SelectionKeyが読み込み準備ができたことを通知すると、他のスレッドが次回select()を呼び出すときに読み込みの準備ができます。したがって、ソケットを読み取ろうとする複数のスレッドで終わるのは簡単です。一方、読んでいる間に読み込みのためにキーの登録を解除しようとすると、SelectionKeysとその関心事はしか実際にselect( )。したがって、全体として、このAPIには鋭いエッジがあり、すべての状態を正しく処理するのは難しいことです。

ああ、もう1つの可能性は、あなたが明示的に尋ねるまで、ソケットを最初に閉じた人によっては閉じたソケットに気付くことがあります。私は頭の上から正確な情報を思い出すことはできませんが、クライアントの半分がソケットの終わりを閉じます。は選択キーの準備ができていることを通知します。読まれる。これにより、クライアントのTIME_WAITステータスに一連のソケットが残ることがあります。

最後に、async IOを実行している場合は、「パターン指向ソフトウェアアーキテクチャ」(POSA)シリーズで2つの書籍をお勧めします。第2巻では、多くのIOパターンを扱っています。 (例えば、NIOはVolume 2のReactorパターンに非常によく似ています。これは、上記で言及した状態処理の問題を扱っています。)第4巻では、それらのパターンを含んでおり、それらを一般的な分散システムのより大きなコンテキストに埋め込みます。これらの本はどちらも非常に貴重な資料です。

+0

うわ、大量のためのおかげで(及び品質)の助け!私は今できる限りこの資料を研究しています。 - SelectionKey.register()ではなく、SocketChannel.register()を意味すると思いますか? - NIO用のスレッドを1つだけ使用することで、スレッドの問題のいくつかを回避できますか? - TIME_WAITステータスのソケットを定期的にチェックして、終了する必要がある候補は妥当と思われますか? (あなたが言及した半閉じた問題) ありがとうトン! – DivideByHero

+0

1)はい、register()はSelectableChannel(SocketChannelが拡張)にあります。それが私の意図だった。 2)選択にスレッドを1つだけ使用してから、チャネルを読み取り/書き込みアクションのためにオフにできます。同時接続数が多い場合は、1つのスレッドだけで処理できないことがわかります。それは難しいハンドオフです。 3)定期的にハーフクローズドソケットを探しています。 – mtnygard