1

すべての接続をシャットダウンするオプションが必要な Java サーバーがあります。この一環として、各クライアント ソケットで close() を呼び出しています。私が抱えている問題は、この呼び出しが無期限にブロックされることがあるということです。

これは、数百人のユーザーをシミュレートすることによってのみ再現できるため、特定するのは困難ですが、書き込み時にそのソケットがブロックされている場合に発生すると思われます。

ソケットで shutdownOutput() を呼び出すと役立つという別の質問を読みましたが、SSLSocket (私が使用している) ではサポートされていません。

別の方法はありますか?書き込みのためにキューに入れられたデータが送信されるかどうかは重要ではありません。接続を強制終了する必要があるだけです。

4

1 に答える 1

4

私自身のアプリケーションを徹底的にテストした後、私はこれにいくらかの光を当てることができるかもしれません。私が観察した現象は次のとおりです。

開いてAで処理されたJava を、並行するBから閉じると、呼び出しがAの次の呼び出しまでブロックされることがあり、その後、再実行されて。を示します。BのinとAのanyの非同期呼び出しの間で、Aはそのソケットで正常に操作を実行できます。SSLSocketThread Thread close()read()Thread EOFclose()Thread read()Thread write()

これは、 Aによって開始された呼び出しが終了する前にThread Bが実行する場合にのみ当てはまることがわかりました。その後、非同期で閉じても問題ないようです。close()startHandshake()Thread SSLSocket

これは、問題をどのように解決するかという問題を私たちに残します。明らかに、状態ベースの動作が少し役立つでしょう。

Bで非同期の遅延が発生する可能性がある場合、close()ASSLセッションの準備ができるまでBを待機させるため、 beforeの呼び出しは非常にうまく機能しているようです。ただし、これによりソケットごとに遅延が発生する可能性があります。また、 Aがソケットの使用を開始する前にBでが実行されない場合は、追加の作業が発生する可能性があります。Thread getSession()close()close()Thread

より良い、しかしそれほど単純ではない解決策は、2つの単方向フラグを使用することです。1つ(handshakeDone)は、SSLハンドシェイクが完了したことを示すためにAによって使用されます( Bがこれを見つけるための非ブロッキングAPIの方法はありません)。もう1つの(toBeClosed)は、ソケットが閉じていることを示すためにBによって使用されます。

toBeClosedハンドシェイクが実行された後にチェックします。Bは、falseの場合に呼び出すclose()か、そうでない場合に設定します。handshakeDonetoBeClosed

これを成功させるには、ABの両方にアトミックブロックが必要であることに注意してください。特定の実装(上記のアルゴリズムと比較して最適化されている可能性があります)はあなたに任せます。

close()ただし、SSLソケットでの非同期呼び出しが誤動作する状況が他にもある可能性があります。

于 2013-01-17T10:12:11.137 に答える