1. 程式人生 > >tcp連接出現close_wait狀態?可能是程式碼不夠健壯

tcp連接出現close_wait狀態?可能是程式碼不夠健壯

一、問題概述

今天遇到個小問題。

我們的程式依賴了大資料那邊的服務,大資料那邊提供了restful介面供我們呼叫。

測試反映介面有問題,我在本地重現了。找了大資料方的同事,解決了。

剛開始怕對方不認賬,就用wireshark抓包了。沒想到對方還挺爽快地解決了。

然後我這邊重新測試,自己抓包了下,結果反而發現我方程式的一個問題。

 

下圖,是我方和大資料方的互動資料包。

 

前三個為tcp連線建立,中間(序號4,5,6)為http請求響應,序號7-8為大資料方在請求完畢後關閉連線。

好了,看下面的圖:(下面這個tcp狀態變遷圖網上到處都是,一定要學會看。)

 

我們重點關注下面紅色部分:

當一個tcp實體(以我方為例),當我方和大資料方建立連線後,一直處於下面的established狀態。

請求結束後,收到對方的FIN(下圖紅色的recv:FIN),我方迴應ACK。(下圖紅色的send:ACK)。

然後我方進入了CLOSE_WAIT狀態。

 

於是我就去cmd裡面檢視下:

 

 果然存在這個close_wait狀態的連線。

但是過了沒特別久,一兩分鐘吧,這個狀態自己消失了。(猜測是作業系統設定了close_wait超時時間,超時後主動發起fin請求斷開連線)

暫時還沒找到原因,大佬知道的話,還請告知下(我的是win7 64位)。

 

二、關於close_wait

這個狀態要怎麼才能進入下一個狀態(LAST_ACK)呢?

看最上面的變遷圖可以知道,我方tcp實體只要發起一個FIN即可。這個FIN怎麼才能發起呢?

那就需要程式主動去關閉連線。

我看了下程式碼,果然是我方的httpclient使用完了沒關閉。。(右邊是我改後的程式碼,,下面把被關閉的兩個變數的完整類名也展示一下)

org.apache.http.impl.client.CloseableHttpClient.CloseableHttpClient httpClient;
org.apache.http.client.methods.CloseableHttpResponse.CloseableHttpResponse response;

 

 

 再看我上面的抓包的圖的最後兩行:

 

過了一定時間後,我方可能是在close_wait狀態下持續了一定時間,觸發了超時,主動向對方發起了FIN。

但是呢,對方其實已經關閉連線了,所以就返回了RST。(對方已經把連線刪除了)

 

我把程式照上面修改後,重新請求了一次:(已經恢復正常了,如下)

 

三、close_wait過多怎麼辦

結論先說:改程式碼。

 我方程式上線的話,部署在伺服器上,close_wait過多,會導致新建立連線失敗(因為埠未釋放的原因。)

這個問題,就是本端tcp實體(被動關閉的一端)沒有主動關閉連線,大部分都是程式的問題。

要改的話,還是具體看看哪個程式有問題,找到具體的程式後(通過檢視有大量close_wait狀態的程式的pid),

再看程式裡和哪個遠端host的連線處於該狀態。

然後再去程式裡找對應的程式碼,修改即可。

 

部分網上的文章,是運維手動清楚close_wait。或者修改close_wait的超時時間。

這個可以解決問題,但是為了程式的健壯性著想,還是修改程式吧。

在伺服器與客戶端通訊過程中,因伺服器發生了socket未關導致的closed_wait發生,致使監聽port開啟的控制代碼數到了1024個,且均處於close_wait的狀態,最終造成配置的port被佔滿出現“Too many open files”,無法再進行通訊。

這個可以參考:

https://blog.csdn.net/wwd0501/article/details/78674170

 

https://blog.csdn.net/mnasd/article/details/80496032