如果客戶端異常掉線或拔掉網線,那么在服務端會留下一個TCP連接,這個連接會變成死連接(經過測試,如果windows的TCP保持連接禁用的話,三個小時該死連接還不消失)。
如果大量客戶端並發,出現的死TCP連接過多,服務器內存和端口將會增加,直到占滿服務器的端口和耗盡內存為止。如果這樣的話,服務器無法健壯穩定的運行。
大家可以另開線程來監控客戶端連接,但是今天要給大家講解的不是這個方法,而是使用TCP協議自帶的心跳包功能解決這個問題。
大家先了解一下 TCP keep-alive原理
一個TCP keep-alive 包是一個簡單的ACK,該ACK包內容為一個比當前連接sequence number 小於一的包。
主機接受到這些ACKs會返回一個包含當前sequence number 的ACK包。
Keep-alives一般被用來驗證遠端連接是否有效。如果該連接上沒有其他數據被傳輸,或者更高level 的 keep-alives被傳送,keep-alives 在每隔KeepAliveTime被發送。(默認是 7,200,000 milliseconds ,也就是2個小時)。
如果沒有收到 keep-alive 應答,keep-alive 將在每 KeepAliveInterval 秒重發一次。KeepAliveInterval 默認為1秒。如 Microsoft 網絡功能中很多部分中采用的 NETBT 連接,更常見的是發送 NETBios keep-alives,所以,在 NetBios 連接中通常不發送TCP keep-alives。
TCP保持連接默認被禁用,但是微軟Sockets應用程序可以使用SetSockOpt函數去啟用他們。
請看下面的類
type
TCP_KeepAlive = record
OnOff: Cardinal;
KeepAliveTime: Cardinal; // 多長時間(ms)沒有數據就開始send心跳包
KeepAliveInterval: Cardinal // 每隔多長時間(ms)send一個心跳包,發5次(系統值)
end;
KeepAliveTime: TCP連接多長時間(毫秒)沒有數據就開始發送心跳包,有數據傳遞的時候不發送心跳包
KeepAliveInterval: 失敗重試時,每隔多長時間(毫秒)發送一個心跳包,重試5次(系統默認值)
如果客戶端網絡中斷,服務器系統發送心跳包后,服務器會自動解除TCP連接。這一點,大家可以使用 netstat -p -tcp 命令查看。