侦测socket clinet是否已经断线(TCP协定)

转自http://www.dotblogs.com.tw/lbwshift2/archive/2012/10/07/76320.aspx

 

TCP/IP協定下,當clinet 要中斷跟server的連線時,會有四個handshake步驟,跑完這四個步驟後socket  會通知你的server程式這個client已斷線

侦测socket clinet是否已经断线(TCP协定)_第1张图片

 

但…如果client沒做handshake卻斷線了 (ex:拔網路線),這時你的程式就不會即刻收到client斷線的通知  (要等非常之久才會收到, 預設是2小時)

所以,有人會自製類似 "ping" 的命令, 由你的server程式定時輪詢每個client是否還在連線。

其實到不用那麼麻煩, windows socket 有偵測的的參數可以做設定,就是利用 Socket.IOControl 來設定Socket的低階作業模式,現在,我們使用IOControlCode.KeepAliveValues參數值來設定:

1 var listenSocket = new Socket(listenerEndPoint.AddressFamily
2                 , SocketType.Stream
3                 , ProtocolType.Tcp);
4  
5 listenSocket.Bind(listenerEndPoint);
6 listenSocket.Listen(100);
7 listenSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1, 5000, 5000), null);

GetKeepAliveSetting Method:

01 /// <summary>
02 /// 建立 keepalive 作業所需的輸入資料
03 /// </summary>
04 /// <param name="onOff">是否啟用1:on ,0:off</param>
05 /// <param name="keepAliveTime">當沒收到client的ack時,等待多久才通知斷線(millisecond)</param>
06 /// <param name="keepAliveInterval">偵測間隔(millisecond)</param>
07 /// <returns></returns>
08 private byte[] GetKeepAliveSetting(int onOff, int keepAliveTime, int keepAliveInterval)
09 {
10     byte[] buffer = new byte[12];
11     BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
12     BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
13     BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
14     return buffer;
15 }

 

Socket.IOControl 的用法在.net 上的MSDN寫的不清不楚,有寫跟沒寫一樣,GetKeepAliveSetting 之所以要傳回12個byte及它格式說明如下圖

侦测socket clinet是否已经断线(TCP协定)_第2张图片

 

加上這一行的設定後

1 listenSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1, 5000, 5000), null);

每5秒 socket server 就會送一個[Keep-Alive]的訊息,client如果還在連線就會回覆[Keep-Alive-ACK]:侦测socket clinet是否已经断线(TCP协定)_第3张图片

 

再來,讓我拔掉client的網路線,不用多久你的server程式就會收到client已斷線的通知了: 侦测socket clinet是否已经断线(TCP协定)_第4张图片

 

 

你可能感兴趣的:(socket)