網(wǎng)絡(luò)連接無法釋放—— CLOSE_WAIT
Posted on 2009-04-11 13:54 Prayer 閱讀(2804) 評論(0) 編輯 收藏 引用 所屬分類: SOCKET問題描述:最近性能測試碰到的一個問題。客戶端使用NIO,服務(wù)器還是一般的Socket連接。當(dāng)測試進(jìn)行一段時間以后,發(fā)現(xiàn)服務(wù)器端的系統(tǒng)出現(xiàn)大量未釋放的網(wǎng)絡(luò)連接。用netstat -na查看,連接狀態(tài)為CLOSE_WAIT。這就奇怪了,為什么Socket已經(jīng)關(guān)閉而連接依然未釋放。
解決:Google了半天,發(fā)現(xiàn)關(guān)于CLOSE_WAIT的問題一般是C的,Java似乎碰到這個問題的不多(這有一篇不錯的,也是解決CLOSE_WAIT的,但是好像沒有根本解決,而是選擇了一個折中的辦法)。接著找,由于使用了NIO,所以懷疑可能是這方面的問題,結(jié)果找到了這篇。順著帖子翻下去,其中有幾個人說到了一個問題—— 一端的Socket調(diào)用close后,另一端的Socket沒有調(diào)用close.于是查了一下代碼,果然發(fā)現(xiàn)Server端在某些異常情況時,沒有關(guān)閉Socket。改正后問題解決。
時間基本上花在Google上了,不過也學(xué)到不少東西。下面為一張TCP連接的狀態(tài)轉(zhuǎn)換圖:
說明:虛線和實線分別對應(yīng)服務(wù)器端(被連接端)和客戶端端(主動連接端)。
結(jié)合上圖使用netstat -na命令即可知道到當(dāng)前的TCP連接狀態(tài)。一般LISTEN、ESTABLISHED、TIME_WAIT是比較常見。
分析:
上面我碰到的這個問題主要因為TCP的結(jié)束流程未走完,造成連接未釋放?,F(xiàn)設(shè)客戶端主動斷開連接,流程如下
Client 消息 Server
close()
------ FIN ------->
FIN_WAIT1 CLOSE_WAIT
<----- ACK -------
FIN_WAIT2
close()
<------ FIN ------
TIME_WAIT LAST_ACK
------ ACK ------->
CLOSED
CLOSED
如上圖所示,由于Server的Socket在客戶端已經(jīng)關(guān)閉時而沒有調(diào)用關(guān)閉,造成服務(wù)器端的連接處在“掛起”狀態(tài),而客戶端則處在等待應(yīng)答的狀態(tài)上。此問題的典型特征是:一端處于FIN_WAIT2 ,而另一端處于CLOSE_WAIT. 不過,根本問題還是程序?qū)懙牟缓?,有待提高?/p>