[linux][tcp]CLOSE_WAIT的一個TCP問題
- 2019 年 12 月 13 日
- 筆記
前言
某機器上殘留了很多CLOSE_WAIT狀態的TCP連接,使用netstat卻看不到是哪一個進程在使用。
分析
TCP狀態機
回顧一下TCP的狀態機,處於ESTABLISHED狀態的TCP連接收到FIN訊號後,回復ACK,會進入到CLOSE_WAIT狀態。

通常的CLOSE_WAIT狀態的TCP連接

通常情況下,我們可以通過netstat -aptn來獲取到TCP連接的資訊,如上圖,可以知道CLOSE_WAIT狀態的TCP連接屬於50871進程,大概率是用戶邏輯處理有問題,沒有執行close/shutdown來關閉TCP連接。
沒有進程號的CLOSE_WAIT狀態的TCP連接

還有一種情況,沒有進程歸屬的CLOSE_WAIT狀態的TCP連接。
同時,我們使用lsof命令,或者ls -al /proc/PID/fd同樣也看不到目標進程有對應的fd。
那麼,這些連接是怎麼來的呢?
在TCP的三次握手之後,TCP連接已經進入了ESTABLISHED。而且,不管server端是否執行accept,都會完成三次握手。
在三次握手完成之後(內核態完成),在用戶進程沒有執行accept之前,內核會把對應的socket加入到listen的隊列中。在隊列中的socket,在server端執行accept之前,client執行了close/shutdown操作,在server端就會看到上圖中的現象:大量的沒有進程歸屬的CLOSE_WAIT狀態的TCP連接。
解決辦法
只要server及時執行accept操作即可。否則,因為listen的隊列已經滿了,無法讓其他的連接正常執行。
那麼,能不能自動丟棄這種沒有進程歸屬的CLOSE_WAIT狀態的TCP連接?作者查詢linux-4.19的TCP邏輯,發現只有兩種情況下會有從listen的隊列中的dequeue操作:1,執行accept操作; 2,關閉listen fd。