長串連和心跳包

來源:互聯網
上載者:User

標籤:blog   http   使用   檔案   資料   os   

第一種設定:通過設定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")));
}

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")));
}

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7

TCP協議中有長串連和短串連之分。短串連在資料包發送完成後就會自己斷開,長串連在發包完畢後,會在一定的時間內保持串連,即我們通常所說的Keepalive(存活定時器)功能。
預設的Keepalive逾時需要7,200,000 milliseconds,即2小時,探測次數為5次。它的功效和使用者自己實現的心跳機制是一樣的。開啟Keepalive功能需要消耗額外的寬頻和流量,儘管這微不足道,但在按流量計費的環境下增加了費用,另一方面,Keepalive設定不合理時可能會因為短暫的網路波動而斷開健康的TCP串連。

keepalive並不是TCP規範的一部分。在Host Requirements RFC羅列有不使用它的三個理由:(1)在短暫的故障期間,它們可能引起一個良好串連(good connection)被釋放(dropped),(2)它們消費了不必要的寬頻,(3)在以資料包計費的互連網上它們(額外)花費金錢。然而,在許多的實現中提供了存活定時器。

一些伺服器應用程式可能代表用戶端佔用資源,它們需要知道用戶端主機是否崩潰。存活定時器可以為這些應用程式提供探測服務。Telnet伺服器和Rlogin伺服器的許多版本都預設提供存活選項。

個人電腦使用者使用TCP/IP協議通過Telnet登入一台主機,這是能夠說明需要使用存活定時器的一個常用例子。如果某個使用者在使用結束時只是關掉了電源,而沒有登出(log off),那麼他就留下了一個半開啟(half-open)的串連。如果用戶端消失,留給了伺服器端半開啟的串連,並且伺服器又在等待用戶端的資料,那麼等待將永遠持續下去。存活特徵的目的就是在伺服器端檢測這種半開啟串連。

也可以在用戶端設定存活器選項,且沒有不允許這樣做的理由,但通常設定在伺服器。如果串連兩端都需要探測對方是否消失,那麼就可以在兩端同時設定(比如NFS)。



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
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,從而得知串連已失效,用戶端程式便有機會及時執行清除工作、提醒使用者或重新串連。

TCP串連非正常斷開的檢測(KeepAlive探測)

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

有兩種方法可以檢測:1.TCP串連雙方定時發握手訊息 2.利用TCP協議棧中的KeepAlive探測

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


在windows下使用,要包含MSTcpIP.h的標頭檔。點擊下面的連結即可下載這個檔案
  MSTcpIP 

備忘:長串連雖好,但是比較好用但是佔用系統資源比較大。個人建議如無特殊需要,用自己的心跳包機制最好。

 

轉自:

長串連和心跳包

聯繫我們

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

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

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.