link1: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/html
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就能夠了。如下的文字只是我我的的讀書筆記。app
首先,須要搞清楚TCP keepalive是幹什麼用的。從名字理解就可以知道,keepalive就是用來檢測一個tcp connection是否還鏈接正常。當一個tcp connection創建好以後,若是雙方都不發送數據的話,tcp協議自己是不會發送其它的任何數據的,也就是說,在一個idle的connection上,兩個socket之間不產生任何的數據交換。從另外一個方面講,當一個connection創建以後,連接雙方能夠長時間的不發送任何數據,好比幾天,幾星期甚至幾個月,但該connection仍然存在。less
因此,這就可能出現一個問題。舉例來講,server和client創建了一個connection,server負責接收client的request。當connection創建好以後,client因爲某種緣由機器停機了。但server端並不知道,因此server就會一直監聽着這個connection,但其實這個connection已經失效了。socket
keepalive就是爲這樣的場景準備的。當把一個socket設置成了keepalive,那麼這個socket空閒一段時間後,它就會向對方發送數據來確認對方仍然存在。放在上面的例子中,若是client停機了,那麼server所發送的keepalive數據就不會有response,這樣server就可以確認client完蛋了(至少從表面上看是這樣)。tcp
再繼續介紹keepalive以前,還有幾點須要說明:ide
首先,keepalive並非惟一的手段。想知道某connection是否失效,除了keepalive還有其它的一些辦法,好比heartbeat,或者本身發送檢測信息等等。函數
其次,keepalive並非TCP協議的一部分。之因此如此,也是由於:一,不是全部的場景下都須要使用keepalive;二,keepalive有它本身的缺陷,如link2中所列,「在Host Requirements RFC羅列有不使用它的三個理由:(1)在短暫的故障期間,它們可能引發一個良好鏈接(good connection)被釋放(dropped),(2)它們消費了沒必要要的寬帶,(3)在以數據包計費的互聯網上它們(額外)花費金錢。」ui
再次,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