TCP連接非正常斷開的檢測

如果主機崩潰,write是否阻塞取決於內核的tcp緩衝區,但read將一直阻塞,直到超時ETIMEOUT,或由於某些中間路由器的原因返回EHOSTUNREACH/ENETUNREACH。select不能檢測到該情況。
如果主機崩潰並重起,客戶的write到達主機時主機響應RST,客戶的read將返ECONNRESET。


此處的”非正常斷開”指TCP連接不是以優雅的方式斷開,如網線故障等物理鏈路的原因,還有突然主機斷電等原因
有兩種方法可以檢測:1.TCP連接雙方定時發握手消息 2.利用TCP協議棧中的KeepAlive探測
第二種方法簡單可靠,只需對TCP連接兩個Socket設定KeepAlive探測,所以本文只講第二種方法在Linux,Window2000下的實現(在其它的平臺上沒有作進一步的測試)
Windows 2000平臺下

//定義結構及宏
struct TCP_KEEPALIVE {
u_longonoff;
u_longkeepalivetime;
u_longkeepaliveinterval;
} ;
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
//KeepAlive實現
TCP_KEEPALIVE inKeepAlive = {0}; //輸入參數
unsigned long ulInLen = sizeof(TCP_KEEPALIVE);
TCP_KEEPALIVE outKeepAlive = {0}; //輸出參數
unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);
unsigned long ulBytesReturn = 0;
//設置socket的keep alive爲5秒,並且發送次數爲3次
inKeepAlive.onoff = 1;
inKeepAlive.keepaliveinterval = 5000; //兩次KeepAlive探測間的時間間隔
inKeepAlive.keepalivetime = 5000; //開始首次KeepAlive探測前的TCP空閉時間
if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS,
(LPVOID)&inKeepAlive, ulInLen,
(LPVOID)&outKeepAlive, ulOutLen,
&ulBytesReturn, NULL, NULL) == SOCKET_ERROR)
{
ACE_DEBUG ((LM_INFO,
ACE_TEXT ("(%P|%t) \WSAIoctl failed. error code(%d)!\n"),WSAGetLastError()));
}


Linux平臺下

#include
……
////KeepAlive實現
//下面代碼要求有ACE,如果沒有包含ACE,則請把用到的ACE函數改成linux相應的接口
int keepAlive = 1;//設定KeepAlive
int 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")));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章