【TCP/IP詳解 卷一:協議】TCP的小結


前言:TCP學習的綜述

在學習TCP/IP協議的大頭:TCP協議 的過程中,遇到了很多機制和知識點,詳解中更是用了足足8章的內容介紹它。
TCP協議作為 應用層 和 網絡層 中間的 傳輸層協議,既要為下面的網絡層協議保證連接的可靠性(IP協議)彌補不足,又要作為 應用層進程向網絡層發送數據的中轉站(作為多路復用/解復用器)。

這就使得我們在審視TCP這個協議的過程中,需要橫向和縱向地看待TCP連接

  • 橫向的連接:client 的 TCP 與 server 的 TCP。三握四揮,是 reliable 的體現。
  • 縱向的連接:網絡層 和 應用層 之間聯系的紐帶,協助 應用層 向網絡層 轉遞數據。

與此同時,在TCP的學習中,我們還需要解答TCP的相關問題:

reliable

TCP是如何保障連接的可靠性的?-超時重傳的內容

Control

TCP是如何解決網絡擁塞的?-各種機制:慢啟動,擁塞避免,經受時延的ACK···
TCP是如何解決流量控制(目的:提高網絡的利用率)的?-窗口機制:擁塞窗口,通告窗口···

我想,正是在 reliable 和 control 兩部分,TCP下足了功夫。
保證 reliable 的目的是為了解決網絡層協議的不足之處:解決數據的丟失重傳問題,使得傳輸數據的連接變得更加可靠;而 control 的目的則是想辦法使得傳輸的效率更高。兩者相互影響:
比如我重發數據報的時候會不會造成網絡的擁塞?我控制網絡擁塞的時候會不會導致傳輸效率的低下?我要什么時候控制網絡擁塞而不會過度控制 導致我的一些重要信息發送緩慢?我要什么時候發送數據報才不會造成更加嚴重的網絡擁塞?

正是為了解決這些十分糾結的問題,TCP誕生了。正是它的偉大和不足,以及為了解決它的不足提出的各種各樣的方法,使得它具有迷人的魅力。

本文不會過多的摳細節,是一篇對 TCP各部分的小結,試圖闡述清楚它們之間的關系。

建議參考文章:TCP協議疑難雜症全景解析

第一部分:TCP是怎么建立連接的?-三握四揮

眾所周知,TCP是通過 三次握手 和 四次揮手 來建立/終止一個 client-server TCP連接的。

三次握手 四次揮手

三次握手 建立起 TCP連接 的 reliable,分配初始序列號和資源,在相互確認之后開始數據的傳輸。有 主動打開(一般是client) 和 被動打開(一般是server)。
四次揮手,因為TCP連接是全雙工的,數據可以在兩個方向上進行傳遞,因此在關閉的時候需要必須單獨終止兩個方向的數據傳輸。有 主動關閉(一般是client) 和 被動關閉(一般是server)。

狀態轉移

既然有三握四揮的機制,那么在它進行的過程中,client端 和 server端 就有不同的狀態,在SYN報文,FIN報文或者是ack的發送/接收,都會導致狀態的轉移。也就有了TCP狀態轉移圖:

研究清楚這幅圖是學習 TCP連接的建立與終止 的關鍵。

需要特別注意的是,在結束一個TCP連接的時候,client端有三種狀態(FIN_WAIT1,FIN_WAIT2,TIME_WAIT),server端有兩種狀態(CLOSE_WAIT,LAST_ACK).

client端 的 TIME_WAIT狀態(2MSL狀態)

當發送端 接收到 接收端的 FIN,並發送最后一個ack之后,發送端從 FIN_WAIT2狀態 進入 TIME_WAIT狀態。
TCP數據報有一個 報文段最大生存時間MSL,它是任何報文段被丟棄前在網絡內的最長時間。

設置2MSL狀態的目的是為了防止以下狀態:發送端發送的最后一個ack丟失。設置時間最長為 2MSL 的等待狀態,保證接收端的定時器超時重傳FIN,使得發送端重新發送最后一個ack。

如果說不這么做呢?
假如沒有2MSL狀態,服務器沒有收到最后一個ack,向發送端重發一個FIN,此時發送端已經關閉,這個FIN有可能被丟失,有可能遲到。倘若發送端和接收端 重新使用同一個套接字/插口對(socket):目的端IP地址,源IP地址,目的端端口號,源端口號組成的組合 所確定的連接,那么如果說FIN遲到了,並到達發送端,有可能異常終止這條連接。
所以我們要求,在2MSL等待狀態的時候,確定這條連接的插口對(socket)不能被使用,也就是說,不能用於建立新的連接。

復位

三種情況發送復位報文段:

  • 對方端口不存在
  • 異常關閉
  • 檢查半打開連接

需要注意的是 第三種情況:一方異常關閉但是另外一方還不知道,這在之后的保活定時器(keep-alive)有提到。

第二部分:TCP是如何保證可靠性的?-TCP的超時機制與重傳

TCP是如何保證數據傳輸的可靠性的?答曰重傳定時器。
重傳定時器,保證了發送方在定時器超時溢出且還沒有收到對數據的確認的時候,重新發送數據報,並啟動一些機制(數據報丟失很可能是因為網絡擁塞,為了減緩網絡擁塞,TCP提供了許多解決網絡擁塞的方法,這里提到的是慢啟動/擁塞避免)。

關於定時器時間的計算,采用了估計 往返時間RTT 和 重傳時間RTO 的策略。
(1)如果超時沒有接收到數據報,RTO 采用 指數退避 的方法更新。
(2)如果接收到了數據報,定時器首先跟蹤往返時間RTT,然后根據公式來計算 RTO。公式利用了 均值偏差 和 RTT估計器 來減小計算RTO時因為網絡時延等原因帶來的誤差。

重傳定時器的設計有兩個原則:一是 發送完如何一個報文,並長期收不到它的確認的時候,必須超時;二是 不能過早的超時:即超時的時間設置 不能和 測量的RTT 差太遠。

對於定時器,RFC有以下四則規則:
(1)發送TCP分段時,如果還沒有重傳定時器開啟,那么開啟它。
(2)發送TCP分段時,如果已經有重傳定時器開啟,不再開啟它。
(3)收到一個非冗余ACK時,如果有數據在傳輸中,重新開啟重傳定時器。
(4)收到一個非冗余ACK時,如果沒有數據在傳輸中,則關閉重傳定時器。

其中規則3是用於避免過早的重傳。
也就是說,當發送端一次性發送多個數據報的時候,比如一次性發送 A B C D 四個數據報(暫且不考慮擁塞窗口和通告窗口),當 發送A 的時候,啟動重傳定時器,在收到 A的確認 的時候,重置 重傳定時器。這樣保證不會出現這樣的情況:一次性發送完以上的四個數據報之后,發送端等待的是 對D數據報的確認,但是在定時器超時之前,除了比較早發送的 A B 發送方接收到了對它們的確認之外,並沒有收到 C 和 D 的確認,這就導致了 不必要的重傳。
大多數情況下,一個數據報測得的 往返時間RTT 約等於 重傳時間。

第三部分:TCP是如何保證傳輸數據的 效率 ?-流量控制 避免網絡擁塞

本節將看到,TCP對網絡的流量控制,和避免網絡擁塞的眾多機制:
經受時延的確認(接收方) Nagle算法(發送方) 通告窗口(接收方) 擁塞窗口(發送方) 滑動窗口機制(接收方 & 發送方) 慢啟動(發送方) 擁塞避免算法(發送方) 快速重傳和快速恢復(發送方) 糊塗窗口綜合症的解決方法(接收方 & 發送方)

一個死循環:網絡擁塞 -> 數據報丟失 -> 重傳 -> 網絡擁塞 ···
TCP是怎么樣解決這個死循環,並提高網絡的效率的呢?

角度一:接收方 與 發送方

角度一:接收方TCP獨有的 流量控制 和 避免網絡擁塞 的機制與措施

  • (1)避免過多的ack造成 低速網絡(如廣域網) 的網絡擁塞:經受時延的確認。
    聯系:Nagle算法,避免糊塗窗口綜合症的措施(防止小包)。
  • (2)避免接收方處理過慢,導致接收隊列溢出數據丟失:通告窗口。
    聯系:擁塞窗口,滑動窗口機制。

概要:

經受時延的確認/數據捎帶ACK:通常TCP在收到數據的時候,並不馬上發送對該數據的確認,相反,它推遲發送,以便將ACK與需要沿該方向發送的數據一起發送。絕大多數的時延為200ms。
在慢速網絡 比如廣域網上,過多的小包會造成一定的網絡擁塞,從而導致數據報的丟失,效率低下。而如果 接收方TCP 並不采用此機制,即一接收到數據報就發送對它的確認ACK,無疑會造成小包數量的劇增,再加上服務器本來就要向發送方發送的數據,造成網絡擁塞也就並不奇怪了。

通告窗口:接收方以一個比較慢的速率來處理接收的數據,而發送方以一個比較快的速率來發送數據,如果沒有一個合理的機制來控制的話,勢必會造成接收方接收隊列的溢出,網絡的擁塞以及數據的丟失。接收方提供的是 通告窗口,與 經受時延的ACK 或者是 數據 一起發送往發送方。

角度一:發送方TCP獨有的 流量控制 和 避免網絡擁塞 的機制與措施

  • (1)慢啟動 ssthresh 擁塞避免
    聯系:滑動窗口機制,通告窗口。
  • (2)擁塞窗口 -慢啟動提供:概要中與(1)一起
    聯系:滑動窗口機制,通告窗口。
  • (3)快速重傳,快速恢復算法
    聯系:慢啟動,擁塞避免等。
  • (4)Nagle算法 防止小包
    聯系:經受時延的ACK,避免糊塗窗口綜合症的措施。

概要:注意慢啟動和擁塞避免維持的兩個變量 ssthresh 與 cwnd

慢啟動:如果發送方一開始就向接收方發送多個報文段,直到達到接收方的通告窗口為止,很容易造成中間路由器的緩存溢出,耗盡存儲啟動空間,從而造成網絡擁塞。
慢啟動的工作方法是觀察到 新分組進入網絡的速率 = 另外一端確認分組的速率 來進行工作的。
慢啟動為發送方增添了:擁塞窗口,初始值為1,每接收到一個ack就增加1。發送數據報的數量取決於 min{擁塞窗口,通告窗口}。

但是,慢啟動一點也不慢,它的擁塞窗口的增長方式是 指數型的。這樣到了后期 擁塞窗口 必然會超過 通告窗口,也就達不到控制的效果了。
於是乎,我們引入了 擁塞避免算法。

擁塞避免算法:當擁塞窗口增大到一定程度的時候,我們采用擁塞避免算法,而不是慢啟動。慢啟動和擁塞避免算法之間的界限 我們稱之為 ssthresh(16個報文段,也就是65535字節,擁塞窗口的大小)。
擁塞窗口算法的實現:每收到一個ack,擁塞窗口增加1/cwnd,這是一種加性增長,放緩了慢啟動的指數增長。

慢啟動和擁塞避免的工作過程:教材P235.

慢啟動與擁塞避免的可視化描述:

快速重傳,快速恢復算法:我們並不知道 一個重復的ACK是由一個丟失報文段引起的,還是由於僅僅出現了幾個報文段的重新排序,因此我們必須等待少量的重復ACK的到來。如果一連串收到三個重復的ACK,那么基本可以確定是數據報丟失引起的,那么此時網絡很有可能已經擁塞,需要采取 慢啟動或者是擁塞避免的措施 來控制網絡擁塞。
在連續收到三個重復的ACK之后,我們不用等到定時器溢出,直接進行重傳,這就是快速重傳算法。接下來執行的 並不是 慢啟動 而是 擁塞避免,這就是快速恢復算法。
我們不想進入慢啟動的原因是因為,在收發兩端仍然有流動的數據,我們並不想使用慢啟動,從而造成數據流的突然減少。

快速重傳 快速恢復算法的工作過程:教材P237.

Nagle算法:發送方用於防止小包的措施,具體原因與 接收方TCP的 經受時延的ACK 一樣:避免慢速網絡的網絡擁塞。
該算法要求一個TCP連接上 最多只能有一個 未被確認的小分組,這導致了發送方數據的積累:在確認到達之前不允許發送小分組,相反TCP積累這些小分組,並在確認到達的時候“一股腦兒”以一個數據報的形式發送出去。
優越之處在於:確認到達的越快,數據發送的也就越快。它是自適應的。

發送方與接收方 共有的 防止網絡擁塞 和 控制流量 的措施

  • 滑動窗口機制:發送方TCP 的 擁塞窗口 與 接收方TCP 的 通告窗口 的共同作用。作用於發送端。
  • 糊塗窗口綜合症 與 發送方TCP 的 Nagle算法 和 接收方TCP 的 經受時延的ACK 有直接的關系。

概要:

首先談談 滑動窗口機制,它的可視化表示如下圖:

接收方 鑒於自身接收數據的快慢,向發送方提供 通告窗口,以實現對發送端發送流量的控制,這個通告窗口就是上圖中的 提供的窗口。
發送方 根據接收到數據報的情況,基於避免網絡擁塞的慢啟動算法,提供了擁塞窗口,即上圖中 發送但未被確認。

當發送方發送的數據 被成功確認的時候,滑動窗口的左沿向右移動;同時根據接收方新發送的通告窗口,右沿也向右移動。移動的距離是由 返回的確認號 與 發送端緩存的 目前第一個尚未被確認的數據報的初始序號 的差值所決定。

滑動窗口機制,即體現了 接收方根據自身情況對發送方的流量控制(通過通告窗口),避免了發送方一次性發送過多的數據導致讀取數據緩慢的接收方緩存溢出;又體現了 發送方TCP對網絡擁塞的監視,以及避免擁塞的策略(通過慢啟動算法 提供的 擁塞窗口)。

但是,接收方對發送方的流量控制 同時也會帶來一些不好的東西,就是我們接下來要引述的 糊塗窗口綜合症 了。
由於接收方處理數據十分緩慢,往往在一個數據報往返時間RTT內處理不了多少數據,這就導致了接收端經常會通告一些小窗口,這是我們不希望看到的:在前面有提到,過多的小包會加劇慢速網絡的網絡擁塞程度。這就是 糊塗窗口綜合症。

由於接收方可以通告一個小的窗口,發送方也可以發送小的數據,因此 避免糊塗窗口綜合症的對策也是從 對發送方 和 對接收方 兩個方面着手的:

(1)對發送方(在滿足以下條件之一的情況下發送數據)

  • 可以發送一個滿長度的數據報,即一個MSS長度的數據報。
  • 可以發送至少是通告窗口一半的數據
  • 可以發送任何數據但是不希望接收ACK(前面還有未確認的報文) 或者該連接上不能使用Nagle算法。

(2)對接收方

  • 接收方不通告小的窗口(特例:教材P249,防止滑動窗口右沿左移),並且一般不通告比目前的接收狀況 即窗口 更大的大小。除非 接收方應用進程接收了MSS大小的數據,或者處理了接收方一半緩存大小的數據。

糊塗窗口綜合症的解決方法,與發送方TCP的Nagle算法,和接收方的經受時延的ack,是TCP用於避免慢速網絡(WAN)網絡擁塞的策略。

角度小結:How to control?

通過角度一對於發送方和接收方各自以及共有的流量控制及避免網絡擁塞的策略進行了一個歸納。

有我們開頭的四個問題:

  • TCP是怎么樣知道發生了數據報丟失?
  • TCP怎么樣處理網絡擁塞?
  • TCP怎么樣控制重傳的時間 從而不會引起過度的不必要的重傳?
  • TCP怎么樣均衡 控制網絡擁塞 以及 傳輸效率?

以及這個死循環:網絡擁塞 -> 數據報丟失 -> 重傳
這個死循環很大程度的導致了傳輸數據效率的低下,於是乎,TCP必然要采取一定的措施來制止這個死循環的發生。

那么我們把這四個問題 和 這個死循環結合起來,根據上文的內容來解答他們。

(1)網絡擁塞,既然TCP知道可能會出現網絡擁塞,那么接收方和發送方的TCP肯定要想辦法避免它和解決它。
避免它:慢啟動算法 和 擁塞避免算法,慢啟動所提供的擁塞窗口;針對慢速網絡:Nagle算法,經受時延的ack,避免糊塗窗口綜合症的措施。
解決它:當擁塞發生的時候,我們希望降低分組進入網絡的傳輸速率,擁塞避免算法起到了很好的處理丟失分組的方法,在教材的P235詳細說明了擁塞避免算法在擁塞發生的時候所采取的措施(啟用慢啟動,設置ssthresh等)。

(2)數據報丟失,網絡擁塞造成了數據報丟失,發送方怎么樣知道數據報丟失?
處理數據報丟失的方法是 (3)重傳,那么發送方什么時候重傳不會造成重傳風暴 導致網絡擁塞?
TCP 在 發送數據的效率 和 減緩網絡擁塞 是怎么樣均衡的?

發送方是如何知道數據報丟失的?
-重傳定時器超時,或者是發送方接收到了三個重復的ack;前者重發數據報並利用指數退避更新RTO,后者立即重發數據報,進入快速重傳和快速恢復。
准確的來說,重傳定時器超時所估計的網絡擁塞比接受到的三個重復的ack所估計的網絡擁塞更加嚴重:收到三個重復的ack有可能是因為數據報的錯序導致的,說明后面的數據報接收方有收到,就進入快速重傳快速恢復狀態;而重傳定時器超時估計起來就嚴重的多了,網絡擁塞程度已經嚴重到丟失大量數據的階段了,因此必須使發送方重新進入調整網絡擁塞的狀態:慢啟動或者擁塞避免。

什么時候重傳 不會造成進一步的擁塞?
-控制重傳時間的 是重傳定時器,TCP利用對往返時間RTT的測量跟蹤路由器和網絡流量的變化,利用往返時間RTT的估計器以及均值偏差來確定重傳的時間,最大程度的降低了估計的誤差,並且利用RFC定義的重傳定時器的四個原則保證了它不會過早的重傳,從而造成不必要的重傳。

TCP是怎么樣均衡控制網絡擁塞 和 傳輸效率的?
-利用滑動窗口機制,以及慢啟動對擁塞窗口的“指數型增長” 和 擁塞避免對擁塞窗口的“加性增長”,盡可能的利用帶寬,同時也減小網絡擁塞發生的可能。
滑動窗口機制的擁塞窗口是發送方根據其對網絡擁塞的估計(利用RTT) 避免中間路由緩存的溢出 所采取的流量控制措施;而通告窗口則是 接收方 根據自身進程接收數據的快慢,以及在該連接上可用緩存的大小,采取的流量控制措施。
與此同時,避免網絡擁塞的 慢啟動 和 擁塞避免 也提供了利用網絡帶寬 提高網絡效率的方法:每接收到一個ack,就增加擁塞窗口的大小。
這樣,均衡地控制了網絡擁塞 也保證了一定的傳輸效率。

慢啟動和擁塞避免 是避免網絡擁塞,解決網絡擁塞的方法,它們作用於擁塞窗口,使在不同的網絡條件下(擁塞或者不擁塞)盡可能的利用帶寬。

這就是TCP中的control,內容既復雜又相互聯系,但是需要抓住本質的兩點來分析:1)控制流量,避免網絡擁塞 2)控制傳輸數據的效率


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM