日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tcp keepalive

發布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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
  • #include?<mstcpip.h>??
  • ??
  • ????????BOOL?bKeepAlive?=?TRUE;??
  • ????????int?nRet?=?setsockopt(m_socket,?SOL_SOCKET,?SO_KEEPALIVE,???
  • ????????(char*)&bKeepAlive,?sizeof(bKeepAlive));??
  • ????????if?(nRet?==?SOCKET_ERROR)??
  • ????????{??
  • ????????????TRACE(L"setsockopt?failed:?%d\n",?WSAGetLastError());??
  • ????????????return?FALSE;??
  • ????????}??
  • ??
  • ????????//?set?KeepAlive?parameter??
  • ????????tcp_keepalive?alive_in;??
  • ????????tcp_keepalive?alive_out;??
  • ????????alive_in.keepalivetime??????=?500;??//?0.5s??
  • ????????alive_in.keepaliveinterval??=?1000;?//1s??
  • ????????alive_in.onoff??????????????=?TRUE;??
  • ??
  • ????????unsigned?long?ulBytesReturn?=?0;??
  • ????????nRet?=?WSAIoctl(m_socket,?SIO_KEEPALIVE_VALS,?&alive_in,?sizeof(alive_in),??
  • ??????????????????????&alive_out,?sizeof(alive_out),?&ulBytesReturn,?NULL,?NULL);??
  • ????????if?(nRet?==?SOCKET_ERROR)??
  • ????????{??
  • ????????????TRACE(L"WSAIoctl?failed:?%d\n",?WSAGetLastError());??
  • ????????????return?FALSE;??
  • ????????}??

  • 其中,setsockopt設置了keepalive模式,但是系統對keepalive默認的參數可能不符合我們的要求,比如空閑2小時后才探測對端是否活躍,所以WSAIoctl函數通過tcp_keepalive結構體對這些參數進行了相應設置

    tcp_keepalive這個結構體在mstcpip.h頭文件中有定義:

    [cpp]?view plaincopy
  • struct?tcp_keepalive?{??
  • ????ULONG?onoff;???//是否開啟keepalive??
  • ????ULONG?keepalivetime;??//多長時間(ms)沒有數據就開始send心跳包??
  • ULONG?keepaliveinterval;?//每隔多長時間(ms)send一個心跳包,??
  • //發5次(2000?XP?2003默認),?10次(Vista后系統默認)??
  • };??

  • 這個結構體設置了空閑檢測時間,及檢測時重復發送的間隔時間

    按照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_ERRORWSAGetLastError()得到的結果為WSAECONNRESET(10054)。

    b)????? 網絡斷開

    結果同上:select函數正常返回,recv函數返回SOCKET_ERRORWSAGetLastError()得到的結果為WSAECONNRESET(10054)

    對于程序異常退出的情況,實際上在不開啟keepalive的情況下也是可以檢測到的

    新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!

    總結

    以上是生活随笔為你收集整理的tcp keepalive的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。