クライアントがnettyからのソケット接続を閉じたかどうかを判断しようとしています。これを行う方法はありますか?
クライアントがclose()
を介してソケットを閉じ、TCPハンドシェイクの閉じが正常に終了した場合、channelInactive()
(またはchannelClosed()
in 3)イベントがトリガーされます。
ただし、停電やLANケーブルの接続が外れたためにクライアントマシンがオフラインになるなどの異常なケースでは、接続が実際にダウンしていることがわかるまでに長い時間がかかる場合があります。この状況を検出するには、クライアントに定期的にメッセージを送信し、一定の時間内に応答を受信することを期待する必要があります。これはpingのようなものです。プロトコルで定期的なpingおよびpongメッセージを定義する必要があります。これは、接続の状態をチェックするだけです。
または、_SO_KEEPALIVE
_を有効にすることもできますが、このオプションのキープアライブ間隔は通常OSに依存するため、使用することはお勧めしません。
ユーザーがこの種の動作を比較的簡単に実装できるように、NettyはReadTimeoutHandler
を提供しています。一定時間インバウンドトラフィックがない場合にReadTimeoutHandler
が例外を発生させるようにパイプラインを構成し、exceptionCaught()
ハンドラーメソッドで例外の接続を閉じます。定期的なpingメッセージを送信することになっているパーティの場合は、タイマー(またはIdleStateHandler
)を使用して送信します。
Nettyの上で使用するプロトコルによって異なります。 pingのようなメッセージをサポートするように設計している場合は、それらのメッセージを送信するだけです。それに加えて、nettyはTCPの非常に薄いラッパーにすぎません。
this SO post これはisOpen()
および関連について説明しています。ただし、これはキープアライブの問題を解決しません。
サーバーを作成していて、nettyがクライアントである場合、サーバーはselect()
または同等のものを呼び出して切断を検出し、ソケットが読み取り可能であるかどうかを検出してからrecv()
を呼び出すことができます。 recv()
が0を返す場合、ソケットはクライアントによって正常に閉じられました。 recv()
が-1を返す場合は、errno
または同等のもので実際のエラーを確認します(いくつかの例外を除いて、ほとんどのエラーは不正な切断として扱われる必要があります)。予期しない切断については、OSが検出するのに長い時間がかかる可能性があるため、TCP keep-alivesを有効にするか、クライアントにサーバーにデータを送信するように要求する必要があります。定期的にクライアントから何も受信されない場合は、クライアントがなくなったと想定して接続の終了を閉じます。クライアントが必要な場合は、再接続できます。
ピアによって閉じられた接続から読み取る場合、APIに応じて、ある種のストリームの終了が示されます。このような接続に書き込むと、IOException: 'connectionreset'が発生します。 TCPは、閉じた接続を検出する他の方法を提供しません。
TCPキープアライブは、(a)デフォルトでオフになっており、(b)有効になっている場合、デフォルトでは2時間ごとにのみ動作します。これはおそらくあなたが望むものではありません。これを使用して、接続が切断されたことを検出した後に読み取りまたは書き込みを行うと、上記のリセットエラーが発生します。