哪時候 accept 成功上來的 TCP socket 會不是條 TCP 連線?

"哪時候 accept 成功上來的 TCP socket 會不是條 TCP 連線?" 是個在實際開發中遇到的狀況,雖然真實情況沒有像標題寫得這麼聳動?,但是也是滿有趣的小知識。

首先要知道的是 TCP 的三向交握在沒有 accept 前就已經做完了。Kernel 在 SYNC 封包一來的時候就開始做三向交握並在完成後把這條連線放到 listen 的 backlog 中等待有程式呼叫 accept() 來把 socket 拿去用。

那這個問題的解答之一就可以變成 "哪時候 TCP 連線會被關掉?",在這個狀況下比較容易發生的是 client 認為 server 一直沒有回他造成超時而關掉了 TCP 連線。當 client 端關掉連線後,我們知道 server TCP 的狀態就會進入 close wait 並隨後就關掉了這條 TCP 連線。

雖然 client 已經關掉了連線,但因為這個 socket 已經被丟進 backlog 了,應用程式是可以成功的 accept 到一個 socket,要呼叫 setsocketopt 也都沒有問題,但後續操作基本上都會失敗。

有個有趣的點是若對這樣的 socket 呼叫 getpeername(),是否成功就看 Kernel 實作多久會回收掉底層的結構了,在我的 Linux 機器上測試來是關掉後兩分鐘就沒辦法成功拿到 peer 的 IP 和 port 等資訊了。

總結:

如果以後遇到 accept 成功但 getpeername 失敗的時候,可以先考慮一下是否是這個狀況,是否是 server 太忙造成 accept 的速度太慢,而不是先懷疑網路設定有問題 XD

Like what you read? Give Jack Yu a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.