深入淺出TCP協議的2MSL TIME_WAIT狀態


2MSL TIME_WAIT狀態存在的理由:
TIME_WAIT狀態的存在有兩個理由:(1)讓4次握手關閉流程更加可靠;4次握手的最后一個ACK是是由主動關閉方發送出去的,若這個ACK丟失,被動關閉方會再次發一個FIN過來。若主動關閉方能夠保持一個2MSL的TIME_WAIT狀態,則有更大的機會讓丟失的ACK被再次發送出去。(2)防止lost duplicate對后續新建正常鏈接的傳輸造成破壞。lost duplicate在實際的網絡中非常常見,經常是由於路由器產生故障,路徑無法收斂,導致一個packet在路由器A,B,C之間做類似死循環的跳轉。IP頭部有個TTL,限制了一個包在網絡中的最大跳數,因此這個包有兩種命運,要么最后TTL變為0,在網絡中消失;要么TTL在變為0之前路由器路徑收斂,它憑借剩余的TTL跳數終於到達目的地。但非常可惜的是TCP通過超時重傳機制在早些時候發送了一個跟它一模一樣的包,並先於它達到了目的地,因此它的命運也就注定被TCP協議棧拋棄。另外一個概念叫做incarnation connection,指跟上次的socket pair一摸一樣的新連接,叫做incarnation of previous connection。lost duplicate加上incarnation connection,則會對我們的傳輸造成致命的錯誤。大家都知道TCP是流式的,所有包到達的順序是不一致的,依靠序列號由TCP協議棧做順序的拼接;假設一個incarnation connection這時收到的seq=1000, 來了一個lost duplicate為seq=1000, len=1000, 則tcp認為這個lost duplicate合法,並存放入了receive buffer,導致傳輸出現錯誤。通過一個2MSL TIME_WAIT狀態,確保所有的lost duplicate都會消失掉,避免對新連接造成錯誤。

該狀態為什么設計在主動關閉這一方:
(1)發最后ack的是主動關閉一方
(2)只要有一方保持TIME_WAIT狀態,就能起到避免incarnation connection在2MSL內的重新建立,不需要兩方都有

如何正確對待2MSL TIME_WAIT
RFC要求socket pair在處於TIME_WAIT時,不能再起一個incarnation connection。但絕大部分TCP實現,強加了更為嚴格的限制。在2MSL等待期間,socket中使用的本地端口在默認情況下不能再被使用。若A 10.234.5.5: 1234和B 10.55.55.60:6666建立了連接,A主動關閉,那么在A 端只要 port為1234,無論對方的port和ip是什么,都不允許再起服務。顯而易見這是比RFC更為嚴格的限制,RFC僅僅是要求socket pair不一致,而實現當中只要這個port處於TIME_WAIT,就不允許起連接。這個限制對主動打開方來說是無所謂的,因為一般用的是臨時端口;但對於被動打開方,一般是server,就悲劇了,因為server一般是熟知端口。比如http,一般端口是80,不可能允許這個服務在2MSL內不能起來。解決方案是給服務器的socket設置SO_REUSEADDR選項,這樣的話就算熟知端口處於TIME_WAIT狀態,在這個端口上依舊可以將服務啟動。當然,雖然有了SO_REUSEADDR選項,但sockt pair這個限制依舊存在。比如上面的例子,A通過SO_REUSEADDR選項依舊在1234端口上起了監聽,但這時我們若是從B通過6666端口去連它,TCP協議會告訴我們連接失敗,原因為Address already in use.

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com