第一種設置:經過設置socket的keepalive屬性
#include "/usr/include/linux/tcp.h"
#include "/usr/include/linux/socket.h"
////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")));
}linux
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")));
}windows
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")));
}網絡
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7socket
TCP協議中有長鏈接和短鏈接之分。短鏈接在數據包發送完成後就會本身斷開,長鏈接在發包完畢後,會在必定的時間內保持鏈接,即咱們一般所說的Keepalive(存活定時器)功能。
默認的Keepalive超時須要7,200,000 milliseconds,即2小時,探測次數爲5次。它的功效和用戶本身實現的心跳機制是同樣的。開啓Keepalive功能須要消耗額外的寬帶和流量,儘管這微不足道,但在按流量計費的環境下增長了費用,另外一方面,Keepalive設置不合理時可能會由於短暫的網絡波動而斷開健康的TCP鏈接。
tcp
keepalive並非TCP規範的一部分。在Host Requirements RFC羅列有不使用它的三個理由:(1)在短暫的故障期間,它們可能引發一個良好鏈接(good connection)被釋放(dropped),(2)它們消費了沒必要要的寬帶,(3)在以數據包計費的互聯網上它們(額外)花費金錢。然而,在許多的實現中提供了存活定時器。函數
一些服務器應用程序可能表明客戶端佔用資源,它們須要知道客戶端主機是否崩潰。存活定時器能夠爲這些應用程序提供探測服務。Telnet服務器和Rlogin服務器的許多版本都默認提供存活選項。ui
我的計算機用戶使用TCP/IP協議經過Telnet登陸一臺主機,這是可以說明須要使用存活定時器的一個經常使用例子。若是某個用戶在使用結束時只是關掉了電源,而沒有註銷(log off),那麼他就留下了一個半打開(half-open)的鏈接。若是客戶端消失,留給了服務器端半打開的鏈接,而且服務器又在等待客戶端的數據,那麼等待將永遠持續下去。存活特徵的目的就是在服務器端檢測這種半打開鏈接。.net
也能夠在客戶端設置存活器選項,且沒有不容許這樣作的理由,但一般設置在服務器。若是鏈接兩端都須要探測對方是否消失,那麼就能夠在兩端同時設置(好比NFS)。blog
keepalive工做原理:
若在一個給定鏈接上,兩小時以內無任何活動,服務器便向客戶端發送一個探測段。(咱們將在下面的例子中看到探測段的樣子。)客戶端主機必須是下列四種狀態之一:
1) 客戶端主機依舊活躍(up)運行,而且從服務器可到達。從客戶端TCP的正常響應,服務器知道對方仍然活躍。服務器的TCP爲接下來的兩小時復位存活定時器,若是在這兩個小時到期以前,鏈接上發生應用程序的通訊,則定時器從新爲往下的兩小時復位,而且接着交換數據。
2) 客戶端已經崩潰,或者已經關閉(down),或者正在重啓過程當中。在這兩種狀況下,它的TCP都不會響應。服務器沒有收到對其發出探測的響應,而且在75秒以後超時。服務器將總共發送10個這樣的探測,每一個探測75秒。若是沒有收到一個響應,它就認爲客戶端主機已經關閉並終止鏈接。
3) 客戶端曾經崩潰,但已經重啓。這種狀況下,服務器將會收到對其存活探測的響應,但該響應是一個復位,從而引發服務器對鏈接的終止。
4) 客戶端主機活躍運行,但從服務器不可到達。這與狀態2相似,由於TCP沒法區別它們兩個。它所能代表的僅是未收到對其探測的回覆。
服務器沒必要擔憂客戶端主機被關閉而後重啓的狀況(這裏指的是操做員執行的正常關閉,而不是主機的崩潰)。當系統被操做員關閉時,全部的應用程序進程(也就是客戶端進程)都將被終止,客戶端TCP會在鏈接上發送一個FIN。收到這個FIN後,服務器TCP向服務器進程報告一個文件結束,以容許服務器檢測這種狀態。
在第一種狀態下,服務器應用程序不知道存活探測是否發生。凡事都是由TCP層處理的,存活探測對應用程序透明,直到後面2,3,4三種狀態發生。在這三種狀態下,經過服務器的TCP,返回給服務器應用程序錯誤信息。(一般服務器向網絡發出一個讀請求,等待客戶端的數據。若是存活特徵返回一個錯誤信息,則將該信息做爲讀操做的返回值返回給服務器。)在狀態2,錯誤信息相似於「鏈接超時」。狀態3則爲「鏈接被對方復位」。第四種狀態看起來像鏈接超時,或者根據是否收到與該鏈接相關的ICMP錯誤信息,而可能返回其它的錯誤信息。
linux內核包含對keepalive的支持。其中使用了三個參數:tcp_keepalive_time(開啓keepalive的閒置時 長)tcp_keepalive_intvl(keepalive探測包的發送間隔)和tcp_keepalive_probes (若是對方不予應答,探測包的發送次數);在liunx中,keepalive是一個開關選項,能夠經過函數來使能。具體地說,可使用如下代碼:
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
當tcp檢測到對端socket再也不可用時(不能發出探測包,或探測包沒有收到ACK的響應包),select會返回socket可讀,而且在recv時返回-1,同時置上errno爲ETIMEDOUT。此時TCP的狀態是斷開的。
keepalive參數設置代碼以下:
開啓Keepalive選項以後,對於使用IOCP模型的服務器端程序來講,一旦檢測到鏈接斷開,GetQueuedCompletionStatus函數將當即返回FALSE,使得服務器端能及時清除該鏈接、釋放該鏈接相關的資源。對於使用select模型的客戶端來講,鏈接斷開被探測到時,以recv目的阻塞在socket上的select方法將當即返回SOCKET_ERROR,從而得知鏈接已失效,客戶端程序便有機會及時執行清除工做、提醒用戶或從新鏈接。
TCP鏈接非正常斷開的檢測(KeepAlive探測)
此處的」非正常斷開」指TCP鏈接不是以優雅的方式斷開,如網線故障等物理鏈路的緣由,還有忽然主機斷電等緣由
有兩種方法能夠檢測:1.TCP鏈接雙方定時發握手消息 2.利用TCP協議棧中的KeepAlive探測
第二種方法簡單可靠,只需對TCP鏈接兩個Socket設定KeepAlive探測。
在windows下使用,要包含MSTcpIP.h的頭文件。點擊下面的連接便可下載這個文件
MSTcpIP
備註:長鏈接雖好,可是比較好用可是佔用系統資源比較大。我的建議如無特殊須要,用本身的心跳包機制最好。
轉自: