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

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

數據 https 端口 bsp 分享 結束 調用 解決問題 ref

一、問題概述

今天遇到個小問題。

我們的程序依賴了大數據那邊的服務,大數據那邊提供了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

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