4

プロジェクトのコア NIO サーバー ネットワーク コードを書き直しています。また、将来の使用のために接続情報をいつ「保存」する必要があるかを把握しようとしています。たとえば、クライアントが通常の方法で接続すると、その接続されたクライアントの SocketChannel オブジェクトを保存して関連付け、いつでもそのクライアントにデータを書き込めるようにします。通常、クライアントの IP アドレス (ポートを含む) を、SocketChannel オブジェクトにマップする HashMap のキーとして使用します。そうすれば、IP アドレスを簡単に検索して、その SocketChannel を介してデータを非同期に送信できます。

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

将来の使用のために、どの時点で SocketChannel を「保存」する必要がありますか? 接続が (OP_ACCEPT を介して) 受け入れられると、SocketChannel への参照を保存しています。OP_READ イベントが発生したときにマップ エントリが既に存在していると想定できるため、これは効率的なアプローチだと思います。そうしないと、OP_READ が発生するたびに計算コストの高い HashMap のチェックを行う必要があり、それは明らかです。 OP_ACCEPT よりも多くのクライアントが発生します。私の懸念は、受け入れられる (OP_ACCEPT) がデータをまったく送信しない (OP_READ) 接続が存在する可能性があることです。これは、ファイアウォールの問題、またはクライアントまたはネットワーク アダプターの誤動作が原因である可能性があります。これにより、アクティブではなく、近いメッセージを受信しない「ゾンビ」接続が発生する可能性があると思います。

ネットワーク コードを書き直す理由の 1 つは、まれにクライアント接続が異常な状態になることがあるからです。接続が「有効」であり、保存できると仮定するために使用する情報を含め、OP_ACCEPT と OP_READ を処理した方法が間違っている可能性があると考えています。

申し訳ありませんが、私の質問は具体的ではありません。SocketChannel が本当に有効であるかどうかを判断するための最良かつ最も効率的な方法を探しているだけなので、それへの参照を保存できます。助けてくれてどうもありがとう!

4

2 に答える 2

4

セレクターとノンブロッキング IO を使用している場合は、NIO 自体がチャネルとそのステートフル データの間の関連付けを追跡できるようにすることを検討してください。SelectionKey.register() を呼び出すと、3 つの引数の形式を使用して「添付ファイル」を渡すことができます。将来のすべての時点で、その SelectionKey は常に、指定した添付ファイル オブジェクトを返します。(これは、OS レベル API の「void *user_data」タイプの引数にかなり明確に触発されています。)

そのアタッチメントはキーにとどまるため、状態データを保持するのに便利な場所です。良い点は、チャネルからキー、アタッチメントへのすべてのマッピングがすでに NIO によって処理されているため、簿記の手間が減ることです。ブックキーピングは、マップ ルックアップと同様に、IO レスポンダー ループ内で実際に害を及ぼす可能性があります。

追加機能として、アタッチメントを後で変更することもできるため、プロトコルのさまざまなフェーズにさまざまな状態オブジェクトが必要な場合は、SelectionKey でも追跡できます。

接続を見つける奇妙な状態に関しては、NIO とセレクターの使用にはいくつかの微妙な点があり、それがあなたを悩ませている可能性があります。たとえば、SelectionKey が読み取りの準備ができていることを通知すると、次に他のスレッドが select() を呼び出したときに、引き続き読み取りの準備ができています。そのため、複数のスレッドがソケットを読み取ろうとするのは簡単です。一方、読み取り中にキーを読み取り用に登録解除しようとすると、スレッド バグが発生する可能性があります。SelectionKey とその対象操作は、実際に select() を呼び出すスレッドによってのみ操作できるためです。したがって、全体として、この API にはいくつかの鋭いエッジがあり、すべての状態処理を正しく行うのは困難です。

ああ、もう 1 つの可能性として、誰が最初にソケットを閉じるかによって、明示的に尋ねるまで、ソケットが閉じていることに気付く場合と気付かない場合があります。頭のてっぺんからの正確な詳細を思い出すことはできませんが、それは次のようなものです: クライアントがソケットの端を半分閉じます。 . これにより、クライアント上で多数のソケットが TIME_WAIT ステータスのままになる可能性があります。

最後の推奨事項として、非同期 IO を使用している場合は、「パターン指向ソフトウェア アーキテクチャ」(POSA) シリーズの本を何冊かお勧めします。第 2 巻では、多くの IO パターンを扱います。(たとえば、NIO は、Volume 2 の Reactor パターンに非常に適しています。これは、前述の状態処理の問題の多くに対処します。) Volume 4 には、これらのパターンが含まれており、一般的な分散システムのより大きなコンテキストに埋め込まれています。これらの本はいずれも非常に貴重な資料です。

于 2009-07-28T01:24:21.947 に答える
0

別の方法として、既存の NIO ソケット フレームワークを調べることもできます。考えられる候補は次のとおりです。

于 2009-07-28T16:58:11.510 に答える