linux下socket keep alive講解

來源:互聯網
上載者:User

【需求】
不影響伺服器處理的前提下,檢測用戶端程式是否被強制終了。
【現狀】
伺服器端和用戶端的Socket都設定了keepalive屬性。
伺服器端設定了探測次數等參數,用戶端、伺服器只是開啟了keepalive機能
伺服器端起了一個監視線程,利用select來檢測socket是否被關閉。。。

下面這是我的一點膚淺理解。

1.關於keep alive

無論windows,還是linux,keepalive就三個參數:

sk->keepalive_probes:探測次數
sk->keepalive_time   探測的逾時
sk->keepalive_intvl 探測間隔

對 於一個已經建立的tcp串連。如果在keepalive_time時間內雙方沒有任何的資料包傳輸,則開啟keepalive功能的一端將發送 eepalive資料包,若沒有收到應答,則每隔keepalive_intvl時間再發送該資料包,發送keepalive_probes次。一直沒有 收到應答,則發送rst包關閉串連。若收到應答,則將計時器清零。例如★:

sk->keepalive_probes = 3;
sk->keepalive_time   = 30;
sk->keepalive_intvl = 1;

意 思就是說對於tcp串連,如果一直在socket上有資料來往就不會觸發keepalive,但是如果30秒一直沒有資料往來,則keep alive開始工作:發送探測包,受到響應則認為網路,是好的,結束探測;如果沒有相應就每隔1秒發探測包,一共發送3次,3次後仍沒有相應,
就 關閉串連,也就是從網路開始斷到你的socket能夠意識到網路異常,最多花33秒。但是如果沒有設定keep alive,可能你在你的socket(阻塞性)的上面,接收: recv會一直阻塞不能返回,除非對端主動關閉串連,因為recv不知道socket斷了。發送:取決於資料量的大小,只要底層協議站的buffer能放 下你的發送資料,應用程式層級的send就會一直成功返回。 直到buffer滿,甚至buffer滿了還要阻塞一段時間試圖等待buffer空閑。所以你對send的傳回值的檢查根本檢測不到失敗。開啟了keep
alive功能,你直接通過發送接收的函數傳回值就可以知道網路是否異常。設定的方法(應用程式層):

int keepalive = 1; // 開啟keepalive屬性
int keepidle = 60; // 如該串連在60秒內沒有任何資料往來,則進行探測
int keepinterval = 5; // 探測時發包的時間間隔為5 秒
int keepcount = 3; // 探測嘗試的次數.如果第1次探測包就收到響應了,則後2次的不再發.
setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive ));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount ));

2.select和keep alive的關係

select 是為單個線程使用多個socket而設計的,跟檢測串連無關,如果只是檢測一個socket的話,沒有必要使用select。開了keepalive機能 的話,每次調用recv或send時檢查傳回值,判斷是否出錯或為0.如果出錯,再檢查errno查資料,看哪個或哪幾個錯誤號碼表示連結斷了或不存在就可 以了。

另外,誰想定期檢查串連狀況,誰就啟用keep alive。另一端可以不起,只是被動地對探測包進行響應,這種響應是tcp協議的基本要求,跟keep alive無關。並不需要用戶端和伺服器端都開啟keep alive。

3.測試結果

按照例★的值在一端的socket上開啟keep alive,然後阻塞在一個recv或者不停的send,這個時候拔了網線,測試從拔掉網線到recv/send返回失敗的時間。

在linux kernel裡頭的測試發現,對於阻塞型的socket,當recv的時候,如果沒有設定keep alive,即使網線拔掉或者ifdown,recv很長時間不會返回,最長達17分鐘,雖然這個時間比linux的預設逾時時間()短了很多。但是如果 設定了keep alive,基本都在keepalive_time +keepalive_probes*keepalive_intvl =33秒內返回錯誤。

但是對於迴圈不停send的socket,當拔掉網線後,會持續一段時間send返 回成功(0~10秒左右,取決 於發送資料的量),然後send阻塞,因為協議層的buffer滿了,在等待buffer空閑,大概90秒左右後才會返回錯誤。由此看來,send的時 候,keep alive似乎沒有起到作用,這個原因至今也不清楚。後來通過給send之前設定timer來解決的。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.