转自http://www.dotblogs.com.tw/lbwshift2/archive/2012/10/07/76320.aspx
TCP/IP協定下,當clinet 要中斷跟server的連線時,會有四個handshake步驟,跑完這四個步驟後socket 會通知你的server程式這個client已斷線:
![image image](http://files.dotblogs.com.tw/lbwshift2/1210/a5cab465a7b4_CE69/image46_thumb.png)
但…如果client沒做handshake卻斷線了 (ex:拔網路線),這時你的程式就不會即刻收到client斷線的通知 (要等非常之久才會收到, 預設是2小時)
所以,有人會自製類似 "ping" 的命令, 由你的server程式定時輪詢每個client是否還在連線。
其實到不用那麼麻煩, windows socket 有偵測的的參數可以做設定,就是利用 Socket.IOControl 來設定Socket的低階作業模式,現在,我們使用IOControlCode.KeepAliveValues參數值來設定:
1 | var listenSocket = new Socket(listenerEndPoint.AddressFamily |
5 | listenSocket.Bind(listenerEndPoint); |
6 | listenSocket.Listen(100); |
7 | listenSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1, 5000, 5000), null ); |
GetKeepAliveSetting Method:
02 | /// 建立 keepalive 作業所需的輸入資料 |
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) |
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); |
Socket.IOControl 的用法在.net 上的MSDN寫的不清不楚,有寫跟沒寫一樣,GetKeepAliveSetting 之所以要傳回12個byte及它格式說明如下圖:
![image image](http://files.dotblogs.com.tw/lbwshift2/1210/a5cab465a7b4_CE69/image26_thumb.png)
加上這一行的設定後
1 | listenSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1, 5000, 5000), null ); |
每5秒 socket server 就會送一個[Keep-Alive]的訊息,client如果還在連線就會回覆[Keep-Alive-ACK]:![image image](http://files.dotblogs.com.tw/lbwshift2/1210/a5cab465a7b4_CE69/image39_thumb.png)
再來,讓我拔掉client的網路線,不用多久你的server程式就會收到client已斷線的通知了: