tcp keepalive
部分信息可以看UNIX網絡編程第157頁,
摘錄過來:
在一個正常的TCP連接上,當我們用無限等待的方式調用下面的Recv或Send的時候:
?? ret=recv(s,&buf[idx],nLeft,flags);
? ?或
?? ret=send(s,&buf[idx],nLeft,flags);
?? 如果TCP連接被對方正常關閉,也就是說,對方是正確地調用了closesocket(s)或者shutdown(s)的話,那么上面的Recv或Send調用就能馬上返回,并且報錯。這是由于closesocket(s)或者shutdown(s)有個正常的關閉過程,會告訴對方“TCP連接已經關閉,你不需要再發送或者接受消息了”。但是,如果是網線突然被拔掉,TCP連接的任何一端的機器突然斷電或重啟動,那么這時候正在執行Recv或Send操作的一方就會因為沒有任何連接中斷的通知而一直等待下去,也就是會被長時間卡住。這種情形解決的辦法:
1>自己編寫心跳包程序
簡單的說也就是在自己的程序中加入一條線程,定時向對端發送數據包,查看是否有ACK,如果有則連接正常,沒有的話則連接斷開
2>啟動TCP編程里的keepAlive機制
?
其實keepalive的原理就是TCP內嵌的一個心跳包,
以服務器端為例,如果當前server端檢測到超過一定時間(默認是?7,200,000 milliseconds,也就是2個小時)沒有數據傳輸,那么會向client端發送一個keep-alive packet(該keep-alive packet就是ACK和當前TCP序列號減一的組合),此時client端應該為以下三種情況之一:
?
1. client端仍然存在,網絡連接狀況良好。此時client端會返回一個ACK。server端接收到ACK后重置計時器,在2小時后再發送探測。如果2小時內連接上有數據傳輸,那么在該時間基礎上向后推延2個小時。
2.?客戶端異常關閉,或是網絡斷開。在這兩種情況下,client端都不會響應。服務器沒有收到對其發出探測的響應,并且在一定時間(系統默認為1000 ms)后重復發送keep-alive packet,并且重復發送一定次數(2000 XP 2003?系統默認為5次, Vista后的系統默認為10次)。
3.?客戶端曾經崩潰,但已經重啟。這種情況下,服務器將會收到對其存活探測的響應,但該響應是一個復位,從而引起服務器對連接的終止。
?
? 對于實用程序來說,2小時的空閑時間太長。因此,我們需要手工開啟Keepalive功能并設置合理的Keepalive參數。在XP和WIN2003系統上,可以針對單獨的socket來設置,但是在windows?2000,不能單獨設置,如果設置,那么影響是整個系統的所有socket。
?
了解了keep alive大致的原理,下來看看在程序中怎么用,怎么設置參數:
[cpp]?view plaincopy
其中,setsockopt設置了keepalive模式,但是系統對keepalive默認的參數可能不符合我們的要求,比如空閑2小時后才探測對端是否活躍,所以WSAIoctl函數通過tcp_keepalive結構體對這些參數進行了相應設置
tcp_keepalive這個結構體在mstcpip.h頭文件中有定義:
[cpp]?view plaincopy
這個結構體設置了空閑檢測時間,及檢測時重復發送的間隔時間
按照msdn上的說法,這些參數也可以通過在注冊表里設置,分別為:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveTime
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\KeepAliveInterval
?
另外,有些人可能已經發現了,tcp_keepalive這個結構體中沒有對重試次數這個參數的設置,這個參數可以通過注冊表來設置,具體位置為:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpMaxDataRetransmissions
此處的keepalivetime表示的是TCP連接處于暢通時候的探測頻率,一旦探測包沒有返回,就以keepaliveinterval的頻率發送,經過若干次的重試,如果探測包都沒有返回,那么就得出結論:TCP連接已經斷開,于是上面的Recv或Send調用也就能馬上返回,不會無限制地卡住了。
? 上圖是對上面文字的說明。亮條之前,TCP處于暢通狀態,KeepAlive是以1000毫秒(keepalivetime的值)的頻率發送探測包,在發送到第32個探測包的時候,探測包沒有返回,于是就以5000毫秒(keepalivetime的值)的頻率發送探測包,重發幾次后,探測包都沒有返回,于是就得出結論:此TCP連接已經斷開了!
?
設置好keepalive以后,我們通過實驗來看看當client異常退出或是網絡斷掉的情況下,keepalive怎么通知我們異常斷開的情況。這里采用select模式,實驗環境為XP系統和Win7系統,幾種情況返回值如下:
?
1.?正常斷開
select函數正常返回,recv函數返回0
?
2.?異常斷開
a)?????? 程序異常退出,如client端重啟,應用非正常關閉等
select函數正常返回,recv函數返回SOCKET_ERROR,WSAGetLastError()得到的結果為WSAECONNRESET(10054)。
b)????? 網絡斷開
結果同上:select函數正常返回,recv函數返回SOCKET_ERROR,WSAGetLastError()得到的結果為WSAECONNRESET(10054)。
對于程序異常退出的情況,實際上在不開啟keepalive的情況下也是可以檢測到的
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的tcp keepalive的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL Server 2008 允许远程
- 下一篇: C#复习⑧