天天看點

為什麼TCP裡面有TIME_WAIT狀态

今天在實作TCP/IP協定棧中的連接配接管理管理功能的時候,遇到一個TIME_WAIT狀态,處于TIME_WAIT狀态的tcp socket 在等待2個Max Segment Lifttime以後就會轉移到closed狀态。

覺得有些奇怪,以下是我的一點了解。

為什麼TCP裡面有TIME_WAIT狀态

首先這個TIME_WAIT一定是從FIN_WAIT_2轉移過來的。進入TIME_WAIT意味着這個tcp socket在主動關閉的時候,自己的FIN已經被對方确認,而且對方也發了一個FIN過來表示對方也沒有什麼資料要主動傳輸了。

是以,處于TIME_WAIT等待這麼久的時間首先有第一個作用: 對 對方FIN的ACK确認有可能在傳輸過程被丢棄。于是對方會重新發送FIN,停留在TIME_WAIT可以對重傳的FIN進行确認。否則,對方将一直處于LAST_ACK狀态。

第二個作用就比較隐蔽了,TCP的TIME_WAIT故意讓主動關閉連接配接的socket等待這麼長的時間是為了讓這個socket的那些舊的仍然在網絡中傳輸的資料包能夠從整個網絡清空出去。

既然socket都跑到TIME_WAIT為什麼還有在空中飛的舊資料包呢?這主要是一些逾時的但是又沒有被丢棄的資料包,這些資料包在前面的傳輸中被檢測到逾時了,于是tcp啟動了逾時重傳機制,而且還走了新的、更不擁塞的鍊路,于是導緻這些重傳的資料包反而更快被對端确認。

這些姗姗來遲的舊資料包如果在TIME_WAIT階段到達,就會被丢棄掉。

然而,如果這個主動的關閉的socket 沒有等待足夠長的時間,而是又用着相同的端口号去建立一個新的TCP連接配接,那麼這些舊的資料包就幹擾新的連接配接。雖然,新的連接配接可以通過seq和ack來識别出這些舊資料包的seq、ack不合理,但是TCP的規範是要求不能這麼搞的,因為TCP規範并沒有要求所有的初始序列号怎麼選擇,如果剛好選擇的初始序列号和舊的資料包的seq吻合了,那麼就很麻煩了。

也正是因為有TIME_WAIT狀态的存在,導緻我們在主動關閉一個socket的時候,盡管包含這個socket的程序已經關閉了,但是這個socket還處與TIME_WAIT狀态,再次啟動這個程序是無法再去bind這個socket直到這個socket從TIME_WAIT轉移到CLOSED去。

繼續閱讀