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

當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]TCP握手一定是三次?TCP 揮手一定是四次?為什么要有快速重傳,超時(shí)重傳不夠用?為什么要有 SACK,為什么要有 D-SACK?Silly Window 又是什么?為什么有滑動(dòng)窗口流控還需要擁塞控制?快速重傳一定要依賴(lài)三次重復(fù) ACK ?

每個(gè)時(shí)代,都不會(huì)虧待會(huì)學(xué)習(xí)的人。

在進(jìn)入今天主題之前我先拋幾個(gè)問(wèn)題,這篇文章一共提出 23 個(gè)問(wèn)題。

TCP 握手一定是三次?TCP 揮手一定是四次?

為什么要有快速重傳,超時(shí)重傳不夠用?為什么要有 SACK,為什么要有 D-SACK?

都知道有滑動(dòng)窗口,那由于接收方的太忙了滑動(dòng)窗口降為了 0 怎么辦?發(fā)送方就永遠(yuǎn)等著了?

Silly Window 又是什么?

為什么有滑動(dòng)窗口流控還需要擁塞控制?

快速重傳一定要依賴(lài)三次重復(fù) ACK ?

這篇文章我想由淺到深地過(guò)一遍 TCP,不是生硬的搬出各個(gè)知識(shí)點(diǎn),從問(wèn)題入手,然后從發(fā)展、演進(jìn)的角度來(lái)看 TCP。

起初我在學(xué)計(jì)算機(jī)網(wǎng)絡(luò)的時(shí)候就有非常非常多的疑問(wèn),腦子里簡(jiǎn)直充滿(mǎn)了十萬(wàn)個(gè)為什么,而網(wǎng)絡(luò)又非常的復(fù)雜,發(fā)展了這么多年?yáng)|西真的太多了,今天我就大致的淺顯地說(shuō)一說(shuō)我對(duì) TCP 這些要點(diǎn)的理解

好了,廢話(huà)不多說(shuō),開(kāi)始上正菜。

TCP 是用來(lái)解決什么問(wèn)題?

TCP 即 Transmission Control Protocol,可以看到是一個(gè)傳輸控制協(xié)議,重點(diǎn)就在這個(gè)控制

控制什么?

控制可靠、按序地傳輸以及端與端之間的流量控制。夠了么?還不夠,它需要更加智能,因此還需要加個(gè)擁塞控制,需要為整體網(wǎng)絡(luò)的情況考慮。

這就是出行你我他,安全靠大家。

為什么要 TCP,IP 層實(shí)現(xiàn)控制不行么?

我們知道網(wǎng)絡(luò)是分層實(shí)現(xiàn)的,網(wǎng)絡(luò)協(xié)議的設(shè)計(jì)就是為了通信,從鏈路層到 IP 層其實(shí)就已經(jīng)可以完成通信了。

你看鏈路層不可或缺畢竟咱們電腦都是通過(guò)鏈路相互連接的,然后 IP 充當(dāng)了地址的功能,所以通過(guò) IP 咱們找到了對(duì)方就可以進(jìn)行通信了。

那加個(gè) TCP 層干啥?IP 層實(shí)現(xiàn)控制不就完事了嘛?

之所以要提取出一個(gè) TCP 層來(lái)實(shí)現(xiàn)控制是因?yàn)?IP 層涉及到的設(shè)備更多,一條數(shù)據(jù)在網(wǎng)絡(luò)上傳輸需要經(jīng)過(guò)很多設(shè)備,而設(shè)備之間需要靠 IP 來(lái)尋址。

假設(shè) IP 層實(shí)現(xiàn)了控制,那是不是涉及到的設(shè)備都需要關(guān)心很多事情?整體傳輸?shù)男适遣皇谴蟠蛘劭哿耍?

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

我舉個(gè)例子,假如 A 要傳輸給 F 一個(gè)積木,但是無(wú)法直接傳輸?shù)?,需要?jīng)過(guò) B、C、D、E 這幾個(gè)中轉(zhuǎn)站之手。這里有兩種情況:

  • 假設(shè) BCDE 都需要關(guān)心這個(gè)積木搭錯(cuò)了沒(méi),都拆開(kāi)包裹仔細(xì)的看看,沒(méi)問(wèn)題了再裝回去,最終到了 F 的手中。
  • 假設(shè) BCDE 都不關(guān)心積木的情況,來(lái)啥包裹只管轉(zhuǎn)發(fā)就完事了,由最終的 F 自己來(lái)檢查這個(gè)積木答錯(cuò)了沒(méi)。

你覺(jué)得哪種效率高?明顯是第二種,轉(zhuǎn)發(fā)的設(shè)備不需要關(guān)心這些事,只管轉(zhuǎn)發(fā)就完事!

所以把控制的邏輯獨(dú)立出來(lái)成 TCP 層,讓真正的接收端來(lái)處理,這樣網(wǎng)絡(luò)整體的傳輸效率就高了。

連接到底是什么?

我們已經(jīng)知道了為什么需要獨(dú)立出 TCP 這一層,并且這一層主要是用來(lái)干嘛的,接下來(lái)就來(lái)看看它到底是怎么干的。

我們都知道 TCP 是面向連接的,那這個(gè)連接到底是個(gè)什么東西?真的是拉了一條線(xiàn)讓端與端之間連起來(lái)了?

所謂的連接其實(shí)只是雙方都維護(hù)了一個(gè)狀態(tài),通過(guò)每一次通信來(lái)維護(hù)狀態(tài)的變更,使得看起來(lái)好像有一條線(xiàn)關(guān)聯(lián)了對(duì)方。

TCP 協(xié)議頭

在具體深入之前我們需要先來(lái)看看一些 TCP 頭的格式,這很基礎(chǔ)也很重要。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

我就不一一解釋了,挑重點(diǎn)的說(shuō)。

首先可以看到 TCP 包只有端口,沒(méi)有 IP。

Seq 就是 Sequence Number 即序號(hào),它是用來(lái)解決亂序問(wèn)題的。

ACK 就是 Acknowledgement Numer 即確認(rèn)號(hào),它是用來(lái)解決丟包情況的,告訴發(fā)送方這個(gè)包我收到啦。

標(biāo)志位就是 TCP flags 用來(lái)標(biāo)記這個(gè)包是什么類(lèi)型的,用來(lái)控制 TPC 的狀態(tài)。

窗口就是滑動(dòng)窗口,Sliding Window,用來(lái)流控。

三次握手

明確了協(xié)議頭的要點(diǎn)之后,我們?cè)賮?lái)看三次握手。

三次握手真是個(gè)老生常談的問(wèn)題了,但是真的懂了么?不是浮在表面?能不能延伸出一些點(diǎn)別的?

我們先來(lái)看一下熟悉的流程。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

首先為什么要握手,其實(shí)主要就是為了初始化Seq Numer,SYN 的全稱(chēng)是 Synchronize Sequence Numbers,這個(gè)序號(hào)是用來(lái)保證之后傳輸數(shù)據(jù)的順序性。

你要說(shuō)是為了測(cè)試保證雙方發(fā)送接收功能都正常,我覺(jué)得也沒(méi)毛病,不過(guò)我認(rèn)為重點(diǎn)在于同步序號(hào)。

那為什么要三次,就拿我和你這兩個(gè)角色來(lái)說(shuō),首先我告訴你我的初始化序號(hào),你聽(tīng)到了和我說(shuō)你收到了。

然后你告訴我你的初始序號(hào),然后我對(duì)你說(shuō)我收到了。

這好像四次了?如果真的按一來(lái)一回就是四次,但是中間一步可以合在一起,就是你和我說(shuō)你知道了我的初始序號(hào)的時(shí)候同時(shí)將你的初始序號(hào)告訴我。

因此四次握手就可以減到三次了。

不過(guò)你沒(méi)有想過(guò)這么一種情形,我和你同時(shí)開(kāi)口,一起告訴對(duì)方各自的初始序號(hào),然后分別回應(yīng)收到了,這不就是四次握手了?

我來(lái)畫(huà)個(gè)圖,清晰一點(diǎn)。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

看看是不是四次握手了? 不過(guò)具體還是得看實(shí)現(xiàn),有些實(shí)現(xiàn)可能不允許這種情況出現(xiàn),但是這不影響我們思考,因?yàn)?span style="color: rgb(60, 112, 198);">握手的重點(diǎn)就是同步初始序列號(hào),這種情況也完成了同步的目標(biāo)。

初始序列號(hào) ISN 的取值

不知道大家有沒(méi)有想過(guò) ISN 的值要設(shè)成什么?代碼寫(xiě)死從零開(kāi)始?

想象一下如果寫(xiě)死一個(gè)值,比如 0 ,那么假設(shè)已經(jīng)建立好連接了,client 也發(fā)了很多包比如已經(jīng)第 20 個(gè)包了,然后網(wǎng)絡(luò)斷了之后 client 重新,端口號(hào)還是之前那個(gè),然后序列號(hào)又從 0 開(kāi)始,此時(shí)服務(wù)端返回第 20 個(gè)包的ack,客戶(hù)端是不是傻了?

所以 RFC793 中認(rèn)為 ISN 要和一個(gè)假的時(shí)鐘綁定在一起ISN 每四微秒加一,當(dāng)超過(guò) 2 的 32 次方之后又從 0 開(kāi)始,要四個(gè)半小時(shí)左右發(fā)生 ISN 回繞。

所以 ISN 變成一個(gè)遞增值,真實(shí)的實(shí)現(xiàn)還需要加一些隨機(jī)值在里面,防止被不法份子猜到 ISN。

SYN 超時(shí)了怎么處理?

也就是 client 發(fā)送 SYN 至 server 然后就掛了,此時(shí) server 發(fā)送 SYN+ACK 就一直得不到回復(fù),怎么辦?

我腦海中一想到的就是重試,但是不能連續(xù)快速重試多次,你想一下,假設(shè) client 掉線(xiàn)了,你總得給它點(diǎn)時(shí)間恢復(fù)吧,所以呢需要慢慢重試,階梯性重試。

在 Linux 中就是默認(rèn)重試 5 次,并且就是階梯性的重試,間隔就是1s、2s、4s、8s、16s,再第五次發(fā)出之后還得等 32s 才能知道這次重試的結(jié)果,所以說(shuō)總共等63s 才能斷開(kāi)連接。

SYN Flood 攻擊

你看到?jīng)] SYN 超時(shí)需要耗費(fèi)服務(wù)端 63s 的時(shí)間斷開(kāi)連接,也就說(shuō) 63s 內(nèi)服務(wù)端需要保持這個(gè)資源,所以不法分子就可以構(gòu)造出大量的 client 向 server 發(fā) SYN 但就是不回 server。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

使得 server 的 SYN 隊(duì)列耗盡,無(wú)法處理正常的建連請(qǐng)求。

所以怎么辦?

可以開(kāi)啟 tcp_syncookies,那就用不到 SYN 隊(duì)列了。

SYN 隊(duì)列滿(mǎn)了之后 TCP 根據(jù)自己的 ip、端口、然后對(duì)方的 ip、端口,對(duì)方 SYN 的序號(hào),時(shí)間戳等一波操作生成一個(gè)特殊的序號(hào)(即 cookie)發(fā)回去,如果對(duì)方是正常的 client 會(huì)把這個(gè)序號(hào)發(fā)回來(lái),然后 server 根據(jù)這個(gè)序號(hào)建連。

或者調(diào)整 tcp_synack_retries 減少重試的次數(shù),設(shè)置 tcp_max_syn_backlog 增加 SYN 隊(duì)列數(shù),設(shè)置 tcp_abort_on_overflow SYN 隊(duì)列滿(mǎn)了直接拒絕連接。

為什么要四次揮手?

四次揮手和三次握手成雙成對(duì),同樣也是 TCP 中的一線(xiàn)明星,讓我們重溫一下熟悉的圖。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

為什么揮手需要四次?因?yàn)?TCP 是全雙工協(xié)議,也就是說(shuō)雙方都要關(guān)閉,每一方都向?qū)Ψ桨l(fā)送 FIN 和回應(yīng) ACK。

就像我對(duì)你說(shuō)我數(shù)據(jù)發(fā)完了,然后你回復(fù)好的你收到了。然后你對(duì)我說(shuō)你數(shù)據(jù)發(fā)完了,然后我向你回復(fù)我收到了。

所以看起來(lái)就是四次。

從圖中可以看到主動(dòng)關(guān)閉方的狀態(tài)是 FIN_WAIT_1 到 FIN_WAIT_2 然后再到 TIME_WAIT,而被動(dòng)關(guān)閉方是 CLOSE_WAIT 到 LAST_ACK。

四次揮手狀態(tài)一定是這樣變遷的嗎

狀態(tài)一定是這樣變遷的嗎?讓我們?cè)賮?lái)看個(gè)圖。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

可以看到雙方都主動(dòng)發(fā)起斷開(kāi)請(qǐng)求所以各自都是主動(dòng)發(fā)起方,狀態(tài)會(huì)從 FIN_WAIT_1 都進(jìn)入到 CLOSING 這個(gè)過(guò)度狀態(tài)然后再到 TIME_WAIT。

揮手一定需要四次嗎?

假設(shè) client 已經(jīng)沒(méi)有數(shù)據(jù)發(fā)送給 server 了,所以它發(fā)送 FIN 給 server 表明自己數(shù)據(jù)發(fā)完了,不再發(fā)了,如果這時(shí)候 server 還是有數(shù)據(jù)要發(fā)送給 client 那么它就是先回復(fù) ack ,然后繼續(xù)發(fā)送數(shù)據(jù)。

等 server 數(shù)據(jù)發(fā)送完了之后再向 client 發(fā)送 FIN 表明它也發(fā)完了,然后等 client 的 ACK 這種情況下就會(huì)有四次揮手。

那么假設(shè) client 發(fā)送 FIN 給 server 的時(shí)候 server 也沒(méi)數(shù)據(jù)給 client,那么 server 就可以將 ACK 和它的 FIN 一起發(fā)給client ,然后等待 client 的 ACK,這樣不就三次揮手了?

為什么要有 TIME_WAIT?

斷開(kāi)連接發(fā)起方在接受到接受方的 FIN 并回復(fù) ACK 之后并沒(méi)有直接進(jìn)入 CLOSED 狀態(tài),而是進(jìn)行了一波等待,等待時(shí)間為 2MSL。

MSL 是 Maximum Segment Lifetime,即報(bào)文最長(zhǎng)生存時(shí)間,RFC 793 定義的 MSL 時(shí)間是 2 分鐘,Linux 實(shí)際實(shí)現(xiàn)是 30s,那么 2MSL 是一分鐘。

那么為什么要等 2MSL 呢?

  • 就是怕被動(dòng)關(guān)閉方?jīng)]有收到最后的 ACK,如果被動(dòng)方由于網(wǎng)絡(luò)原因沒(méi)有到,那么它會(huì)再次發(fā)送 FIN, 此時(shí)如果主動(dòng)關(guān)閉方已經(jīng) CLOSED 那就傻了,因此等一會(huì)兒。

  • 假設(shè)立馬斷開(kāi)連接,但是又重用了這個(gè)連接,就是五元組完全一致,并且序號(hào)還在合適的范圍內(nèi),雖然概率很低但理論上也有可能,那么新的連接會(huì)被已關(guān)閉連接鏈路上的一些殘留數(shù)據(jù)干擾,因此給予一定的時(shí)間來(lái)處理一些殘留數(shù)據(jù)。

等待 2MSL 會(huì)產(chǎn)生什么問(wèn)題?

如果服務(wù)器主動(dòng)關(guān)閉大量的連接,那么會(huì)出現(xiàn)大量的資源占用,需要等到 2MSL 才會(huì)釋放資源。

如果是客戶(hù)端主動(dòng)關(guān)閉大量的連接,那么在 2MSL 里面那些端口都是被占用的,端口只有 65535 個(gè),如果端口耗盡了就無(wú)法發(fā)起送的連接了,不過(guò)我覺(jué)得這個(gè)概率很低,這么多端口你這是要建立多少個(gè)連接?

如何解決 2MSL 產(chǎn)生的問(wèn)題?

快速回收,即不等 2MSL 就回收, Linux 的參數(shù)是 tcp_tw_recycle,還有 tcp_timestamps 不過(guò)默認(rèn)是打開(kāi)的。

其實(shí)上面我們已經(jīng)分析過(guò)為什么需要等 2MSL,所以如果等待時(shí)間果斷就是出現(xiàn)上面說(shuō)的那些問(wèn)題。

所以不建議開(kāi)啟,而且 Linux 4.12 版本后已經(jīng)咔擦了這個(gè)參數(shù)了。

前不久剛有位朋友在群里就提到了這玩意。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

一問(wèn)果然有 NAT 的身影。

現(xiàn)象就是請(qǐng)求端請(qǐng)求服務(wù)器的靜態(tài)資源偶爾會(huì)出現(xiàn) 20-60 秒左右才會(huì)有響應(yīng)的情況,從抓包看請(qǐng)求端連續(xù)三個(gè) SYN 都沒(méi)有回應(yīng)。

比如你在學(xué)校,對(duì)外可能就一個(gè)公網(wǎng) IP,然后開(kāi)啟了 tcp_tw_recycle(tcp_timestamps 也是打開(kāi)的情況下),在 60 秒內(nèi)對(duì)于同源 IP 的連接請(qǐng)求中 timestamp 必須是遞增的,不然認(rèn)為其是過(guò)期的數(shù)據(jù)包就會(huì)丟棄。

學(xué)校這么多機(jī)器,你無(wú)法保證時(shí)間戳是一致的,因此就會(huì)出問(wèn)題。

所以這玩意不推薦使用。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

重用,即開(kāi)啟 tcp_tw_reuse 當(dāng)然也是需要 tcp_timestamps 的。

這里有個(gè)重點(diǎn),tcp_tw_reuse 是用在連接發(fā)起方的,而我們的服務(wù)端基本上是連接被動(dòng)接收方。

tcp_tw_reuse 是發(fā)起新連接的時(shí)候,可以復(fù)用超過(guò) 1s 的處于 TIME_WAIT 狀態(tài)的連接,所以它壓根沒(méi)有減少我們服務(wù)端的壓力。

它重用的是發(fā)起方處于 TIME_WAIT 的連接。

這里還有一個(gè) SO_REUSEADDR ,這玩意有人會(huì)和 tcp_tw_reuse 混為一談,首先 tcp_tw_reuse 是內(nèi)核選項(xiàng)而 SO_REUSEADDR 是用戶(hù)態(tài)選項(xiàng)。

然后 SO_REUSEADDR 主要用在你啟動(dòng)服務(wù)的時(shí)候,如果此時(shí)的端口被占用了并且這個(gè)連接處于 TIME_WAIT 狀態(tài),那么你可以重用這個(gè)端口,如果不是 TIME_WAIT,那就是給你個(gè) Address already in use。

所以這兩個(gè)玩意好像都不行,而且 tcp_tw_reuse 和tcp_tw_recycle,其實(shí)是違反 TCP 協(xié)議的,說(shuō)好的等我到天荒地老,你卻偷偷放了手?

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

要么就是調(diào)小 MSL 的時(shí)間,不過(guò)也不太安全,要么調(diào)整 tcp_max_tw_buckets 控制 TIME_WAIT 的數(shù)量,不過(guò)默認(rèn)值已經(jīng)很大了 180000,這玩意應(yīng)該是用來(lái)對(duì)抗 DDos 攻擊的。

所以我給出的建議是服務(wù)端不要主動(dòng)關(guān)閉,把主動(dòng)關(guān)閉方放到客戶(hù)端。畢竟咱們服務(wù)器是一對(duì)很多很多服務(wù),我們的資源比較寶貴。

自己攻擊自己

還有一個(gè)很騷的解決方案,我自己瞎想的,就是自己攻擊自己。

Socket 有一個(gè)選項(xiàng)叫 IP_TRANSPARENT ,可以綁定一個(gè)非本地的地址,然后服務(wù)端把建連的 ip 和端口都記下來(lái),比如寫(xiě)入本地某個(gè)地方。

然后啟動(dòng)一個(gè)服務(wù),假如現(xiàn)在服務(wù)端資源很緊俏,那么你就定個(gè)時(shí)間,過(guò)了多久之后就將處于 TIME_WAIT 狀態(tài)的對(duì)方 ip 和端口告訴這個(gè)服務(wù)。

然后這個(gè)服務(wù)就利用 IP_TRANSPARENT 偽裝成之前的那個(gè) client 向服務(wù)端發(fā)起一個(gè)請(qǐng)求,然后服務(wù)端收到會(huì)給真的 client 一個(gè) ACK, 那 client 都關(guān)了已經(jīng),說(shuō)你在搞啥子,于是回了一個(gè) RST,然后服務(wù)端就中止了這個(gè)連接。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

超時(shí)重傳機(jī)制是為了解決什么問(wèn)題?

前面我們提到 TCP 要提供可靠的傳輸,那么網(wǎng)絡(luò)又是不穩(wěn)定的如果傳輸?shù)陌鼘?duì)方?jīng)]收到卻又得保證可靠那么就必須重傳。

TCP 的可靠性是靠確認(rèn)號(hào)的,比如我發(fā)給你1、2、3、4這4個(gè)包,你告訴我你現(xiàn)在要 5 那說(shuō)明前面四個(gè)包你都收到了,就是這么回事兒。

不過(guò)這里要注意,SeqNum 和 ACK 都是以字節(jié)數(shù)為單位的,也就是說(shuō)假設(shè)你收到了1、2、4 但是 3 沒(méi)有收到你不能 ACK 5,如果你回了 5 那么發(fā)送方就以為你5之前的都收到了。

所以只能回復(fù)確認(rèn)最大連續(xù)收到包,也就是 3。

而發(fā)送方不清楚 3、4 這兩個(gè)包到底是還沒(méi)到呢還是已經(jīng)丟了,于是發(fā)送方需要等待,這等待的時(shí)間就比較講究了。

如果太心急可能 ACK 已經(jīng)在路上了,你這重傳就是浪費(fèi)資源了,如果太散漫,那么接收方急死了,這死鬼怎么還不發(fā)包來(lái),我等的花兒都謝了。

所以這個(gè)等待超時(shí)重傳的時(shí)間很關(guān)鍵,怎么搞?聰明的小伙伴可能一下就想到了,你估摸著正常來(lái)回一趟時(shí)間是多少不就好了,我就等這么長(zhǎng)。

這就來(lái)回一趟的時(shí)間就叫 RTT,即 Round Trip Time,然后根據(jù)這個(gè)時(shí)間制定超時(shí)重傳的時(shí)間 RTO,即 Retransmission Timeout。

不過(guò)這里大概只好了 RTO 要參考下 RTT ,但是具體要怎么算?首先肯定是采樣,然后一波加權(quán)平均得到 RTO。

RFC793 定義的公式如下:

1、先采樣 RTT 2、SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT) 3、RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]

ALPHA 是一個(gè)平滑因子取值在 0.8~0.9之間,UBOUND 就是超時(shí)時(shí)間上界-1分鐘,LBOUND 是下界-1秒鐘,BETA 是一個(gè)延遲方差因子,取值在 1.3~2.0。

但是還有個(gè)問(wèn)題,RTT 采樣的時(shí)間用一開(kāi)始發(fā)送數(shù)據(jù)的時(shí)間到收到 ACK 的時(shí)間作為樣本值還是重傳的時(shí)間到 ACK 的時(shí)間作為樣本值?

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

從圖中就可以看到,一個(gè)時(shí)間算長(zhǎng)了,一個(gè)時(shí)間算短了,這有點(diǎn)難,因?yàn)槟悴恢肋@個(gè)  ACK 到底是回復(fù)誰(shuí)的。

所以怎么辦?發(fā)生重傳的來(lái)回我不采樣不就好了,我不知道這次 ACK 到底是回復(fù)誰(shuí)的,我就不管他,我就采樣正常的來(lái)回。

這就是 Karn / Partridge 算法,不采樣重傳的RTT。

但是不采樣重傳會(huì)有問(wèn)題,比如某一時(shí)刻網(wǎng)絡(luò)突然就是很差,你要是不管重傳,那么還是按照正常的 RTT 來(lái)算 RTO, 那么超時(shí)的時(shí)間就過(guò)短了,于是在網(wǎng)絡(luò)很差的情況下還瘋狂重傳加重了網(wǎng)絡(luò)的負(fù)載。

因此 Karn 算法就很粗暴的搞了個(gè)發(fā)生重傳我就將現(xiàn)在的 RTO 翻倍,哼!就是這么簡(jiǎn)單粗暴。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

但是這種平均的計(jì)算很容易把一個(gè)突然間的大波動(dòng),平滑掉,所以又搞了個(gè)算法,叫 Jacobson / Karels Algorithm。

它把最新的 RTT 和平滑過(guò)的 SRTT 做了波計(jì)算得到合適的 RTO,公式我就不貼了,反正我不懂,不懂就不嗶嗶了。

為什么還需要快速重傳機(jī)制?

超時(shí)重傳是按時(shí)間來(lái)驅(qū)動(dòng)的,如果是網(wǎng)絡(luò)狀況真的不好的情況,超時(shí)重傳沒(méi)問(wèn)題,但是如果網(wǎng)絡(luò)狀況好的時(shí)候,只是恰巧丟包了,那等這么長(zhǎng)時(shí)間就沒(méi)必要。

于是又引入了數(shù)據(jù)驅(qū)動(dòng)的重傳叫快速重傳,什么意思呢?就是發(fā)送方如果連續(xù)三次收到對(duì)方相同的確認(rèn)號(hào),那么馬上重傳數(shù)據(jù)。

因?yàn)檫B續(xù)收到三次相同 ACK 證明當(dāng)前網(wǎng)絡(luò)狀況是 ok 的,那么確認(rèn)是丟包了,于是立馬重發(fā),沒(méi)必要等這么久。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

看起來(lái)好像挺完美的,但是你有沒(méi)有想過(guò)我發(fā)送1、2、3、4這4個(gè)包,就 2 對(duì)方?jīng)]收到,1、3、4都收到了,然后不管是超時(shí)重傳還是快速重傳反正對(duì)方就回 ACK 2。

這時(shí)候要重傳 2、3、4 呢還是就 2 呢?

SACK 的引入是為了解決什么問(wèn)題?

SACK 即 Selective Acknowledgment,它的引入就是為了解決發(fā)送方不知道該重傳哪些數(shù)據(jù)的問(wèn)題。

我們來(lái)看一下下面的圖就知道了。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

SACK 就是接收方會(huì)回傳它已經(jīng)接受到的數(shù)據(jù),這樣發(fā)送方就知道哪一些數(shù)據(jù)對(duì)方已經(jīng)收到了,所以就可以選擇性的發(fā)送丟失的數(shù)據(jù)。

如圖,通過(guò) ACK 告知我接下來(lái)要 5500 開(kāi)始的數(shù)據(jù),并一直更新 SACK,6000-6500 我收到了,6000-7000的數(shù)據(jù)我收到了,6000-7500的數(shù)據(jù)我收到了,發(fā)送方很明確的知道,5500-5999 的那一波數(shù)據(jù)應(yīng)該是丟了,于是重傳。

而且如果數(shù)據(jù)是多段不連續(xù)的, SACK 也可以發(fā)送,比如 SACK 0-500,1000-1500,2000-2500。就表明這幾段已經(jīng)收到了。

D-SACK 又是什么東西?

D-SACK 其實(shí)是 SACK 的擴(kuò)展,它利用 SACK 的第一段來(lái)描述重復(fù)接受的不連續(xù)的數(shù)據(jù)序號(hào),如果第一段描述的范圍被 ACK 覆蓋,說(shuō)明重復(fù)了,比如我都 ACK 到6000了你還給我回 SACK 5000-5500 呢?

說(shuō)白了就是從第一段的反饋來(lái)和已經(jīng)接受到的 ACK 比一比,參數(shù)是 tcp_dsack,Linux 2.4 之后默認(rèn)開(kāi)啟。

那知道重復(fù)了有什么用呢?

1、知道重復(fù)了說(shuō)明對(duì)方收到剛才那個(gè)包了,所以是回來(lái)的 ACK 包丟了。2、是不是包亂序的,先發(fā)的包后到?3、是不是自己太著急了,RTO 太小了?4、是不是被數(shù)據(jù)復(fù)制了,搶先一步呢?

滑動(dòng)窗口干嘛用?

我們已經(jīng)知道了 TCP 有序號(hào),并且還有重傳,但是這還不夠,因?yàn)槲覀儾皇倾额^青,還需要根據(jù)情況來(lái)控制一下發(fā)送速率,因?yàn)榫W(wǎng)絡(luò)是復(fù)雜多變的,有時(shí)候就會(huì)阻塞住,而有時(shí)候又很通暢。

所以發(fā)送方需要知道接收方的情況,好控制一下發(fā)送的速率,不至于蒙著頭一個(gè)勁兒的發(fā)然后接受方都接受不過(guò)來(lái)。

因此 TCP 就有個(gè)叫滑動(dòng)窗口的東西來(lái)做流量控制,也就是接收方告訴發(fā)送方我還能接受多少數(shù)據(jù),然后發(fā)送方就可以根據(jù)這個(gè)信息來(lái)進(jìn)行數(shù)據(jù)的發(fā)送。

以下是發(fā)送方維護(hù)的窗口,就是黑色圈起來(lái)的。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖來(lái)自網(wǎng)絡(luò)

圖中的 #1 是已收到 ACK 的數(shù)據(jù),#2 是已經(jīng)發(fā)出去但是還沒(méi)收到 ACK 的數(shù)據(jù),#3 就是在窗口內(nèi)可以發(fā)送但是還沒(méi)發(fā)送的數(shù)據(jù)。#4 就是還不能發(fā)送的數(shù)據(jù)。

然后此時(shí)收到了 36 的 ACK,并且發(fā)出了 46-51 的字節(jié),于是窗口向右滑動(dòng)了。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析 圖片來(lái)自網(wǎng)絡(luò)

TCP/IP Guide 上還有一張完整的圖,畫(huà)的十分清晰,大家看一下。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

如果接收方回復(fù)的窗口一直是 0 怎么辦?

上文已經(jīng)說(shuō)了發(fā)送方式根據(jù)接收方回應(yīng)的 window 來(lái)控制能發(fā)多少數(shù)據(jù),如果接收方一直回應(yīng) 0,那發(fā)送方就杵著?

你想一下,發(fā)送方發(fā)的數(shù)據(jù)都得到 ACK 了,但是呢回應(yīng)的窗口都是 0 ,這發(fā)送方此時(shí)不敢發(fā)了啊,那也不能一直等著啊,這 Window 啥時(shí)候不變 0 ???

于是 TCP 有一個(gè) Zero Window Probe 技術(shù),發(fā)送方得知窗口是 0 之后,會(huì)去探測(cè)探測(cè)這個(gè)接收方到底行不行,也就是發(fā)送 ZWP 包給接收方。

具體看實(shí)現(xiàn)了,可以發(fā)送多次,然后還有間隔時(shí)間,多次之后都不行可以直接 RST。

假設(shè)接收方每次回應(yīng)窗口都很小怎么辦?

你想象一下,如果每次接收方都說(shuō)我還能收 1 個(gè)字節(jié),發(fā)送方該不該發(fā)?

TCP + IP 頭部就 40 個(gè)字節(jié)了,這傳輸不劃算啊,如果傻傻的一直發(fā)這就叫 Silly Window。

那咋辦,一想就是發(fā)送端等著,等養(yǎng)肥了再發(fā),要么接收端自己自覺(jué)點(diǎn),數(shù)據(jù)小于一個(gè)閾值就告訴發(fā)送端窗口此時(shí)是 0 算了,也等養(yǎng)肥了再告訴發(fā)送端。

發(fā)送端等著的方案就是納格算法,這個(gè)算法相信看一下代碼就知道了。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

簡(jiǎn)單的說(shuō)就是當(dāng)前能發(fā)送的數(shù)據(jù)和窗口大于等于 MSS 就立即發(fā)送,否則再判斷一下之前發(fā)送的包 ACK 回來(lái)沒(méi),回來(lái)再發(fā),不然就攢數(shù)據(jù)。

接收端自覺(jué)點(diǎn)的方案是 David D Clark’s 方案,如果窗口數(shù)據(jù)小于某個(gè)閾值就告訴發(fā)送方窗口 0 別發(fā),等緩過(guò)來(lái)數(shù)據(jù)大于等于 MSS 或者接受 buffer 騰出一半空間了再設(shè)置正常的 window 值給發(fā)送方。

對(duì)了提到納格算法不得不再提一下延遲確認(rèn),納格算法在等待接收方的確認(rèn),而開(kāi)啟延遲確認(rèn)則會(huì)延遲發(fā)送確認(rèn),會(huì)等之后的包收到了再一起確認(rèn)或者等待一段時(shí)候真的沒(méi)了再回復(fù)確認(rèn)。

這就相互等待了,然后延遲就很大了,兩個(gè)不可同時(shí)開(kāi)啟。

已經(jīng)有滑動(dòng)窗口了為什么還要擁塞控制?

前面我已經(jīng)提到了,加了擁塞控制是因?yàn)?TCP 不僅僅就管兩端之間的情況,還需要知曉一下整體的網(wǎng)絡(luò)情形,畢竟只有大家都守規(guī)矩了道路才會(huì)通暢。

前面我們提到了重傳,如果不管網(wǎng)絡(luò)整體的情況,肯定就是對(duì)方?jīng)]給 ACK ,那我就無(wú)腦重傳。

如果此時(shí)網(wǎng)絡(luò)狀況很差,所有的連接都這樣無(wú)腦重傳,是不是網(wǎng)絡(luò)情況就更差了,更加擁堵了?

然后越擁堵越重傳,一直沖沖沖!然后就 GG 了。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

所以需要個(gè)擁塞控制,來(lái)避免這種情況的發(fā)送。

擁塞控制怎么搞?

主要有以下幾個(gè)步驟來(lái)搞:

1、慢啟動(dòng),探探路。2、擁塞避免,感覺(jué)差不多了減速看看 3、擁塞發(fā)生快速重傳/恢復(fù)

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

慢啟動(dòng),就是新司機(jī)上路慢慢來(lái),初始化 cwnd(Congestion Window)為 1,然后每收到一個(gè) ACK 就 cwnd++ 并且每過(guò)一個(gè) RTT ,cwnd = 2*cwnd 。

線(xiàn)性中帶著指數(shù),指數(shù)中又夾雜著線(xiàn)性增。

然后到了一個(gè)閾值,也就是 ssthresh(slow start threshold)的時(shí)候就進(jìn)入了擁塞避免階段。

這個(gè)階段是每收到一個(gè) ACK 就 cwnd = cwnd + 1/cwnd并且每一個(gè) RTT 就 cwnd++。

可以看到都是線(xiàn)性增。

然后就是一直增,直到開(kāi)始丟包的情況發(fā)生,前面已經(jīng)分析到重傳有兩種,一種是超時(shí)重傳,一種是快速重傳。

如果發(fā)生超時(shí)重傳的時(shí)候,那說(shuō)明情況有點(diǎn)糟糕,于是直接把 ssthresh 置為當(dāng)前 cwnd 的一半,然后 cwnd 直接變?yōu)?1,進(jìn)入慢啟動(dòng)階段。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

如果是快速重傳,那么這里有兩種實(shí)現(xiàn),一種是 TCP Tahoe ,和超時(shí)重傳一樣的處理。

一種是 TCP Reno,這個(gè)實(shí)現(xiàn)是把 cwnd = cwnd/2 ,然后把 ssthresh 設(shè)置為當(dāng)前的 cwnd 。

然后進(jìn)入快速恢復(fù)階段,將 cwnd = cwnd + 3(因?yàn)榭焖僦貍饔腥危?span style="color: rgb(60, 112, 198);">重傳 DACK 指定的包,如果再收到一個(gè)DACK則 cwnd++,如果收到是正常的 ACK 那么就將 cwnd 設(shè)為 ssthresh 大小,進(jìn)入擁塞避免階段。

可以看到快速恢復(fù)就重傳了指定的一個(gè)包,那有可能是很多包都丟了,然后其他的包只能等待超時(shí)重傳,超時(shí)重傳就會(huì)導(dǎo)致 cwnd 減半,多次觸發(fā)就指數(shù)級(jí)下降。

所以又搞了個(gè) New Reno,多加了個(gè) New,它是在沒(méi)有SACK 的情況下改進(jìn)快速恢復(fù),它會(huì)觀察重傳 DACK 指定的包的響應(yīng) ACK 是否是已經(jīng)發(fā)送的最大 ACK,比如你發(fā)了1、2、3、4,對(duì)方?jīng)]收到 2,但是 3、4都收到了,于是你重傳 2 之后 ACK 肯定是 5,說(shuō)明就丟了這一個(gè)包。

不然就是還有其他包丟了,如果就丟了一個(gè)包就是之前的過(guò)程一樣,如果還有其他包丟了就繼續(xù)重傳,直到 ACK 是全部的之后再退出快速恢復(fù)階段。

簡(jiǎn)單的說(shuō)就是一直探測(cè)到全部包都收到了再結(jié)束這個(gè)環(huán)節(jié)。

還有個(gè) FACK,它是基于 SACK 用來(lái)作為重傳過(guò)程中的擁塞控制,相對(duì)于上面的 New Reno 我們就知道它有 SACK 所以不需要一個(gè)一個(gè)試過(guò)去,具體我不展開(kāi)了。

還有哪些擁塞控制算法?

從維基上看有這么多。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

本來(lái)我還想嗶嗶幾句了,嗶嗶了之后又刪了,感覺(jué)說(shuō)了和沒(méi)說(shuō)一樣,想深入但是實(shí)力不允許,有點(diǎn)惆悵啊。

各位看官自個(gè)兒查查吧,或者等我日后修煉有成再來(lái)嗶嗶。

總結(jié)

說(shuō)了這么多來(lái)總結(jié)一下吧。

TCP 是面向連接的,提供可靠、有序的傳輸并且還提供流控和擁塞控制,單獨(dú)提取出 TCP 層而不是在 IP層實(shí)現(xiàn)是因?yàn)?IP 層有更多的設(shè)備需要使用,加了復(fù)雜的邏輯不劃算。

三次握手主要是為了定義初始序列號(hào)為了之后的傳輸打下基礎(chǔ),四次揮手是因?yàn)?TCP 是全雙工協(xié)議,因此雙方都得說(shuō)拜拜。

SYN 超時(shí)了就階梯性重試,如果有 SYN攻擊,可以加大半隊(duì)列數(shù),或減少重試次數(shù),或直接拒絕。

TIME_WAIT 是怕對(duì)方?jīng)]收到最后一個(gè) ACK,然后又發(fā)了 FIN 過(guò)來(lái),并且也是等待處理網(wǎng)絡(luò)上殘留的數(shù)據(jù),怕影響新連接。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

TIME_WAIT 不建議設(shè)小,或者破壞 TIME_WAIT 機(jī)制,如果真想那么可以開(kāi)啟快速回收,或者重用,不過(guò)注意受益的對(duì)象。

超時(shí)重傳是為了保證對(duì)端一定能收到包,快速重傳是為了避免在偶爾丟包的時(shí)候需要等待超時(shí)這么長(zhǎng)時(shí)間,SACK 是為了讓發(fā)送方知道重傳哪些。

D-SACK 是為了讓發(fā)送方知道這次重傳的原因是對(duì)方真的沒(méi)收到還是自己太心急了 RTO 整小了,不至于兩眼一抹黑。

滑動(dòng)窗口是為了平衡發(fā)送方的發(fā)送速率和接收方的接受數(shù)率,不至于瞎發(fā),當(dāng)然還需要注意 Silly Window 的情況,同時(shí)還要注意納格算法和延遲確認(rèn)不能一起搭配。

而滑動(dòng)窗口還不夠,還得有個(gè)擁塞控制,因?yàn)?span style="color: rgb(60, 112, 198);">出行你我他,安全靠大家,TCP 還得跳出來(lái)看看關(guān)心下當(dāng)前大局勢(shì)。

最后

至此就差不多了,不過(guò)還是有很多很多細(xì)節(jié)的,TCP 協(xié)議太復(fù)雜了,這可能是我文章里面圖畫(huà)的最少的一篇了,你看復(fù)雜到我圖都畫(huà)不來(lái)了哈哈哈。

今天我就說(shuō)了個(gè)皮毛,如有紕漏請(qǐng)趕緊后臺(tái)聯(lián)系鞭撻我。

萬(wàn)字長(zhǎng)文!23個(gè)問(wèn)題TCP疑難雜癥全解析

巨人的肩膀

http://www.tcpipguide.com/

https://www.ionos.com/digitalguide/server/know-how/introduction-to-tcp/

https://www.ibm.com/developerworks/cn/linux/l-tcp-sack/

https://coolshell.cn/articles/11564.html/

https://tools.ietf.org/html/rfc793https://nmap.org/book/tcpip-ref.html



免責(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)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

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

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

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

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

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶(hù)希望企業(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ì)開(kāi)幕式在貴陽(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ā)表演講稱(chēng),數(shù)字世界的話(huà)語(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)稱(chēng)"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

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