转自http://www.dotblogs.com.tw/lbwshift2/archive/2012/10/07/76320.aspx
TCP/IP協定下,當clinet 要中斷跟server的連線時,會有四個handshake步驟,跑完這四個步驟後socket 會通知你的server程式這個client已斷線:
但…如果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及它格式說明如下圖:
加上這一行的設定後
1 |
listenSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1, 5000, 5000), null ); |
每5秒 socket server 就會送一個[Keep-Alive]的訊息,client如果還在連線就會回覆[Keep-Alive-ACK]:
再來,讓我拔掉client的網路線,不用多久你的server程式就會收到client已斷線的通知了: