tcp串連探測Keepalive和心跳包

來源:互聯網
上載者:User

採用TCP串連的C/S模式軟體,串連的雙方在串連空閑狀態時,如果任意一方意外崩潰、當機、網線斷開或路由器故障,另一方無法得知TCP串連已經失效,除非繼續在此串連上發送資料導致錯誤返回。很多時候,這不是我們需要的。我們希望伺服器端和用戶端都能及時有效地檢測到串連失效,然後優雅地完成一些清理工作並把錯誤報表給使用者。

如何及時有效地檢測到一方的非正常斷開,一直有兩種技術可以運用。一種是由TCP協議層實現的Keepalive,另一種是由應用程式層自己實現的心跳包。

TCP預設並不開啟Keepalive功能,因為開啟Keepalive功能需要消耗額外的寬頻和流量,儘管這微不足道,但在按流量計費的環境下增加了費用,另一方面,Keepalive設定不合理時可能會因為短暫的網路波動而斷開健康的TCP串連。並且,預設的Keepalive逾時需要7,200,000 milliseconds,即2小時,探測次數為5次。

對於Win2K/XP/2003,可以從下面的登錄機碼找到影響整個系統所有串連的keepalive參數:

[HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters]

"KeepAliveTime”=dword:006ddd00

"KeepAliveInterval"=dword:000003e8

"MaxDataRetries"="5"

對於實用的程式來說,2小時的空閑時間太長。因此,我們需要手工開啟Keepalive功能並設定合理的Keepalive參數。

// 開啟KeepAlive

BOOL bKeepAlive = TRUE;

int nRet = ::setsockopt(socket_handle, SOL_SOCKET, SO_KEEPALIVE, (char*)&bKeepAlive, sizeof(bKeepAlive));

if (nRet == SOCKET_ERROR)

{

return FALSE;

}

// 設定KeepAlive參數

tcp_keepalive alive_in = {0};

tcp_keepalive alive_out = {0};

alive_in.keepalivetime = 5000; // 開始首次KeepAlive探測前的TCP空閉時間

alive_in.keepaliveinterval = 1000; // 兩次KeepAlive探測間的時間間隔

alive_in.onoff = TRUE;

unsigned long ulBytesReturn = 0;

nRet = WSAIoctl(socket_handle, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),

&alive_out, sizeof(alive_out), &ulBytesReturn, NULL, NULL);

if (nRet == SOCKET_ERROR)

{

return FALSE;

}

開啟Keepalive選項之後,對於使用IOCP模型的伺服器端程式來說,一旦檢測到串連斷開,GetQueuedCompletionStatus函數將立即返回FALSE,使得伺服器端能及時清除該串連、釋放該串連相關的資源。對於使用select模型的用戶端來說,串連斷開被探測到時,以recv目的阻塞在socket上的select方法將立即返回SOCKET_ERROR,從而得知串連已失效,用戶端程式便有機會及時執行清除工作、提醒使用者或重新串連。更多精彩內容:http://www.bianceng.cn/Programming/cplus/

另一種技術,由應用程式自己發送心跳包來檢測串連的健康性。用戶端可以在一個Timer中或低層級的線程中定時向發伺服器發送一個短小精悍的包,並等待伺服器的回應。用戶端程式在一定時間內沒有收到伺服器回應即認為串連不可用,同樣,伺服器在一定時間內沒有收到用戶端的心跳包則認為用戶端已經掉線。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 windows下此處的”非正常斷開”指TCP串連不是以優雅的方式斷開,如網線故障等物理鏈路的原因,還有突然主機斷電等原因.

有兩種方法可以檢測:

1.TCP串連雙方定時發握手訊息

2.利用TCP協議棧中的KeepAlive探測

第二種方法簡單可靠,只需對TCP串連兩個Socket設定KeepAlive探測,

所以本文只講第二種方法在Linux,Window2000下的實現(在其它的平台上沒有作進一步的測試)

Windows 2000平台下 標頭檔

#include <mstcpip.h>

//定義結構及宏

/*

struct TCP_KEEPALIVE {

u_longonoff;

u_longkeepalivetime;

u_longkeepaliveinterval;

} ;

*/

tcp_keepalive live,liveout;

live.keepaliveinterval=5000; //每5秒發一次探測報文,發5次沒有回應,就斷開

live.keepalivetime=30000;//超過30s沒有資料,就發送控測包

live.onoff=TRUE;

int Opt = 1;

int iRet = setsockopt(Accept,SOL_SOCKET,SO_KEEPALIVE,(char *)&Opt,sizeof(int));

if(iRet == 0){

DWORD dw;

if(::WSAIoctl(Accept,SIO_KEEPALIVE_VALS,

&live,sizeof(live),&liveout,sizeof(liveout),

&dw,NULL,NULL)== SOCKET_ERROR){

}

}

ACE下代碼

//by rainfish blog.csdn.net/bat603

int Opt = 1;

//在測試過程中,發現檢測的次數是5次,即下面的設定中,從最近一次訊息開始計算的10秒後,每次間隔5秒,連續發送5次,即35秒發現網路斷了

tcp_keepalive live,liveout;

live.keepaliveinterval=5000; //每次檢測的間隔 (單位毫秒)

live.keepalivetime=10000; //第一次開始發送的時間(單位毫秒)

live.onoff=TRUE;

int iRet = stream.set_option(SOL_SOCKET,SO_KEEPALIVE,&Opt,sizeof(int));

if(iRet == 0){

DWORD dw;

//此處顯示了在ACE下擷取通訊端的方法,即控制代碼的(SOCKET)化就是控制代碼

if(WSAIoctl((SOCKET)h,SIO_KEEPALIVE_VALS,&live,sizeof(live),

&liveout,sizeof(liveout),&dw,NULL,NULL)== SOCKET_ERROR){

//Delete Client

return;

}

}

Linux平台下

#include "/usr/include/linux/tcp.h"#include "/usr/include/linux/socket.h"////KeepAlive實現,單位秒//下面代碼要求有ACE,如果沒有包含ACE,則請把用到的ACE函數改成linux相應的介面int keepAlive = 1;//設定KeepAliveint keepIdle = 5;//開始首次KeepAlive探測前的TCP空閉時間int keepInterval = 5;//兩次KeepAlive探測間的時間間隔int keepCount = 3;//判定斷開前的KeepAlive探測次數if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt SO_KEEPALIVE error!/n")));}    if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPIDLE error!/n")));}    if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPINTVL error!/n")));}    if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t)setsockopt TCP_KEEPCNT error!/n")));}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。