《TIME_WAIT and its design implications for protocols and scalable client server systems》 這篇真是不可思議的詳細易懂, 讀完後大概理解 TCP 結束時的前因後果了。
首先要理解的前提是, 無論 process 如何結束, 只要網路連線正常, TCP 會保證另一端得知連線結束。
接著問題要視主動 close 和被動 close 兩個方向來看。被動 close 比較單純, 會進入 CLOSE_WAIT, 程式要記得呼叫 close() 然後就沒事了。由 man page 得知, recv() 回傳 0 bytes 表示另一端結束連線。在 blocking IO 的情況下很單純, 不太會忘了 close。 non-blocking 的情況有可能寫出 bug, 而一直沒呼叫 close(), 這時用 netstat 可看到這類的連線狀態一直卡在 CLOSE_WAIT。
主動 close 的時候, 一切順利最後會進入 TIME_WAIT, 然後就是等一段時間才真的釋放使用的 port。對於同時需要主動連線出去 (做為別人的 client) 的 server 來說, 短時間內大量累加的 TIME_WAIT 有可能造成 port 不足而無法連線出去, 所以這篇的作者建議在設計 protocol 時, 盡量讓 client 主動結束連線。
綜合以上的訊息, 我理解的架構是: 盡可能讓 client 關掉連線, 再加上一個合理的長時間 timeout, 只有在 timeout 的情況下 server 才會主動關掉連線。發生 timeout 有兩種可能: client 其實「還在線上」, 只是很久沒傳資料; 或是 client 斷網後, 長於 timeout 的時間沒有連上網路。但不論何者, 為了減省 server 資源 (# of fd, memory, thread, etc), timeout 仍是必要的。
我之前在理解 TCP 斷線議題時, 一直卡在程式要怎麼知道對方斷線了? 搞清楚 kernel 實作 TCP 這點並做了些實驗後, 加上讀完這篇, 才恍然大悟。
請問一下, 我有一個系統是擔任FTP Client的角色, 上傳檔案到FTP Server, 可是用netstat卻發現有大量處於 CLOSE_WAIT , 是被動式關閉才有可能發生嗎?
回覆刪除