TCP之keepalive機制的應用場景

若是TCP鏈接被對方正常關閉,也就是說,對方是正確地調用了close或者shutdown的話,那麼Recv或Send調用就能立刻返回,而且報錯。這是因爲close或者shutdown有個正常的關閉過程,會告訴對方「TCP鏈接已經關閉,你不須要再發送或者接受消息了」。編程

可是,若是鏈接被意外斷開,客戶端並無正常關閉socket。雙方並未按照協議上的四次揮手去斷開鏈接。那麼這時候正在執行Recv或Send操做的一方就會由於沒有任何鏈接中斷的通知而一直等待下去,也就是會被長時間卡住。像這種若是一方已經關閉或異常終止鏈接,而另外一方殊不知道,咱們將這樣的TCP鏈接稱爲半打開的。服務器

 

解決意外中斷辦法都是利用保活機制。而保活機制分又可讓底層實現也可本身實現。網絡

一種是應用層的心跳機制;socket

還有一種就是啓用TCP的keepAlive機制;tcp

 

以服務器端爲例,若是當前server端檢測到超過必定時間沒有數據傳輸,那麼會向client端發送一個keep-alive packet(該keep-alive packet就是ACK和當前TCP序列號減一的組合),此時client端應該爲如下三種狀況之一:server

1. client端仍然存在,網絡鏈接情況良好。此時client端會返回一個ACK。server端接收到ACK後重置計時器(復位存活定時器),在必定時間後再發送探測。若是鏈接上一直有數據傳輸,那麼在該時間基礎上向後推延一段時間。基礎

2. 客戶端異常關閉,或是網絡斷開。在這兩種狀況下,client端都不會響應。服務器沒有收到對其發出探測的響應,而且在必定時間(系統默認爲1000 ms)後重復發送keep-alive packet,而且重複發送必定次數。cli

3. 客戶端曾經崩潰,但已經重啓。這種狀況下,服務器將會收到對其存活探測的響應,但該響應是一個復位(RST),從而引發服務器對鏈接的終止。服務器端

 

在應用層socket編程的表現爲:當tcp檢測到對端socket再也不可用時(不能發出探測包,或探測包沒有收到ACK的響應包),select/epoll會返回socket可讀,而且在recv時返回-1,同時置上errno爲ETIMEDOUT。select

 

範例:

  1.  int keepAlive = 1; // 開啓keepalive屬性  
  2.  int keepIdle = 60; // 如該鏈接在60秒內沒有任何數據往來,則進行探測   
  3.  int keepInterval = 5; // 探測時發包的時間間隔爲5 秒  
  4.  int keepCount = 3; // 探測嘗試的次數.若是第1次探測包就收到響應了,則後2次的再也不發.  
  5.   
  6.  setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));  
  7.  setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));  
  8.  setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));  
  9.  setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));   
相關文章
相關標籤/搜索