怎樣實時判斷socket連接狀態?


  • 對端正常close socket,或者進程退出(正常退出或崩潰),對端系統正常關閉
這種情況下,協議棧會走正常的關閉狀態轉移,使用epoll的話,一般要判斷如下幾個情況
    • 處理可讀事件時,在循環read后,返回結果為0
    • 處理可寫事件時,write返回-1,errno為EPIPE
    • EPOLLERR或EPOLLHUP或事件
  • 對端非正常斷開,比如服務器斷電,網線被拔掉
這種情況下,協議棧無法感知,SO_KEEPALIVE這個選項的超時事件太長並不實用,一般還是以應用層的heartbeat來及時發現。

 

下面來羅列一下判斷遠端已經斷開的方法:

法一:

當recv()返回值小於等於0時,socket連接斷開。但是還需要判斷 errno是否等於 EINTR,如果errno == EINTR 則說明recv函數是由於程序接收到信號后返回的,socket連接還是正常的,不應close掉socket連接。

 

法二:

  struct tcp_info info; 
  int len=sizeof(info); 
  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
  if((info.tcpi_state==TCP_ESTABLISHED))  則說明未斷開  else 斷開

 

法三:

若使用了select等系統函數,若遠端斷開,則select返回1,recv返回0則斷開。其他注意事項同法一。

 

法四:

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));

設置后,若斷開,則在使用該socket讀寫時立即失敗,並返回ETIMEDOUT錯誤

 

法五:

自己實現一個心跳檢測,一定時間內未收到自定義的心跳包則標記為已斷開。

 

參考:

1. 知乎:怎樣實時判斷socket鏈接狀態?

2. 知乎:socket長連接是否會超時?連接中斷,客戶端或者服務器端是否一定能得到通知呢?

3. 如何判斷SOCKET已經斷開

4. TCP socket如何判斷連接斷開

5. 服務器中判斷客戶端socket斷開連接的方法

6. tcp 服務端如何判斷客戶端斷開連接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM