TCP
連線是雙向傳輸的對等的模式(全雙工模式),就是說雙方都可以同時向對方傳送或接收資料。
而斷開的時候,也是雙方都可以主動斷開,此時需要經過四次揮手的過程,流程如下圖所示:
- 主動方傳送
FIN
包給被動方,主動方狀態變成FIN_WAIT_1
,等待被動方的確認。此時主動方不能再傳送資料。 - 被動方收到
FIN
之後,返回ACK
包給主動方,確認自己收到這個包,被動方狀態變成CLOSE_WAIT
,等待關閉連線(等待快取資料都傳送過去) - 主動方收到
ACK
之後,狀態變成FIN_WAIT_2
,等待被動方的FIN
包。 - 被動方將緩衝區剩餘的資料傳送給主動方。
- 被動方傳送
FIN
給主動方,被動方狀態變成LAST_ACK
狀態。 - 主動方收到
FIN
之後,返回ACK
包給被動方,主動方變成TIME_WAIT
狀態。 - 被動方收到
ACK
確認後,變成CLOSE
狀態。 - 主動方在經過
2MSL
時間之後,變成CLOSE
狀態。
MSL(Maximum Segment Lifetime)指報文最大生存時間,它是任何報文在網路上存在的最長時間,超過這個時間報文將被丟棄。
為什麼握手需要三次,而揮手需要四次?
因為 TCP
連線是全雙工模式,一方斷開連線,另一方還是可以繼續傳送資料,所以無法像三次握手一樣,將 FIN
和 ACK
合併到一起,而是需要等待被動方處理完所有資料,不再有資料傳送時,才會傳送 FIN
,來關閉被動方的連線。
為什麼需要 TIME_WAIT
狀態?
需要 TIME_WAIT
狀態,主要是兩個原因:
- 防止歷史連線中的資料,被後面相同四元組的連線錯誤的接收:
在連線關閉過程中,可能會存在一些延遲的資料包在網路中,這些資料包可能在連線關閉後到達目的地。TIME_WAIT
狀態的存在可以確保在這段時間內不會接收到與當前連線相關的舊資料包,防止這些資料包造成連線的混亂。 - 保證「被動關閉連線」的一方,能被正確的關閉:
如果主動方收到FIN
,發出ACK
之後,直接進入CLOSE
狀態,那麼當這個ACK
丟失時,被動方收不到ACK
則會重發一個FIN
,但此時主動方已經是CLOSE
狀態,無法再給被動方傳送ACK
了。
如果兩端同時關閉,會出現什麼情況?
前面說過,TCP
連線雙方都可以主動斷開,那如果兩邊同時斷開,會怎樣呢?
從上圖可以看到,一方發出FIN
,進入FIN_WAIT_1
狀態,原本期待收到ACK
,但此時收到了FIN
,則會變成CLOSING
狀態,等到收到ACK
時,再進入TIME_WAIT
狀態,同樣要經過2MSL
時間變成CLOSE
狀態。
參考資料
- TCP連線斷開 - 小林coding