關於Socket通訊中的Close_wait狀態
文/轉 編輯
編者按:使用Socket通訊,有時我們查看端口狀態的時候,經常會發現Socket處於close_wait狀態,從而影響系統性能,此文或許會給你一些答案。
最近遇到的一個關於socket.close的問題,在某個應用服務器出現的狀況(執行netstat -np | grep tcp):
tcp 0 0 10.224.122.16:50158 10.224.112.58:8788 CLOSE_WAIT
tcp 0 0 10.224.122.16:37655 10.224.112.58:8788 CLOSE_WAIT
tcp 1 0 127.0.0.1:32713 127.0.0.1:8080 CLOSE_WAIT
tcp 38 0 10.224.122.16:34538 10.224.125.42:443 CLOSE_WAIT
tcp 38 0 10.224.122.16:33394 10.224.125.42:443 CLOSE_WAIT
tcp 1 0 10.224.122.16:18882 10.224.125.10:80 CLOSE_WAIT
tcp 1 0 10.224.122.16:18637 10.224.125.10:80 CLOSE_WAIT
tcp 1 0 10.224.122.16:19655 10.224.125.12:80 CLOSE_WAIT
........................................
總共出現了200個CLOSE_WAIT的socket.而且這些socket長時間得不到釋放.下面我們來看看為什么會出現這種大量socket的CLOSE_WAIT情況
首先我們要搞清楚的是,這個socket是誰發起的,我們可以看到122.16這台機器開了很多端口,而且端口號都很大,125.12 或者125.10上的端口都是很常見服務器端口,所以122.16上這么多CLOSE_WAIT
的socket是由122.16開啟的,換句話說這台機器是傳統的客戶端,它會主動的請求其他機器的服務端口.
要搞清楚為什么會出現CLOSE_WAIT,那么首先我們必須要清楚CLOSE_WAIT的機制和原理.
假設我們有一個client, 一個server.
當client主動發起一個socket.close()這個時候對應TCP來說,會發生什么事情呢?如下圖所示.
client首先發送一個FIN信號給server, 這個時候client變成了FIN_WAIT_1的狀態, server端收到FIN之后,返回ACK,然后server端的狀態變成了CLOSE_WAIT.
接着server端需要發送一個FIN給client,然后server端的狀態變成了LAST_ACK,接着client返回一個ACK,然后server端的socket就被成功的關閉了.
從這里可以看到,如果由客戶端主動關閉一鏈接,那么客戶端是不會出現CLOSE_WAIT狀態的.客戶端主動關閉鏈接,那么Server端將會出現CLOSE_WAIT的狀態.
而我們的服務器上,是客戶端socket出現了CLOSE_WAIT,由此可見這個是由於server主動關閉了server上的socket.
那么當server主動發起一個socket.close(),這個時候又發生了一些什么事情呢.
從圖中我們可以看到,如果是server主動關閉鏈接,那么Client則有可能進入CLOSE_WAIT,如果Client不發送FIN包,那么client就一直會處在CLOSE_WAIT狀態(后面我們可以看到有參數可以調整這個時間).
那么現在我們要搞清楚的是,在第二中場景中,為什么Client不發送FIN包給server.要搞清楚這個問題,我們首先要搞清楚server是怎么發FIN包給client的,其實server就是調用了
socket.close方法而已,也就是說如果要client發送FIN包,那么client就必須調用socket.close,否則就client就一直會處在CLOSE_WAIT。