www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]每日一句英語(yǔ)學(xué)習(xí),每天進(jìn)步一點(diǎn)點(diǎn): 來(lái)自:小林coding 前言 前一篇「硬不硬你說(shuō)了算!近 40 張圖解被問(wèn)千百遍的 TCP 三次握手和四次揮手面試題」得到了很多讀者的認(rèn)可,在此特別感謝你們的認(rèn)可,大家都暖暖的。 來(lái)了,今天又來(lái)圖解 TCP 了,小林可能會(huì)遲到,

每日一句英語(yǔ)學(xué)習(xí),每天進(jìn)步一點(diǎn)點(diǎn):
你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了 來(lái)自:小林coding

前言

前一篇「TCP 三次握手和四次揮手面試題" tab="innerlink" data-linktype="2" rel="nofollow">硬不硬你說(shuō)了算!近 40 張圖解被問(wèn)千百遍的 TCP 三次握手和四次揮手面試題」得到了很多讀者的認(rèn)可,在此特別感謝你們的認(rèn)可,大家都暖暖的。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

來(lái)了,今天又來(lái)圖解 TCP 了,小林可能會(huì)遲到,但不會(huì)缺席。

遲到的原因,主要是 TCP 巨復(fù)雜,它為了保證可靠性,用了巨多的機(jī)制來(lái)保證,真是個(gè)「?jìng)ゴ蟆沟膮f(xié)議,寫著寫著發(fā)現(xiàn)這水太深了。。。

本文的全部圖片都是小林繪畫的,非常的辛苦且累,不廢話了,直接進(jìn)入正文吧,Go!


正文

相信大家都知道 TCP 是一個(gè)可靠傳輸?shù)膮f(xié)議,那它是如何保證可靠的呢?

為了實(shí)現(xiàn)可靠性傳輸,需要考慮很多事情,例如數(shù)據(jù)的破壞、丟包、重復(fù)以及分片順序混亂等問(wèn)題。如不能解決這些問(wèn)題,也就無(wú)從談起可靠傳輸。

那么,TCP 是通過(guò)序列號(hào)、確認(rèn)應(yīng)答、重發(fā)控制、連接管理以及窗口控制等機(jī)制實(shí)現(xiàn)可靠性傳輸?shù)摹?/p>

今天,將重點(diǎn)介紹 TCP 的重傳機(jī)制、滑動(dòng)窗口、流量控制、擁塞控制

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
提綱

重傳機(jī)制

TCP 實(shí)現(xiàn)可靠傳輸?shù)姆绞街?,是通過(guò)序列號(hào)與確認(rèn)應(yīng)答。

在 TCP 中,當(dāng)發(fā)送端的數(shù)據(jù)到達(dá)接收主機(jī)時(shí),接收端主機(jī)會(huì)返回一個(gè)確認(rèn)應(yīng)答消息,表示已收到消息。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
正常的數(shù)據(jù)傳輸

但在錯(cuò)綜復(fù)雜的網(wǎng)絡(luò),并不一定能如上圖那么順利能正常的數(shù)據(jù)傳輸,萬(wàn)一數(shù)據(jù)在傳輸過(guò)程中丟失了呢?

所以 TCP 針對(duì)數(shù)據(jù)包丟失的情況,會(huì)用重傳機(jī)制解決。

接下來(lái)說(shuō)說(shuō)常見的重傳機(jī)制:

  • 超時(shí)重傳

  • 快速重傳

  • SACK

  • D-SACK

超時(shí)重傳

重傳機(jī)制的其中一個(gè)方式,就是在發(fā)送數(shù)據(jù)時(shí),設(shè)定一個(gè)定時(shí)器,當(dāng)超過(guò)指定的時(shí)間后,沒有收到對(duì)方的 ACK 確認(rèn)應(yīng)答報(bào)文,就會(huì)重發(fā)該數(shù)據(jù),也就是我們常說(shuō)的超時(shí)重傳。

TCP 會(huì)在以下兩種情況發(fā)生超時(shí)重傳:

  • 數(shù)據(jù)包丟失

  • 確認(rèn)應(yīng)答丟失

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
超時(shí)重傳的兩種情況

超時(shí)時(shí)間應(yīng)該設(shè)置為多少呢?

我們先來(lái)了解一下什么是 RTT(Round-Trip Time 往返時(shí)延),從下圖我們就可以知道:

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
RTT

RTT 就是數(shù)據(jù)從網(wǎng)絡(luò)一端傳送到另一端所需的時(shí)間,也就是包的往返時(shí)間。

超時(shí)重傳時(shí)間是以 RTO (Retransmission Timeout 超時(shí)重傳時(shí)間)表示。

假設(shè)在重傳的情況下,超時(shí)時(shí)間 RTO 「較長(zhǎng)或較短」時(shí),會(huì)發(fā)生什么事情呢?

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
超時(shí)時(shí)間較長(zhǎng)與較短

上圖中有兩種超時(shí)時(shí)間不同的情況:

  • 當(dāng)超時(shí)時(shí)間 RTO 較大時(shí),重發(fā)就慢,丟了老半天才重發(fā),沒有效率,性能差;

  • 當(dāng)超時(shí)時(shí)間 RTO 較小時(shí),會(huì)導(dǎo)致可能并沒有丟就重發(fā),于是重發(fā)的就快,會(huì)增加網(wǎng)絡(luò)擁塞,導(dǎo)致更多的超時(shí),更多的超時(shí)導(dǎo)致更多的重發(fā)。

精確的測(cè)量超時(shí)時(shí)間 RTO 的值是非常重要的,這可讓我們的重傳機(jī)制更高效。

根據(jù)上述的兩種情況,我們可以得知,超時(shí)重傳時(shí)間 RTO 的值應(yīng)該略大于報(bào)文往返  RTT 的值。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
RTO 應(yīng)略大于 RTT

至此,可能大家覺得超時(shí)重傳時(shí)間 RTO 的值計(jì)算,也不是很復(fù)雜嘛。

好像就是在發(fā)送端發(fā)包時(shí)記下 t0 ,然后接收端再把這個(gè) ack 回來(lái)時(shí)再記一個(gè) t1,于是 RTT = t1 – t0。沒那么簡(jiǎn)單,這只是一個(gè)采樣,不能代表普遍情況

實(shí)際上「報(bào)文往返 RTT 的值」是經(jīng)常變化的,因?yàn)槲覀兊木W(wǎng)絡(luò)也是時(shí)常變化的。也就因?yàn)椤笀?bào)文往返 RTT 的值」 是經(jīng)常波動(dòng)變化的,所以「超時(shí)重傳時(shí)間 RTO 的值」應(yīng)該是一個(gè)動(dòng)態(tài)變化的值。

我們來(lái)看看 Linux 是如何計(jì)算 RTO 的呢?

估計(jì)往返時(shí)間,通常需要采樣以下兩個(gè):

  • 需要 TCP 通過(guò)采樣 RTT 的時(shí)間,然后進(jìn)行加權(quán)平均,算出一個(gè)平滑 RTT 的值,而且這個(gè)值還是要不斷變化的,因?yàn)榫W(wǎng)絡(luò)狀況不斷地變化。

  • 除了采樣 RTT,還要采樣 RTT 的波動(dòng)范圍,這樣就避免如果 RTT 有一個(gè)大的波動(dòng)的話,很難被發(fā)現(xiàn)的情況。

RFC6289 建議使用以下的公式計(jì)算 RTO:

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
RFC6289 建議的 RTO 計(jì)算

其中 SRTT 是計(jì)算平滑的RTT ,DevRTR 是計(jì)算平滑的RTT 與 最新 RTT 的差距。

在 Linux 下,α = 0.125,β = 0.25, μ = 1,? = 4。別問(wèn)怎么來(lái)的,問(wèn)就是大量實(shí)驗(yàn)中調(diào)出來(lái)的。

如果超時(shí)重發(fā)的數(shù)據(jù),再次超時(shí)的時(shí)候,又需要重傳的時(shí)候,TCP 的策略是超時(shí)間隔加倍。

也就是每當(dāng)遇到一次超時(shí)重傳的時(shí)候,都會(huì)將下一次超時(shí)時(shí)間間隔設(shè)為先前值的兩倍。兩次超時(shí),就說(shuō)明網(wǎng)絡(luò)環(huán)境差,不宜頻繁反復(fù)發(fā)送。

超時(shí)觸發(fā)重傳存在的問(wèn)題是,超時(shí)周期可能相對(duì)較長(zhǎng)。那是不是可以有更快的方式呢?

于是就可以用「快速重傳」機(jī)制來(lái)解決超時(shí)重發(fā)的時(shí)間等待。

快速重傳

TCP 還有另外一種快速重傳(Fast Retransmit)機(jī)制,它不以時(shí)間為驅(qū)動(dòng),而是以數(shù)據(jù)驅(qū)動(dòng)重傳。

快速重傳機(jī)制,是如何工作的呢?其實(shí)很簡(jiǎn)單,一圖勝千言。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
快速重傳機(jī)制

在上圖,發(fā)送方發(fā)出了 1,2,3,4,5 份數(shù)據(jù):

  • 第一份 Seq1 先送到了,于是就 Ack 回 2;

  • 結(jié)果 Seq2 因?yàn)槟承┰驔]收到,Seq3 到達(dá)了,于是還是 Ack 回 2;

  • 后面的 Seq4 和 Seq5 都到了,但還是 Ack 回 2,因?yàn)?Seq2 還是沒有收到;

  • 發(fā)送端收到了三個(gè) Ack = 2 的確認(rèn),知道了 Seq2 還沒有收到,就會(huì)在定時(shí)器過(guò)期之前,重傳丟失的 Seq2。

  • 最后,接收到收到了 Seq2,此時(shí)因?yàn)?Seq3,Seq4,Seq5 都收到了,于是 Ack 回 6 。

所以,快速重傳的工作方式是當(dāng)收到三個(gè)相同的 ACK 報(bào)文時(shí),會(huì)在定時(shí)器過(guò)期之前,重傳丟失的報(bào)文段。

快速重傳機(jī)制只解決了一個(gè)問(wèn)題,就是超時(shí)時(shí)間的問(wèn)題,但是它依然面臨著另外一個(gè)問(wèn)題。就是重傳的時(shí)候,是重傳之前的一個(gè),還是重傳所有的問(wèn)題。

比如對(duì)于上面的例子,是重傳 Seq2 呢?還是重傳 Seq2、Seq3、Seq4、Seq5 呢?因?yàn)榘l(fā)送端并不清楚這連續(xù)的三個(gè) Ack 2 是誰(shuí)傳回來(lái)的。

根據(jù) TCP 不同的實(shí)現(xiàn),以上兩種情況都是有可能的??梢?,這是一把雙刃劍。

為了解決不知道該重傳哪些 TCP 報(bào)文,于是就有 SACK 方法。

SACK 方法

還有一種實(shí)現(xiàn)重傳機(jī)制的方式叫:SACK( Selective Acknowledgment 選擇性確認(rèn))。

這種方式需要在 TCP 頭部「選項(xiàng)」字段里加一個(gè) SACK 的東西,它可以將緩存的地圖發(fā)送給發(fā)送方,這樣發(fā)送方就可以知道哪些數(shù)據(jù)收到了,哪些數(shù)據(jù)沒收到,知道了這些信息,就可以只重傳丟失的數(shù)據(jù)。

如下圖,發(fā)送方收到了三次同樣的 ACK 確認(rèn)報(bào)文,于是就會(huì)觸發(fā)快速重發(fā)機(jī)制,通過(guò) SACK 信息發(fā)現(xiàn)只有 200~299 這段數(shù)據(jù)丟失,則重發(fā)時(shí),就只選擇了這個(gè) TCP 段進(jìn)行重復(fù)。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
選擇性確認(rèn)

如果要支持 SACK,必須雙方都要支持。在 Linux 下,可以通過(guò) net.ipv4.tcp_sack 參數(shù)打開這個(gè)功能(Linux 2.4 后默認(rèn)打開)。

Duplicate SACK

Duplicate SACK 又稱 D-SACK,其主要使用了 SACK 來(lái)告訴「發(fā)送方」有哪些數(shù)據(jù)被重復(fù)接收了。

下面舉例兩個(gè)栗子,來(lái)說(shuō)明 D-SACK 的作用。

栗子一號(hào):ACK 丟包

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
ACK 丟包

  • 「接收方」發(fā)給「發(fā)送方」的兩個(gè) ACK 確認(rèn)應(yīng)答都丟失了,所以發(fā)送方超時(shí)后,重傳第一個(gè)數(shù)據(jù)包(3000 ~ 3499)

  • 于是「接收方」發(fā)現(xiàn)數(shù)據(jù)是重復(fù)收到的,于是回了一個(gè) SACK = 3000~3500,告訴「發(fā)送方」 3000~3500 的數(shù)據(jù)早已被接收了,因?yàn)?ACK 都到了 4000 了,已經(jīng)意味著 4000 之前的所有數(shù)據(jù)都已收到,所以這個(gè) SACK 就代表著 D-SACK

  • 這樣「發(fā)送方」就知道了,數(shù)據(jù)沒有丟,是「接收方」的 ACK 確認(rèn)報(bào)文丟了。

栗子二號(hào):網(wǎng)絡(luò)延時(shí)

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
網(wǎng)絡(luò)延時(shí)

  • 數(shù)據(jù)包(1000~1499) 被網(wǎng)絡(luò)延遲了,導(dǎo)致「發(fā)送方」沒有收到 Ack 1500 的確認(rèn)報(bào)文。

  • 而后面報(bào)文到達(dá)的三個(gè)相同的 ACK 確認(rèn)報(bào)文,就觸發(fā)了快速重傳機(jī)制,但是在重傳后,被延遲的數(shù)據(jù)包(1000~1499)又到了「接收方」;

  • 所以「接收方」回了一個(gè) SACK=1000~1500,因?yàn)?ACK 已經(jīng)到了 3000,所以這個(gè) SACK 是 D-SACK,表示收到了重復(fù)的包。

  • 這樣發(fā)送方就知道快速重傳觸發(fā)的原因不是發(fā)出去的包丟了,也不是因?yàn)榛貞?yīng)的 ACK 包丟了,而是因?yàn)榫W(wǎng)絡(luò)延遲了。

可見,D-SACK 有這么幾個(gè)好處:

  1. 可以讓「發(fā)送方」知道,是發(fā)出去的包丟了,還是接收方回應(yīng)的 ACK 包丟了;

  2. 可以知道是不是「發(fā)送方」的數(shù)據(jù)包被網(wǎng)絡(luò)延遲了;

  3. 可以知道網(wǎng)絡(luò)中是不是把「發(fā)送方」的數(shù)據(jù)包給復(fù)制了;

在 Linux 下可以通過(guò) net.ipv4.tcp_dsack 參數(shù)開啟/關(guān)閉這個(gè)功能(Linux 2.4 后默認(rèn)打開)。


滑動(dòng)窗口

引入窗口概念的原因

我們都知道 TCP 是每發(fā)送一個(gè)數(shù)據(jù),都要進(jìn)行一次確認(rèn)應(yīng)答。當(dāng)上一個(gè)數(shù)據(jù)包收到了應(yīng)答了, 再發(fā)送下一個(gè)。

這個(gè)模式就有點(diǎn)像我和你面對(duì)面聊天,你一句我一句。但這種方式的缺點(diǎn)是效率比較低的。

如果你說(shuō)完一句話,我在處理其他事情,沒有及時(shí)回復(fù)你,那你不是要干等著我做完其他事情后,我回復(fù)你,你才能說(shuō)下一句話,很顯然這不現(xiàn)實(shí)。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
按數(shù)據(jù)包進(jìn)行確認(rèn)應(yīng)答

所以,這樣的傳輸方式有一個(gè)缺點(diǎn):數(shù)據(jù)包的往返時(shí)間越長(zhǎng),通信的效率就越低。

為解決這個(gè)問(wèn)題,TCP 引入了窗口這個(gè)概念。即使在往返時(shí)間較長(zhǎng)的情況下,它也不會(huì)降低網(wǎng)絡(luò)通信的效率。

那么有了窗口,就可以指定窗口大小,窗口大小就是指無(wú)需等待確認(rèn)應(yīng)答,而可以繼續(xù)發(fā)送數(shù)據(jù)的最大值

窗口的實(shí)現(xiàn)實(shí)際上是操作系統(tǒng)開辟的一個(gè)緩存空間,發(fā)送方主機(jī)在等到確認(rèn)應(yīng)答返回之前,必須在緩沖區(qū)中保留已發(fā)送的數(shù)據(jù)。如果按期收到確認(rèn)應(yīng)答,此時(shí)數(shù)據(jù)就可以從緩存區(qū)清除。

假設(shè)窗口大小為 3 個(gè) TCP 段,那么發(fā)送方就可以「連續(xù)發(fā)送」 3 個(gè) TCP 段,并且中途若有 ACK 丟失,可以通過(guò)「下一個(gè)確認(rèn)應(yīng)答進(jìn)行確認(rèn)」。如下圖:

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
用滑動(dòng)窗口方式并行處理

圖中的 ACK 600 確認(rèn)應(yīng)答報(bào)文丟失,也沒關(guān)系,因?yàn)榭梢酝ㄔ捪乱粋€(gè)確認(rèn)應(yīng)答進(jìn)行確認(rèn),只要發(fā)送方收到了 ACK 700 確認(rèn)應(yīng)答,就意味著 700 之前的所有數(shù)據(jù)「接收方」都收到了。這個(gè)模式就叫累計(jì)確認(rèn)或者累計(jì)應(yīng)答。

窗口大小由哪一方?jīng)Q定?

TCP 頭里有一個(gè)字段叫 Window,也就是窗口大小。

這個(gè)字段是接收端告訴發(fā)送端自己還有多少緩沖區(qū)可以接收數(shù)據(jù)。于是發(fā)送端就可以根據(jù)這個(gè)接收端的處理能力來(lái)發(fā)送數(shù)據(jù),而不會(huì)導(dǎo)致接收端處理不過(guò)來(lái)。

所以,通常窗口的大小是由接收方的決定的。

發(fā)送方發(fā)送的數(shù)據(jù)大小不能超過(guò)接收方的窗口大小,否則接收方就無(wú)法正常接收到數(shù)據(jù)。

發(fā)送方的滑動(dòng)窗口

我們先來(lái)看看發(fā)送方的窗口,下圖就是發(fā)送方緩存的數(shù)據(jù),根據(jù)處理的情況分成四個(gè)部分,其中深藍(lán)色方框是發(fā)送窗口,紫色方框是可用窗口:

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

  • #1 是已發(fā)送并收到 ACK確認(rèn)的數(shù)據(jù):1~31 字節(jié)

  • #2 是已發(fā)送但未收到 ACK確認(rèn)的數(shù)據(jù):32~45 字節(jié)

  • #3 是未發(fā)送但總大小在接收方處理范圍內(nèi)(接收方還有空間):46~51字節(jié)

  • #4 是未發(fā)送但總大小超過(guò)接收方處理范圍(接收方?jīng)]有空間):52字節(jié)以后

在下圖,當(dāng)發(fā)送方把數(shù)據(jù)「全部」都一下發(fā)送出去后,可用窗口的大小就為 0 了,表明可用窗口耗盡,在沒收到 ACK 確認(rèn)之前是無(wú)法繼續(xù)發(fā)送數(shù)據(jù)了。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
可用窗口耗盡

在下圖,當(dāng)收到之前發(fā)送的數(shù)據(jù) 32~36 字節(jié)的 ACK 確認(rèn)應(yīng)答后,如果發(fā)送窗口的大小沒有變化,則滑動(dòng)窗口往右邊移動(dòng) 5 個(gè)字節(jié),因?yàn)橛?5 個(gè)字節(jié)的數(shù)據(jù)被應(yīng)答確認(rèn),接下來(lái) 52~56 字節(jié)又變成了可用窗口,那么后續(xù)也就可以發(fā)送 52~56 這 5 個(gè)字節(jié)的數(shù)據(jù)了。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
32 ~ 36 字節(jié)已確認(rèn)

程序是如何表示發(fā)送方的四個(gè)部分的呢?

TCP 滑動(dòng)窗口方案使用三個(gè)指針來(lái)跟蹤在四個(gè)傳輸類別中的每一個(gè)類別中的字節(jié)。其中兩個(gè)指針是絕對(duì)指針(指特定的序列號(hào)),一個(gè)是相對(duì)指針(需要做偏移)。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
SND.WND、SND.UN、SND.NXT
  • SND.WND:表示發(fā)送窗口的大?。ù笮∈怯山邮辗街付ǖ模?;

  • SND.UNA:是一個(gè)絕對(duì)指針,它指向的是已發(fā)送但未收到確認(rèn)的第一個(gè)字節(jié)的序列號(hào),也就是 #2 的第一個(gè)字節(jié)。

  • SND.NXT:也是一個(gè)絕對(duì)指針,它指向未發(fā)送但可發(fā)送范圍的第一個(gè)字節(jié)的序列號(hào),也就是 #3 的第一個(gè)字節(jié)。

  • 指向 #4 的第一個(gè)字節(jié)是個(gè)相對(duì)指針,它需要 SND.UNA 指針加上 SND.WND 大小的偏移量,就可以指向 #4 的第一個(gè)字節(jié)了。

那么可用窗口大小的計(jì)算就可以是:

可用窗口大 = SND.WND -(SND.NXT - SND.UNA)

接收方的滑動(dòng)窗口

接下來(lái)我們看看接收方的窗口,接收窗口相對(duì)簡(jiǎn)單一些,根據(jù)處理的情況劃分成三個(gè)部分:

  • #1 + #2 是已成功接收并確認(rèn)的數(shù)據(jù)(等待應(yīng)用進(jìn)程讀取);

  • #3 是未收到數(shù)據(jù)但可以接收的數(shù)據(jù);

  • #4 未收到數(shù)據(jù)并不可以接收的數(shù)據(jù);


你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
接收窗口

其中三個(gè)接收部分,使用兩個(gè)指針進(jìn)行劃分:

  • RCV.WND:表示接收窗口的大小,它會(huì)通告給發(fā)送方。

  • RCV.NXT:是一個(gè)指針,它指向期望從發(fā)送方發(fā)送來(lái)的下一個(gè)數(shù)據(jù)字節(jié)的序列號(hào),也就是 #3 的第一個(gè)字節(jié)。

  • 指向 #4 的第一個(gè)字節(jié)是個(gè)相對(duì)指針,它需要 RCV.NXT 指針加上 RCV.WND 大小的偏移量,就可以指向 #4 的第一個(gè)字節(jié)了。


接收窗口和發(fā)送窗口的大小是相等的嗎?

并不是完全相等,接收窗口的大小是約等于發(fā)送窗口的大小的。

因?yàn)榛瑒?dòng)窗口并不是一成不變的。比如,當(dāng)接收方的應(yīng)用進(jìn)程讀取數(shù)據(jù)的速度非常快的話,這樣的話接收窗口可以很快的就空缺出來(lái)。那么新的接收窗口大小,是通過(guò) TCP 報(bào)文中的 Windows 字段來(lái)告訴發(fā)送方。那么這個(gè)傳輸過(guò)程是存在時(shí)延的,所以接收窗口和發(fā)送窗口是約等于的關(guān)系。


流量控制

發(fā)送方不能無(wú)腦的發(fā)數(shù)據(jù)給接收方,要考慮接收方處理能力。

如果一直無(wú)腦的發(fā)數(shù)據(jù)給對(duì)方,但對(duì)方處理不過(guò)來(lái),那么就會(huì)導(dǎo)致觸發(fā)重發(fā)機(jī)制,從而導(dǎo)致網(wǎng)絡(luò)流量的無(wú)端的浪費(fèi)。

為了解決這種現(xiàn)象發(fā)生,TCP 提供一種機(jī)制可以讓「發(fā)送方」根據(jù)「接收方」的實(shí)際接收能力控制發(fā)送的數(shù)據(jù)量,這就是所謂的流量控制。

下面舉個(gè)栗子,為了簡(jiǎn)單起見,假設(shè)以下場(chǎng)景:

  • 客戶端是接收方,服務(wù)端是發(fā)送方

  • 假設(shè)接收窗口和發(fā)送窗口相同,都為 200

  • 假設(shè)兩個(gè)設(shè)備在整個(gè)傳輸過(guò)程中都保持相同的窗口大小,不受外界影響


你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
流量控制

根據(jù)上圖的流量控制,說(shuō)明下每個(gè)過(guò)程:

  1. 客戶端向服務(wù)端發(fā)送請(qǐng)求數(shù)據(jù)報(bào)文。這里要說(shuō)明下,本次例子是把服務(wù)端作為發(fā)送方,所以沒有畫出服務(wù)端的接收窗口。

  2. 服務(wù)端收到請(qǐng)求報(bào)文后,發(fā)送確認(rèn)報(bào)文和 80 字節(jié)的數(shù)據(jù),于是可用窗口 Usable 減少為 120 字節(jié),同時(shí) SND.NXT 指針也向右偏移 80 字節(jié)后,指向 321,這意味著下次發(fā)送數(shù)據(jù)的時(shí)候,序列號(hào)是 321。

  3. 客戶端收到 80 字節(jié)數(shù)據(jù)后,于是接收窗口往右移動(dòng) 80 字節(jié),RCV.NXT 也就指向 321,這意味著客戶端期望的下一個(gè)報(bào)文的序列號(hào)是 321,接著發(fā)送確認(rèn)報(bào)文給服務(wù)端。

  4. 服務(wù)端再次發(fā)送了 120 字節(jié)數(shù)據(jù),于是可用窗口耗盡為 0,服務(wù)端無(wú)法在繼續(xù)發(fā)送數(shù)據(jù)。

  5. 客戶端收到 120 字節(jié)的數(shù)據(jù)后,于是接收窗口往右移動(dòng) 120 字節(jié),RCV.NXT 也就指向 441,接著發(fā)送確認(rèn)報(bào)文給服務(wù)端。

  6. 服務(wù)端收到對(duì) 80 字節(jié)數(shù)據(jù)的確認(rèn)報(bào)文后,SND.UNA 指針往右偏移后指向 321,于是可用窗口 Usable 增大到 80。

  7. 服務(wù)端收到對(duì) 120 字節(jié)數(shù)據(jù)的確認(rèn)報(bào)文后,SND.UNA 指針往右偏移后指向 441,于是可用窗口 Usable 增大到 200。

  8. 服務(wù)端可以繼續(xù)發(fā)送了,于是發(fā)送了 160 字節(jié)的數(shù)據(jù)后,SND.NXT 指向 601,于是可用窗口  Usable 減少到 40。

  9. 客戶端收到 160 字節(jié)后,接收窗口往右移動(dòng)了 160 字節(jié),RCV.NXT 也就是指向了 601,接著發(fā)送確認(rèn)報(bào)文給服務(wù)端。

  10. 服務(wù)端收到對(duì) 160 字節(jié)數(shù)據(jù)的確認(rèn)報(bào)文后,發(fā)送窗口往右移動(dòng)了 160 字節(jié),于是 SND.UNA 指針偏移了 160 后指向 601,可用窗口 Usable 也就增大至了 200。

操作系統(tǒng)緩沖區(qū)與滑動(dòng)窗口的關(guān)系

前面的流量控制例子,我們假定了發(fā)送窗口和接收窗口是不變的,但是實(shí)際上,發(fā)送窗口和接收窗口中所存放的字節(jié)數(shù),都是放在操作系統(tǒng)內(nèi)存緩沖區(qū)中的,而操作系統(tǒng)的緩沖區(qū),會(huì)被操作系統(tǒng)調(diào)整

當(dāng)應(yīng)用進(jìn)程沒辦法及時(shí)讀取緩沖區(qū)的內(nèi)容時(shí),也會(huì)對(duì)我們的緩沖區(qū)造成影響。

那操心系統(tǒng)的緩沖區(qū),是如何影響發(fā)送窗口和接收窗口的呢?

我們先來(lái)看看第一個(gè)例子。

當(dāng)應(yīng)用程序沒有及時(shí)讀取緩存時(shí),發(fā)送窗口和接收窗口的變化。

考慮以下場(chǎng)景:

  • 客戶端作為發(fā)送方,服務(wù)端作為接收方,發(fā)送窗口和接收窗口初始大小為 360;

  • 服務(wù)端非常的繁忙,當(dāng)收到客戶端的數(shù)據(jù)時(shí),應(yīng)用層不能及時(shí)讀取數(shù)據(jù)。


你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

根據(jù)上圖的流量控制,說(shuō)明下每個(gè)過(guò)程:

  1. 客戶端發(fā)送 140 字節(jié)數(shù)據(jù)后,可用窗口變?yōu)?220 (360 - 140)。

  2. 服務(wù)端收到 140 字節(jié)數(shù)據(jù),但是服務(wù)端非常繁忙,應(yīng)用進(jìn)程只讀取了 40 個(gè)字節(jié),還有 100 字節(jié)占用著緩沖區(qū),于是接收窗口收縮到了 260 (360 - 100),最后發(fā)送確認(rèn)信息時(shí),將窗口大小通過(guò)給客戶端。

  3. 客戶端收到確認(rèn)和窗口通告報(bào)文后,發(fā)送窗口減少為 260。

  4. 客戶端發(fā)送 180 字節(jié)數(shù)據(jù),此時(shí)可用窗口減少到 80。

  5. 服務(wù)端收到 180 字節(jié)數(shù)據(jù),但是應(yīng)用程序沒有讀取任何數(shù)據(jù),這 180 字節(jié)直接就留在了緩沖區(qū),于是接收窗口收縮到了 80 (260 - 180),并在發(fā)送確認(rèn)信息時(shí),通過(guò)窗口大小給客戶端。

  6. 客戶端收到確認(rèn)和窗口通告報(bào)文后,發(fā)送窗口減少為 80。

  7. 客戶端發(fā)送 80 字節(jié)數(shù)據(jù)后,可用窗口耗盡。

  8. 服務(wù)端收到 80 字節(jié)數(shù)據(jù),但是應(yīng)用程序依然沒有讀取任何數(shù)據(jù),這 80 字節(jié)留在了緩沖區(qū),于是接收窗口收縮到了 0,并在發(fā)送確認(rèn)信息時(shí),通過(guò)窗口大小給客戶端。

  9. 客戶端收到確認(rèn)和窗口通告報(bào)文后,發(fā)送窗口減少為 0。

可見最后窗口都收縮為 0 了,也就是發(fā)生了窗口關(guān)閉。當(dāng)發(fā)送方可用窗口變?yōu)?0 時(shí),發(fā)送方實(shí)際上會(huì)定時(shí)發(fā)送窗口探測(cè)報(bào)文,以便知道接收方的窗口是否發(fā)生了改變,這個(gè)內(nèi)容后面會(huì)說(shuō),這里先簡(jiǎn)單提一下。

我們先來(lái)看看第二個(gè)例子。

當(dāng)服務(wù)端系統(tǒng)資源非常緊張的時(shí)候,操心系統(tǒng)可能會(huì)直接減少了接收緩沖區(qū)大小,這時(shí)應(yīng)用程序又無(wú)法及時(shí)讀取緩存數(shù)據(jù),那么這時(shí)候就有嚴(yán)重的事情發(fā)生了,會(huì)出現(xiàn)數(shù)據(jù)包丟失的現(xiàn)象。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

說(shuō)明下每個(gè)過(guò)程:

  1. 客戶端發(fā)送 140 字節(jié)的數(shù)據(jù),于是可用窗口減少到了 220。

  2. 服務(wù)端因?yàn)楝F(xiàn)在非常的繁忙,操作系統(tǒng)于是就把接收緩存減少了 100 字節(jié),當(dāng)收到 對(duì) 140 數(shù)據(jù)確認(rèn)報(bào)文后,又因?yàn)閼?yīng)用程序沒有讀取任何數(shù)據(jù),所以 140 字節(jié)留在了緩沖區(qū)中,于是接收窗口大小從 360 收縮成了 100,最后發(fā)送確認(rèn)信息時(shí),通告窗口大小給對(duì)方。

  3. 此時(shí)客戶端因?yàn)檫€沒有收到服務(wù)端的通告窗口報(bào)文,所以不知道此時(shí)接收窗口收縮成了 100,客戶端只會(huì)看自己的可用窗口還有 220,所以客戶端就發(fā)送了 180 字節(jié)數(shù)據(jù),于是可用窗口減少到 40。

  4. 服務(wù)端收到了 180 字節(jié)數(shù)據(jù)時(shí),發(fā)現(xiàn)數(shù)據(jù)大小超過(guò)了接收窗口的大小,于是就把數(shù)據(jù)包丟失了。

  5. 客戶端收到第 2 步時(shí),服務(wù)端發(fā)送的確認(rèn)報(bào)文和通告窗口報(bào)文,嘗試減少發(fā)送窗口到 100,把窗口的右端向左收縮了 80,此時(shí)可用窗口的大小就會(huì)出現(xiàn)詭異的負(fù)值。

所以,如果發(fā)生了先減少緩存,再收縮窗口,就會(huì)出現(xiàn)丟包的現(xiàn)象。

為了防止這種情況發(fā)生,TCP 規(guī)定是不允許同時(shí)減少緩存又收縮窗口的,而是采用先收縮窗口,過(guò)段時(shí)間在減少緩存,這樣就可以避免了丟包情況。

窗口關(guān)閉

在前面我們都看到了,TCP 通過(guò)讓接收方指明希望從發(fā)送方接收的數(shù)據(jù)大?。ù翱诖笮。﹣?lái)進(jìn)行流量控制。

如果窗口大小為 0 時(shí),就會(huì)阻止發(fā)送方給接收方傳遞數(shù)據(jù),直到窗口變?yōu)榉?0 為止,這就是窗口關(guān)閉。

窗口關(guān)閉潛在的危險(xiǎn)

接收方向發(fā)送方通告窗口大小時(shí),是通過(guò) ACK 報(bào)文來(lái)通告的。

那么,當(dāng)發(fā)生窗口關(guān)閉時(shí),接收方處理完數(shù)據(jù)后,會(huì)向發(fā)送方通告一個(gè)窗口非 0 的 ACK 報(bào)文,如果這個(gè)通告窗口的 ACK 報(bào)文在網(wǎng)絡(luò)中丟失了,那麻煩就大了。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
窗口關(guān)閉潛在的危險(xiǎn)

這會(huì)導(dǎo)致發(fā)送方一直等待接收方的非 0 窗口通知,接收方也一直等待發(fā)送方的數(shù)據(jù),如不不采取措施,這種相互等待的過(guò)程,會(huì)造成了死鎖的現(xiàn)象。

TCP 是如何解決窗口關(guān)閉時(shí),潛在的死鎖現(xiàn)象呢?

為了解決這個(gè)問(wèn)題,TCP 為每個(gè)連接設(shè)有一個(gè)持續(xù)定時(shí)器,只要 TCP 連接一方收到對(duì)方的零窗口通知,就啟動(dòng)持續(xù)計(jì)時(shí)器。

如果持續(xù)計(jì)時(shí)器超時(shí),就會(huì)發(fā)送窗口探測(cè) ( Window probe ) 報(bào)文,而對(duì)方在確認(rèn)這個(gè)探測(cè)報(bào)文時(shí),給出自己現(xiàn)在的接收窗口大小。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
窗口探測(cè)

  • 如果接收窗口仍然為 0,那么收到這個(gè)報(bào)文的一方就會(huì)重新啟動(dòng)持續(xù)計(jì)時(shí)器;

  • 如果接收窗口不是 0,那么死鎖的局面就可以被打破了。

窗口探查探測(cè)的次數(shù)一般為 3 此次,每次次大約 30-60 秒(不同的實(shí)現(xiàn)可能會(huì)不一樣)。如果 3 次過(guò)后接收窗口還是 0 的話,有的 TCP 實(shí)現(xiàn)就會(huì)發(fā) RST 報(bào)文來(lái)中斷連接。

糊涂窗口綜合癥

如果接收方太忙了,來(lái)不及取走接收窗口里的數(shù)據(jù),那么就會(huì)導(dǎo)致發(fā)送方的發(fā)送窗口越來(lái)越小。

到最后,如果接收方騰出幾個(gè)字節(jié)并告訴發(fā)送方現(xiàn)在有幾個(gè)字節(jié)的窗口,而發(fā)送方會(huì)義無(wú)反顧地發(fā)送這幾個(gè)字節(jié),這就是糊涂窗口綜合癥。

要知道,我們的 TCP + IP 頭有 40 個(gè)字節(jié),為了傳輸那幾個(gè)字節(jié)的數(shù)據(jù),要達(dá)上這么大的開銷,這太不經(jīng)濟(jì)了。

就好像一個(gè)可以承載 50 人的大巴車,每次來(lái)了一兩個(gè)人,就直接發(fā)車。除非家里有礦的大巴司機(jī),才敢這樣玩,不然遲早破產(chǎn)。要解決這個(gè)問(wèn)題也不難,大巴司機(jī)等乘客數(shù)量超過(guò)了 25 個(gè),才認(rèn)定可以發(fā)車。

現(xiàn)舉個(gè)糊涂窗口綜合癥的栗子,考慮以下場(chǎng)景:

接收方的窗口大小是 360 字節(jié),但接收方由于某些原因陷入困境,假設(shè)接收方的應(yīng)用層讀取的能力如下:

  • 接收方每接收 3 個(gè)字節(jié),應(yīng)用程序就只能從緩沖區(qū)中讀取 1 個(gè)字節(jié)的數(shù)據(jù);

  • 在下一個(gè)發(fā)送方的 TCP 段到達(dá)之前,應(yīng)用程序
    還從緩沖區(qū)中讀取了 40 個(gè)額外的字節(jié);


你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
糊涂窗口綜合癥

每個(gè)過(guò)程的窗口大小的變化,在圖中都描述的很清楚了,可以發(fā)現(xiàn)窗口不斷減少了,并且發(fā)送的數(shù)據(jù)都是比較小的了。

所以,糊涂窗口綜合癥的現(xiàn)象是可以發(fā)生在發(fā)送方和接收方:

  • 接收方可以通告一個(gè)小的窗口

  • 而發(fā)送方可以發(fā)送小數(shù)據(jù)

于是,要解決糊涂窗口綜合癥,就解決上面兩個(gè)問(wèn)題就可以了

  • 讓接收方不通告小窗口給發(fā)送方

  • 讓發(fā)送方避免發(fā)送小數(shù)據(jù)


怎么讓接收方不通告小窗口呢?

接收方通常的策略如下:

當(dāng)「窗口大小」小于 min( MSS,緩存空間/2 ) ,也就是小于 MSS 與 1/2 緩存大小中的最小值時(shí),就會(huì)向發(fā)送方通告窗口為 0,也就阻止了發(fā)送方再發(fā)數(shù)據(jù)過(guò)來(lái)。

等到接收方處理了一些數(shù)據(jù)后,窗口大小 >= MSS,或者接收方緩存空間有一半可以使用,就可以把窗口打開讓發(fā)送方發(fā)送數(shù)據(jù)過(guò)來(lái)。

怎么讓發(fā)送方避免發(fā)送小數(shù)據(jù)呢?

發(fā)送方通常的策略:

使用 Nagle 算法,該算法的思路是延時(shí)處理,它滿足以下兩個(gè)條件中的一條才可以發(fā)送數(shù)據(jù):

  • 要等到窗口大小 >= MSS 或是 數(shù)據(jù)大小 >= MSS

  • 收到之前發(fā)送數(shù)據(jù)的 ack 回包

只要沒滿足上面條件中的一條,發(fā)送方一直在囤積數(shù)據(jù),直到滿足上面的發(fā)送條件。

另外,Nagle 算法默認(rèn)是打開的,如果對(duì)于一些需要小數(shù)據(jù)包交互的場(chǎng)景的程序,比如,telnet 或 ssh 這樣的交互性比較強(qiáng)的程序,則需要關(guān)閉 Nagle 算法。

可以在 Socket 設(shè)置 TCP_NODELAY 選項(xiàng)來(lái)關(guān)閉這個(gè)算法(關(guān)閉 Nagle 算法沒有全局參數(shù),需要根據(jù)每個(gè)應(yīng)用自己的特點(diǎn)來(lái)關(guān)閉)

setsockopt(sock_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int));

擁塞控制

為什么要有擁塞控制呀,不是有流量控制了嗎?

前面的流量控制是避免「發(fā)送方」的數(shù)據(jù)填滿「接收方」的緩存,但是并不知道網(wǎng)絡(luò)的中發(fā)生了什么。

一般來(lái)說(shuō),計(jì)算機(jī)網(wǎng)絡(luò)都處在一個(gè)共享的環(huán)境。因此也有可能會(huì)因?yàn)槠渌鳈C(jī)之間的通信使得網(wǎng)絡(luò)擁堵。

在網(wǎng)絡(luò)出現(xiàn)擁堵時(shí),如果繼續(xù)發(fā)送大量數(shù)據(jù)包,可能會(huì)導(dǎo)致數(shù)據(jù)包時(shí)延、丟失等,這時(shí) TCP 就會(huì)重傳數(shù)據(jù),但是一重傳就會(huì)導(dǎo)致網(wǎng)絡(luò)的負(fù)擔(dān)更重,于是會(huì)導(dǎo)致更大的延遲以及更多的丟包,這個(gè)情況就會(huì)進(jìn)入惡性循環(huán)被不斷地放大….

所以,TCP 不能忽略網(wǎng)絡(luò)上發(fā)生的事,它被設(shè)計(jì)成一個(gè)無(wú)私的協(xié)議,當(dāng)網(wǎng)絡(luò)發(fā)送擁塞時(shí),TCP 會(huì)自我犧牲,降低發(fā)送的數(shù)據(jù)量。

于是,就有了擁塞控制,控制的目的就是避免「發(fā)送方」的數(shù)據(jù)填滿整個(gè)網(wǎng)絡(luò)。

為了在「發(fā)送方」調(diào)節(jié)所要發(fā)送數(shù)據(jù)的量,定義了一個(gè)叫做「擁塞窗口」的概念。

什么是擁塞窗口?和發(fā)送窗口有什么關(guān)系呢?

擁塞窗口 cwnd是發(fā)送方維護(hù)的一個(gè) 的狀態(tài)變量,它會(huì)根據(jù)網(wǎng)絡(luò)的擁塞程度動(dòng)態(tài)變化的。

我們?cè)谇懊嫣岬竭^(guò)發(fā)送窗口 swnd 和接收窗口 rwnd 是約等于的關(guān)系,那么由于入了擁塞窗口的概念后,此時(shí)發(fā)送窗口的值是swnd = min(cwnd, rwnd),也就是擁塞窗口和接收窗口中的最小值。

擁塞窗口 cwnd 變化的規(guī)則:

  • 只要網(wǎng)絡(luò)中沒有出現(xiàn)擁塞,cwnd 就會(huì)增大;

  • 但網(wǎng)絡(luò)中出現(xiàn)了擁塞,cwnd 就減少;


那么怎么知道當(dāng)前網(wǎng)絡(luò)是否出現(xiàn)了擁塞呢?

其實(shí)只要「發(fā)送方」沒有在規(guī)定時(shí)間內(nèi)接收到 ACK 應(yīng)答報(bào)文,也就是發(fā)生了超時(shí)重傳,就會(huì)認(rèn)為網(wǎng)絡(luò)出現(xiàn)了用擁塞。

擁塞控制有哪些控制算法?

擁塞控制主要是四個(gè)算法:

  • 慢啟動(dòng)

  • 擁塞避免

  • 擁塞發(fā)生

  • 快速恢復(fù)

慢啟動(dòng)

TCP 在剛建立連接完成后,首先是有個(gè)慢啟動(dòng)的過(guò)程,這個(gè)慢啟動(dòng)的意思就是一點(diǎn)一點(diǎn)的提高發(fā)送數(shù)據(jù)包的數(shù)量,如果一上來(lái)就發(fā)大量的數(shù)據(jù),這不是給網(wǎng)絡(luò)添堵嗎?

慢啟動(dòng)的算法記住一個(gè)規(guī)則就行:當(dāng)發(fā)送方每收到一個(gè) ACK,就擁塞窗口 cwnd 的大小就會(huì)加 1。

這里假定擁塞窗口 cwnd 和發(fā)送窗口 swnd 相等,下面舉個(gè)栗子:

  • 連接建立完成后,一開始初始化 cwnd = 1,表示可以傳一個(gè) MSS 大小的數(shù)據(jù)。

  • 當(dāng)收到一個(gè) ACK 確認(rèn)應(yīng)答后,cwnd 增加 1,于是一次能夠發(fā)送 2 個(gè)

  • 當(dāng)收到 2 個(gè)的 ACK 確認(rèn)應(yīng)答后, cwnd 增加 2,于是就可以比之前多發(fā)2 個(gè),所以這一次能夠發(fā)送 4 個(gè)

  • 當(dāng)這 4 個(gè)的 ACK 確認(rèn)到來(lái)的時(shí)候,每個(gè)確認(rèn) cwnd 增加 1, 4 個(gè)確認(rèn) cwnd 增加 4,于是就可以比之前多發(fā) 4 個(gè),所以這一次能夠發(fā)送 8 個(gè)。


你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
慢啟動(dòng)算法

可以看出慢啟動(dòng)算法,發(fā)包的個(gè)數(shù)是指數(shù)性的增長(zhǎng)。

那慢啟動(dòng)漲到什么時(shí)候是個(gè)頭呢?

有一個(gè)叫慢啟動(dòng)門限  ssthresh (slow start threshold)狀態(tài)變量。

  • 當(dāng) cwnd < ssthresh 時(shí),使用慢啟動(dòng)算法。

  • 當(dāng) cwnd >= ssthresh 時(shí),就會(huì)使用「擁塞避免算法」。

擁塞避免算法

前面說(shuō)道,當(dāng)擁塞窗口 cwnd 「超過(guò)」慢啟動(dòng)門限 ssthresh 就會(huì)進(jìn)入擁塞避免算法。

一般來(lái)說(shuō) ssthresh 的大小是 65535 字節(jié)。

那么進(jìn)入擁塞避免算法后,它的規(guī)則是:每當(dāng)收到一個(gè) ACK 時(shí),cwnd 增加 1/cwnd。

接上前面的慢啟動(dòng)的栗子,現(xiàn)假定 ssthresh8

  • 當(dāng) 8 個(gè) ACK 應(yīng)答確認(rèn)到來(lái)時(shí),每個(gè)確認(rèn)增加 1/8,8 個(gè) ACK 確認(rèn) cwnd 一共增加 1,于是這一次能夠發(fā)送 9 個(gè) MSS 大小的數(shù)據(jù),變成了線性增長(zhǎng)。

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
擁塞避免

所以,我們可以發(fā)現(xiàn),擁塞避免算法就是將原本慢啟動(dòng)算法的指數(shù)增長(zhǎng)變成了線性增長(zhǎng),還是增長(zhǎng)階段,但是增長(zhǎng)速度緩慢了一些。

就這么一直增長(zhǎng)著后,網(wǎng)絡(luò)就會(huì)慢慢進(jìn)入了擁塞的狀況了,于是就會(huì)出現(xiàn)丟包現(xiàn)象,這時(shí)就需要對(duì)丟失的數(shù)據(jù)包進(jìn)行重傳。

當(dāng)觸發(fā)了重傳機(jī)制,也就進(jìn)入了「擁塞發(fā)生算法」。

擁塞發(fā)生

當(dāng)網(wǎng)絡(luò)出現(xiàn)擁塞,也就是會(huì)發(fā)生數(shù)據(jù)包重傳,重傳機(jī)制主要有兩種:

  • 超時(shí)重傳

  • 快速重傳

這兩種使用的擁塞發(fā)送算法是不同的,接下來(lái)分別來(lái)說(shuō)說(shuō)。

發(fā)生超時(shí)重傳的擁塞發(fā)生算法

當(dāng)發(fā)生了「超時(shí)重傳」,則就會(huì)使用擁塞發(fā)生算法。

這個(gè)時(shí)候,sshresh 和 cwnd 的值會(huì)發(fā)生變化:

  • ssthresh 設(shè)為 cwnd/2,

  • cwnd 重置為 1

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
擁塞發(fā)送 —— 超時(shí)重傳

接著,就重新開始慢啟動(dòng),慢啟動(dòng)是會(huì)突然減少數(shù)據(jù)流的。這真是一旦「超時(shí)重傳」,馬上回到解放前。但是這種方式太激進(jìn)了,反應(yīng)也很強(qiáng)烈,會(huì)造成網(wǎng)絡(luò)卡頓。

就好像本來(lái)在秋名山高速漂移著,突然來(lái)個(gè)緊急剎車,輪胎受得了嗎。。。

發(fā)生快速重傳的擁塞發(fā)生算法

還有更好的方式,前面我們講過(guò)「快速重傳算法」。當(dāng)接收方發(fā)現(xiàn)丟了一個(gè)中間包的時(shí)候,發(fā)送三次前一個(gè)包的 ACK,于是發(fā)送端就會(huì)快速地重傳,不必等待超時(shí)再重傳。

TCP 認(rèn)為這種情況不嚴(yán)重,因?yàn)榇蟛糠譀]丟,只丟了一小部分,則 ssthreshcwnd 變化如下:

  • cwnd = cwnd/2 ,也就是設(shè)置為原來(lái)的一半;

  • ssthresh = cwnd;

  • 進(jìn)入快速恢復(fù)算法

快速恢復(fù)

快速重傳和快速恢復(fù)算法一般同時(shí)使用,快速恢復(fù)算法是認(rèn)為,你還能收到 3 個(gè)重復(fù) ACK 說(shuō)明網(wǎng)絡(luò)也不那么糟糕,所以沒有必要像 RTO 超時(shí)那么強(qiáng)烈。

正如前面所說(shuō),進(jìn)入快速恢復(fù)之前,cwndssthresh 已被更新了:

  • cwnd = cwnd/2 ,也就是設(shè)置為原來(lái)的一半;

  • ssthresh = cwnd;

然后,進(jìn)入快速恢復(fù)算法如下:

  • 擁塞窗口 cwnd = ssthresh + 3 ( 3 的意思是確認(rèn)有 3 個(gè)數(shù)據(jù)包被收到了)

  • 重傳丟失的數(shù)據(jù)包

  • 如果再收到重復(fù)的 ACK,那么 cwnd 增加 1

  • 如果收到新數(shù)據(jù)的 ACK 后,設(shè)置 cwnd 為 ssthresh,接著就進(jìn)入了擁塞避免算法



你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了
快速重傳和快速恢復(fù)

也就是沒有像「超時(shí)重傳」一夜回到解放前,而是還在比較高的值,后續(xù)呈線性增長(zhǎng)。


巨人的肩膀

[1] 趣談網(wǎng)絡(luò)協(xié)議專欄.劉超.極客時(shí)間

[2] Web協(xié)議詳解與抓包實(shí)戰(zhàn)專欄.陶輝.極客時(shí)間

[3] TCP/IP詳解 卷1:協(xié)議.范建華 譯.機(jī)械工業(yè)出版社

[4] 圖解TCP/IP.竹下隆史.人民郵電出版社

[5] The TCP/IP Guide.Charles M. Kozierok.

[6] TCP那些事(上).陳皓.酷殼博客.
https://coolshell.cn/articles/11564.html

[7] TCP那些事(下).陳皓.酷殼博客.https://coolshell.cn/articles/11609.html

特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長(zhǎng)按關(guān)注一下:

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

長(zhǎng)按訂閱更多精彩▼

你還在為 TCP 重傳、滑動(dòng)窗口、流量控制、擁塞控制發(fā)愁嗎?看完圖解就不愁了

如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉