最近在做的項目是用C#作服務端,客戶端每隔10秒發起一次連接,出現的問題是:由於同學在做的客戶端側有一些bug暫未解決,經常會出現客戶端崩掉,但服務端卻沒有監測到socket異常斷開。
查了資料后發現有兩種方式可以解決:
1、用心跳包方式(服務端每隔幾秒向客戶端發起請求,如果沒有收到客戶端回應,則判定為客戶端下線)
2、用socket的KeepAlive機制(個人感覺和心跳包有點類似)
我先用了心跳包的方式測試,發現雖然確實可以將對應的socket關閉,但是延遲很大(在建立socket連接后,把客戶端斷網5s-20s,服務器才會斷開其socket連接),所以選擇使用KeepAlive機制。
Socket server; //server綁定端口及監聽就不貼出來了 Socket client = server.Accept(); client.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 3000, 500), null);//設置Keep-Alive參數 private byte[] KeepAlive(int onOff, int keepAliveTime, int keepAliveInterval) { uint dummy = 0; byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3]; BitConverter.GetBytes((uint)onOff).CopyTo(inOptionValues, 0); BitConverter.GetBytes((uint)keepAliveTime).CopyTo(inOptionValues, Marshal.SizeOf(dummy));//keep-alive間隔(單位ms) BitConverter.GetBytes((uint)keepAliveInterval).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);// 嘗試間隔(單位ms) return inOptionValues; }
設置完以后,還需要在Receive的異步回調函數的catch里執行客戶端socket的close方法(try里執行EndReceive或者下一次的BeginReceive)。
不過使用TcpClient的話好像無需在Receive的異步回調函數里手動執行close(暫未測試,下次測試后補上)。