1. 程式人生 > >網絡編程之 keepalive(zz)

網絡編程之 keepalive(zz)

可能 send 狀態 重新 為知筆記 get www ive 透明

link1: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

link2: http://dev.csdn.net/article/84901.shtm

link3: http://lo-res.org/~aaron/tcpipillustrated/richard_stevens_-TCPIP-Illustrated-Vol.1/tcp_keep.htm

link1是keepalive的使用手冊。link3是richard stevens大作TCPIP illustrated的其中一個章節,專講keepalive,側重原理和概念。link2是link3的中文翻譯版。想了解keepalive,直接看這幾個link就可以了。以下的文字只是我個人的讀書筆記。

首先,需要搞清楚TCP keepalive是幹什麽用的。從名字理解就能夠知道,keepalive就是用來檢測一個tcp connection是否還連接正常。當一個tcp connection建立好之後,如果雙方都不發送數據的話,tcp協議本身是不會發送其它的任何數據的,也就是說,在一個idle的connection上,兩個socket之間不產生任何的數據交換。從另一個方面講,當一個connection建立之後,鏈接雙方可以長時間的不發送任何數據,比如幾天,幾星期甚至幾個月,但該connection仍然存在。

所以,這就可能出現一個問題。舉例來說,server和client建立了一個connection,server負責接收client的request。當connection建立好之後,client由於某種原因機器停機了。但server端並不知道,所以server就會一直監聽著這個connection,但其實這個connection已經失效了。

keepalive就是為這樣的場景準備的。當把一個socket設置成了keepalive,那麽這個socket空閑一段時間後,它就會向對方發送數據來確認對方仍然存在。放在上面的例子中,如果client停機了,那麽server所發送的keepalive數據就不會有response,這樣server就能夠確認client完蛋了(至少從表面上看是這樣)。

再繼續介紹keepalive之前,還有幾點需要說明:

首先,keepalive並不是唯一的手段。想知道某connection是否失效,除了keepalive還有其它的一些辦法,比如heartbeat,或者自己發送檢測信息等等。

其次,keepalive並不是TCP協議的一部分。之所以如此,也是因為:一,不是所有的場景下都需要使用keepalive;二,keepalive有它自己的缺陷,如link2中所列,“在Host Requirements RFC羅列有不使用它的三個理由:(1)在短暫的故障期間,它們可能引起一個良好連接(good connection)被釋放(dropped),(2)它們消費了不必要的寬帶,(3)在以數據包計費的互聯網上它們(額外)花費金錢。”

再次,keepalive沒有辦法區分出到底是由於對方的程序意外終止還是由於網絡故障而導致的connection的失效。所以,如前文所述,它可能因為網絡的短暫故障而導致一個good connection被釋放。

link2和link3中的23.2節描述了在不同的情形下keepalive的作用。我直接粘貼過來了:

在此描述中,我們稱使用存活選項的那一段為服務器,另一端為客戶端。也可以在客戶端設置該選項,且沒有不允許這樣做的理由,但通常設置在服務器。如果連接兩端都需要探測對方是否消失,那麽就可以在兩端同時設置(比如NFS)。

若在一個給定連接上,兩小時之內無任何活動,服務器便向客戶端發送一個探測段。(我們將在下面的例子中看到探測段的樣子。)客戶端主機必須是下列四種狀態之一:

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錯誤信息,而可能返回其它的錯誤信息。

而在link1中詳細介紹了keepalive的使用。這裏簡單歸納一下。

使用keepalive其實非常簡單,就是三個參數和一個函數。先說這個函數。默認情況下, socket是不支持keepalive的,所以需要使用setsockopt函數設置一下(話說setsockopt函數其實很好很強大,以後再仔細琢磨一下)。
/* Check the status for the keepalive option */
if(getsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) {
perror("getsockopt()");
close(s);
exit(EXIT_FAILURE);
}

像這樣就將socket設置成了keepalive。

接著說三個參數。keepalive會使用到系統定義的三個參數: tcp_keepalive_time,tcp_keepalive_intvl,tcp_keepalive_probes。

time是指當一個connection經過了多長時間沒有發送packet就開始啟動keepalive的檢測。系統默認設置為7200秒,就是說,如果某個connection已經7200秒沒有發送過數據,那麽這時候就要開始發送keepalive的探測包來進行檢測了。“the interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further “

intvl是指每兩個keepalive的探測包之間的時間間隔。系統默認為75秒。“the interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime “

probes則是指判斷一個connection失效所需要發送的探測包的數量。系統默認為9個。“the number of unacknowledged probes to send before considering the connection dead and notifying the application layer “

這三個參數既可以通過改寫系統的默認配置文件來進行設置,也可以通過setsockopt函數來進行設置。具體方法見link1。

所以要使用keepalive,首先設置好以上三個參數,然後通過setsockopt來啟動keepalive,這樣就OK了


http://blog.csdn.net/historyasamirror/article/details/5526486




來自為知筆記(Wiz)

網絡編程之 keepalive(zz)