TCP/IPサーバでクライアントと通信している時、クライアントとの接続が切れた場合の処理のまとめです。
接続が切れたとは、以下の場合です。
- クライアントが回線を切った
- クライアントが強制終了した
- ケーブルが外れるなど通信経路が切れた
クライアントが接続を切った
クライアントがshutdown
を実行して回線を切った場合、サーバーのNetworkStream.Read()は長さ0の通信を受け取って終了します。
int readsize = stream.Read( buf, 0, buf.Length );
if( readsize == 0 )
{
// クライアントが切断したときの処理
}
クライアントが強制終了した
クライアントがWSACleanup
を実行たり、ExitProcess
して回線を切った場合、サーバーのNetworkStream.Read()は例外を投げて終了します。
try
{
int readsize = stream.Read( buf, 0, buf.Length );
// クライアントからの受信処理
}
catch( Exception e )
{
// クライアントが切断したときの処理
}
ケーブルが外れるなど通信経路が切れた
通常は無反応です。
Keep-aliveの設定を行っておくと設定条件となった時、強制終了したときと同様にNetworkStream.Read()は例外を投げて終了します。
keep-aliveとは、接続している相手に定期的にプローブという通信を投げ応答があるかどうかを確認するもので、応答がなくなったら回線に異常が生じたと検出する手法です。
プローブのON/OFF、クライアントとの通信がなくなってからプローブを送信するまでの待ち時間、プローブを送信する間隔を設定します。
var clientSocket = listenerSocket.Accept();
// keep-aliveをenableに設定
clientSocket.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true );
// keep-aliveのパラメータ Cで言うところの、unsigned int が3つです。
byte[] tcp_keepalive = new byte[12];
BitConverter.GetBytes( (Int32)1 ).CopyTo( tcp_keepalive, 0 );//onoffスイッチ.
BitConverter.GetBytes( (Int32)2000 ).CopyTo( tcp_keepalive, 4 );//wait time.(ms)
BitConverter.GetBytes( (Int32)1000 ).CopyTo( tcp_keepalive, 8 );//interval.(ms)
// keep-aliveのパラメータ設定
clientSocket.IOControl( IOControlCode.KeepAliveValues, tcp_keepalive, null );
待ち時間と間隔はミリ秒で設定します。
この例では、スイッチはON、待ち時間2秒、間隔1秒、です。Windowsでは10回連続でプローブの応答がなかったら例外を発生するようです。
プローブはネットワークトラフィックを増やします。その点は注意。
参考URL
https://www.codeproject.com/Articles/117557/Set-Keep-Alive-Values