淺談TCP keepalive

    在上一篇文章中曾經提到過,當server端收到來自client的FIN後卻一直不關閉鏈接,TCP鏈接將進入CLOSE_WAIT狀態,並一直維持該狀態,實際上這時client端早已退出,這無疑是一種資源的浪費。在實際的生產環境中,因爲掉電、系統崩潰、網絡異常等緣由,這種狀況是頗有可能發生的,因而咱們須要一種方法來進行鏈接的探測和保活,及時判斷出異常狀況的發生,釋放鏈接資源。html

    TCP的keepalive機制就是爲這項任務而生的,詳細的描述見http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/網絡

    默認狀況下,TCP的keepalive功能是關閉的,因此在前面的例子中server端的CLOSE_WAIT鏈接會一直保持,能夠經過下面的方式打開該功能:code

int keepalive = 1;/*on*/
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));

系統默認的keepalive參數能夠經過/proc或sysctl獲取:server

若是但願將keepalive機制引入程序中,並修改相關參數,能夠經過兩種方法:htm

  • 經過/proc或sysctl修改全局配置,也就是上圖中的內容;資源

  • 經過套接字選項修改特定於套接字的配置;get

因爲咱們不想改動全局配置,所以選擇第二種方法,修改套接字選項:class

int keepalive_idle = 120;
setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &keepalive_idle, sizeof(keepalive_idle));

int keepalive_intvl = 30;
setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &keepalive_intvl, sizeof(keepalive_intvl));

int keepalive_cnt = 5;
setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &keepalive_cnt, sizeof(keepalive_cnt));

注意:這裏咱們但願在server端增長保活探測機制,因此上述代碼都是在server端的修改。
cli

從新運行修改後的程序,並在server端使用netstat觀察:配置


能夠看到,keepalive的timer開始運行起來了,一段時間後CLOSE_WAIT的鏈接將被釋放:

下面經過實際的抓包看看到底發生了什麼?

能夠看到,在數據流量結束120s(TCP_KEEPIDLE)後,服務端發送了一個keepalive報文,該報文是一個長度爲0的"duplicate-ack",且序列號比上一個ACK少1。

此時,因爲client早已退出,所以協議棧會回覆一個RST,server端也就此當即退出了,後續的探測也就不會再進行了。

相關文章
相關標籤/搜索