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

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

 

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

法一:服務器

當recv()返回值小於等於0時,socket鏈接斷開。可是還須要判斷 errno是否等於 EINTR,若是errno == EINTR 則說明recv函數是因爲程序接收到信號後返回的,socket鏈接仍是正常的,不該close掉socket鏈接。socket

 

法二:tcp

  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 斷開函數

 

法三:post

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

 

法四:url

int keepAlive = 1; // 開啓keepalive屬性
int keepIdle = 60; // 如該鏈接在60秒內沒有任何數據往來,則進行探測
int keepInterval = 5; // 探測時發包的時間間隔爲5 秒
int keepCount = 3; // 探測嘗試的次數.若是第1次探測包就收到響應了,則後2次的再也不發.spa

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

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

 

法五:

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

 

參考:

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

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

3. 如何判斷SOCKET已經斷開

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

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

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

相關文章
相關標籤/搜索