socket 斷開和重連問題

jhhost發表於2019-03-05

問題重現

這個問題在c++端比較容易重現,在web端偶現,移動端卻沒發生過。難道是移動端一直沒使用者使用,所以他們也不知道?額,不能這樣想,不然容易被打。一定是有人用的,可能移動端有啥不為人知的厲害操作?

問題分析

由於這個涉及的角色只有兩個,server端和client端,至少目前來說,已經有兩種client端都出現了問題,難道這倆端都寫的有問題麼?額,有一個是我寫的,沒弄清楚之前,不能慫。先從伺服器端查起,檢查相關配置,並沒有發現有類似保持連線時間的配置,額。。。這就尷尬了。客戶端也沒有寫超時自動斷開的邏輯啊?幾個人下午排查了半天,一直沒發現問題到底是怎麼回事兒。只能採用最笨的方法-抓包,然後請我們的好朋友wireshark分析下。同事在伺服器端和客戶端同時抓包,可是有時候就是這樣,你越希望它重現,它反而越不出現。懊惱。。。

下班之前,CTO問查的如何了。大眼瞪小眼,不敢定結論。

他說他看下,第二天中午,cto拉我們去說這個問題,他找到原因了。

他給我們看異常斷開連線前的包,發現斷開連線之前會發兩個包,每個包間隔是2s,上一條訊息的間隔時間是20s,多次異常斷開都是如此。這應該不是巧合,這個包來自伺服器端,這說明伺服器發完這兩個包之後,沒有得到響應,就把客戶端斷開了連線。這個實際上是伺服器的tcp連線的keeplive機制,當伺服器檢測到一個socket端長時間不活動的時候,就會傳送一個探測包檢測client端是否還在,而當client端收到不迴應的時候,會關閉連線,回收資源。linux核心跟這個相關的引數有三個:

tcp_keepalive_time(開啟keepalive的閒置時長)
tcp_keepalive_intvl(keepalive探測包的傳送間隔)
tcp_keepalive_probes (如果對方不予應答,探測包的傳送次數)

那是不是這三個核心引數的配置問題呢?檢查當前配置:

net.ipv4.tcp_keepalive_intvl = 2
net.ipv4.tcp_keepalive_probes = 2
net.ipv4.tcp_keepalive_time = 20
複製程式碼

果然,跟猜想一樣,問題出自這個配置,初始化伺服器的時候,會有指令碼自動調優。加上應用層上編寫程式碼時,並沒有設定此引數,覆蓋系統的設定。所以導致了總是莫名其妙的自己斷開。

真相大白,對cto的崇拜又多了幾分,總能在眾人迷惑的時候,站出來當指明燈。

解決方案:

1. 應用層增加socket保活引數配置,覆蓋系統配置(完美)

2. 直接修改系統配置檔案/etc/sysctl.conf,應用層增加心跳機制,空閒狀態時,每隔19s傳送一個心跳包過去(實際採用)。

順便說一下,之前移動端確實沒有發生斷開連線的異常情況,是因為移動端的開發主動加過保活機制,贊一個。

附錄: tcp長連線和保活時間(keepalive) keeplive詳解


作者:mUncleWang 來源:CSDN 原文:https://blog.csdn.net/qq_30164225/article/details/80714617 版權宣告:本文為博主原創文章,轉載請附上博文連結!

相關文章