TCP是什麼?看完你就知道了

之前受到Wireshark——從此我就喜歡上了它,就像是學武之人得到了一把稱手好劍的啓發,帶着回顧、深入TCP的目標,回顧了《TCP-IP協議卷1》《圖解TCP/IP協議》,受益匪淺。寫這篇文章,希望自己能對TCP形成一個系統性的知識沉澱,也希望能給初學者一個基本概念的認識,讀完本文再深入書籍,應該也是不錯滴。

學習路徑:

1、閱讀《TCP-IP協議卷1》的TCP章節(相關知識非常全面,各種算法,但是因爲拗口的翻譯,比較難一時半會理解)

2、過一遍RFC 793 (TCP協議的規定,八幾年就訂好的,謝謝祖師爺賞口飯喫)

3、閱讀《圖解TCP/IP協議》的TCP章節(深入淺出,各種圖示讓你能更好的理解其作用過程,但描述的知識比較少,無法形成知識體系)

4、重複步驟1進行精讀並輸出xmind

建議最好還是結合 《TCP-IP協議卷1》+《圖解TCP/IP協議》一起看,看不懂時可以過一下《圖解TCP/IP協議》然後再結合《TCP-IP協議卷1》的實戰看

一、總覽

本文依據《TCP-IP協議卷1》的知識思路進行總結

1、TCP:傳輸控制協議(對TCP協議的一個總覽,並詳解了TCP協議頭的構成)

2、TCP連接的建立與終止(主要講解了TCP的三次握手與四次揮手,並講述了TCP連接的狀態變遷,面試常問)

3、一些TCP的數據交互規則(這一章比較小,主要講了幾個數據交互的規則)

4、TCP成塊的數據流(主要講解了TCP數據傳輸中會出現的問題和問題解決方案,主要是滑動窗口,面試常問)

5、TCP的超時與重傳(主要講解了當TCP傳輸時遇到超時的問題如何解決,主要是通過擁塞避免算法)

6、TCP的堅持定時器(講解一些確認通道可用性的定時器)

7、TCP的未來和性能(一些TCP的周邊知識)

二、TCP:傳輸控制協議

1、TCP是什麼?

傳輸控制協議(TCP,Transmission Control Protocol)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議。

說白了TCP就是一種傳輸協議,就像HTTP協議一樣,HTTP的目的是指定了客戶端可能發送給服務器什麼樣的消息以及得到什麼樣的響應,而TCP的目的是爲了確保數據傳輸的可靠性,我給你一個數據包,你一定就要收到,收不到的話那麼我就會給你重發,直到我超時放棄你了。

HTTP是建立在TCP之上的,當你建立起TCP連接之後,在上面傳輸的數據用的是HTTP協議。

2、TCP是面向連接的

經過TCP協議定義的三次握手之後,TCP協議建立一條虛擬的連接用於傳輸數據。

連接是指各種設備,線路,或網絡中進行通信的兩個應用程序爲了相互傳遞消息而專有的、虛擬的通信線路,也叫虛擬電路。

一旦建立了連接,進行通信的應用程序只使用這個虛擬的通信線路發送和接收數據,就可以保障信息的傳輸。應用程序可以不用顧慮其鏈路的問題。TCP則負責控制鏈接的建立,斷開,保持等管理工作。

數據被拆分成數據段,然後改通道進行傳輸,數據段傳輸的可靠性由TCP協議來保障。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2NuZFVfn-1573580402521)(H:\我的知識庫\知識庫\計算機網絡\TCP-IP詳解\TCP是什麼看完你就知道了\1572284935419.png)]

3、TCP怎麼實現其連接可靠性?

  • 應用數據會被切段(小塊數據傳輸保證通暢)
  • 數據段丟失重傳
  • 數據段收到確認
  • 數據段數據校驗和
  • 數據段重排序
  • 數據段去重
  • 流量控制

3.1、TCP以段爲單位發送數據

在三次握手時,交互通信的雙方會把自己最大的消息長度(MSS:Maximum Segment Size)告訴對方,TCP服務會把數據按MSS切分段發送

在這裏插入圖片描述

3.2、數據段收到確認

在TCP中,當發送端的數據到達接受主機時,接收端主機會返回一個收到消息的通知。這個消息叫做確認應答(ACK)。這個機制就好比我們經常在電視上看到人們經常用對講機說話,當你收到別人發送的語音時,你都需要回復一句“收到”讓發送者明確知道這條消息,可以安心的知道消息已被接受者接受。

在這裏插入圖片描述

當發送者在一定時間內沒有收到接受者的回覆時,發送者可以根據重傳策略(後面會介紹)進行消息重傳,保證消息能真正的發到接受者手中。

在這裏插入圖片描述

3.3、數據段丟失重傳

當數據包丟失的時候,TCP會根據重傳策略(後面會介紹)進行消息重傳,重傳策略包含快速重傳,還有超時重傳兩種場景。

3.4、數據段數據校驗和

TCP校驗和(Checksum)是一個端到端的校驗和,由發送端計算,然後由接收端驗證。其目的是爲了發現TCP首部和數據在發送端到接收端之間發生的任何改動。如果接收方檢測到校驗和有差錯,則TCP段會被直接丟棄。此時發送端沒有收到ACK,便會重新傳遞一個完好無損的數據包。

3.5、數據段重排序

TCP協議將數據切分爲多個小片段(數據被劃分爲合理長度),小片段由頭部(header)和數據(payload)組成,爲了確保抵達數據的順序,TCP協議給每個片段的頭部(header)都分配了序列號,接受者可以使用該序列號排序。

3.6、數據段去重

原因與3.5一致,接受者有了一波數據段的序列號,如果ACK因爲網絡關係沒有回覆給到發送者,導致發送者重傳,那麼發送者重傳後,接收者可以利用序列號進行去重,並在下一個ACK中回覆發送者。

3.7、流量控制

TCP的流量控制主要使用的是滑動窗口協議算法,在後面會有介紹。

以上所述都是TCP連接可靠性的保證,那TCP爲什麼可以如此強大呢?其中一部分原因呀,是它定義了一個強大的TCP協議頭,接下來,我們先來了解這個頭,每一個數據段都要攜帶這麼一個頭。

4、TCP首部

在這裏插入圖片描述

字段解析:

  • 端口號:所謂的端口,就好像是門牌號一樣,客戶端可以通過ip地址找到對應的服務器端,但是服務器端是有很多端口的,每個應用程序對應一個端口號,通過類似門牌號的端口號,客戶端才能真正的訪問到該服務器。爲了對端口進行區分,將每個端口進行了編號,這就是端口號。(軟考今年出了一題。。)

  • 序號:對每個數據段做的標記,標誌這某個數據段在某個數據中的位置(劃重點,發送者利用該序號表示數據段是完整數據的哪一部分,設置的規則是上一個段序號+上一個段長度。接收者利用該序號表示發送者下一個應發送的應該是哪一部分的數據,設置的規則是收到的數據段序號+數據段的長度。接收者回復的ACK序號,是發送者下一個數據段的序號,代表的意思是收到該序號之前的數據段)

  • 標誌

    • URG:緊急指針(代表緊急情況,接受者可以選擇優先處理)

    • ACK:應答

    • PSH:推送數據(接收方應該儘快將這個報文段交給應用層)

    • RST:連接重置(遇到該狀態碼,代表你的連接已非常混亂,一般應用層會收到一個連接重置異常)

    • SYN:建立連接

    • FIN:結束

  • 窗口大小:用於流量控制(窗口大小爲字節數,起始於確認序號字段指明的值,這個值是接收端正期望接受的字節)

  • 校驗和:主要是檢驗數據的準確性

  • 緊急數據:當URG標誌1時有效,發送端向另一端發送緊急數據

  • 可選字段:其他附件信息

由上可見呀,TCP協議中許多信息都是蘊含在TCP協議頭裏面,我們使用抓包工具抓包時,能分析統計到關於連接的情況都是根據頭部信息得到的,對頭部信息的掌握能快速讓我們掌握TCP協議原理,對問題的定位我們能更深入層面的分析。

三、TCP連接的建立與終止

看完了TCP協議的基本信息介紹,我們老生常談,繼續來聊聊TCP的連接與斷開問題,從連接斷開的過程中我們能初步瞭解到TCP數據段的傳輸機制,與可靠性保證,首先,我們先來看看連接與斷開的時序圖。

在這裏插入圖片描述

1、連接建立協議

TCP的連接,彷彿就像男女之間建立美妙的愛情關係

男:我愛你
女:嗯,我也愛你
男:嗯

相互的詢問,相互的確認,愛情就這樣產生。TCP也不過如此

clientA:client端發送一個SYN段指明server端打算連接的server的端口,以及初始序號ISN
serverB:server發回包含server的初始序號SYN報文段作爲應答。同時將確認序號設置爲client的ISN+1以對客戶端的SYN報文段進行確認。一個SYN將佔用一個序號
clientA:client必須將確認序號設置爲server的ISN+1以對服務器的SYN報文段確認

以上的過程,我們關注兩個問題

關於初始ISN

ISN隨時間而變化,是一個32bit的計數器,每4ms加1,這樣的選擇序號的目的在於防止在網絡中被延遲的分組在以後又被傳送,而導致某個鏈接的一方對它作錯誤的解釋。

爲什麼需要三次握手?

這個問題其實真的沒有那麼複雜,根據上文,我們可以知道TCP的可靠性保障機制之一就是消息確認機制,你想想呀,如果是兩次握手的話,那少了一次ACK,server怎麼知道到底client是收到自己的SYN請求沒呢?這樣可靠性就得不到保證了。

2、連接斷開協議

成年人的愛情就是龍捲風,來的快,走的快

女:對不起,我要跟你分手,我已經放下你了
男:嗯,我知道了

(男生並還沒放下,男對女還是思念思念思念...)
(一段時間過去了,男生終於也放下了)

男:我也放下你了,我們就這樣吧
女:嗯

相互的告別,相互的確認,當對方跟你告別時,你或許意猶未盡,終於等到你把最後一滴思念都給完了,那你也會跟她做最後的告別,一段感情到此爲止。TCP也不過如此

clientA:向server發送一個FIN
serverB:發回一個ACK,ISN爲收到的FIN的ISN+1
(serverB 繼續把沒發完的數據發發發,直到發完數據)
serverB:向client發送一個FIN
clientA:發回一個ACK,ISN爲收到的FIN的ISN+1

這裏我們需要關注一下這個問題:

爲什麼握手是三次、而揮手要四次?

這是由TCP的半關閉(half-close)造成的。既然一個TCP連接是全雙工的,因此每個方向必須單獨的進行關閉。這原則就是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向連接。當一端收到一個FIN,它必須通知應用層另一端已經終止了那個方向的數據傳送。發送FIN通常是應用層進行關閉的結果。

  • 全雙工:數據在兩個方向能同時傳遞

在這裏插入圖片描述

3、TCP狀態變遷圖

3.1、TCP狀態

TCP狀態在百度上面找不到定義哈,說一下筆者的理解。TCP狀態是TCP連接端在主動或被動做了某種操作後顯示的狀態,該狀態可以展示某條連接當前的信息即此時該連接正在做的某種操作(正在連接、已連接、發送數據…),在Linux上,我們可以通過以下命令看到所有TCP連接的狀態情況

ss -ta

3.2、爲什麼要掌握TCP狀態?

對筆者來說,TCP狀態主要還是便於做故障分析,假定幾個場景場景

#當前服務器的負載
ss -ta|grep 'ESTABLISHED'|wc -l

#服務端CLOSE_WAIT堆積,應用層沒對FIN做響應,導致連接數佔滿
ss -ta|grep 'CLOSE_WAIT'|wc -l

3.3、狀態圖與時序圖

這個圖真可以,有時候狀態也會忘,多看看真會熟悉滴

在這裏插入圖片描述

在這裏插入圖片描述

3.4、幾個關於TCP狀態的問題

爲什麼要存在TIME_WAIT狀態?

TIME_WAIT狀態也稱爲2MSL等待狀態。每個具體的TCP實現必須選擇一個報文段最大生存時間MSL。它是任何報文段被丟棄前在網絡內的最大時間。

  • 它可靠地實現TCP全雙工連接的終止。這樣可讓TCP再次發送最後的ACK以防這個ACK丟失(另一端超時並重發最後的FIN)
  • 允許老的重複分節在網絡中消逝
  • 這TCP連接在2MSL等待期間,定義這個連接的socket不能再被使用

也就是說在2MSL時間內,雖然可以重新啓動服務器,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接。

關於FIN_WAIT_2狀態

只有當另一端的進程完成這個連接關閉,客戶端纔會從FIN_WAIT_2狀態進入TIME_WAIT狀態。這意味着我們client可能永遠保持這個狀態。另一端也將處於CLOSE_WAIT狀態,並一直保持這個狀態直到應用層決定進行關閉。

許多伯克利實現採用如下方式來防止這種在FIN_WAIT_2狀態的無限等待。如果執行主動關閉的應用層將進行全關閉,而不是半關閉來說明它還想接受數據,就設置一個定時器。如果這個連接空閒10min75s ,TCP 將進入CLOSED狀態。

4、其他與連接相關的知識

最大報文段長度(MSS)是什麼?

我們在上面的交互圖中可以看到當發起連接時,雙方都會把自己的MSS告訴對方,表示TCP傳送另一端的最大塊的數據長度。

同一時間發送的段=滑動窗口/MSS。

重視復位報文段RST

一般來說,無論如何一個報文段發往基準的連接出現什麼錯誤,TCP都會發出一個報文段,一般來說可能會有以下場景

  • 到不存在的端口的連接請求
  • 終止一個異常連接
  • 檢測半打開的連接
  • 連接被異常終止

TCP可否同時打開/同時關閉?

TCP是特意設計爲了可以處理同時打開,對於同時打開它僅建立一條連接而不是兩條連接。TCP協議也允許這樣的同時關閉。

TCP選項的作用?

TCP選項,是包含在TCP頭部裏面一些其他的相關信息。如最大報文段長度、窗口擴大因子、時間戳等。

TCP服務器端程序設計是怎樣的,socket?

當一個新的連接請求到達服務器時,服務器接收這個請求,並調用一個新進程來處理這個新的客戶請求。不同操作系統使用不同的技術來調用新的服務器進程。在這個服務程序中,我們關注一下

  • TCP服務器端口號:只有處於LISTEN的進程能夠接受新的連接請求。處於ESTABLISHD的進程不能接受SYN報文段。

  • 連接限制:可限定本地IP地址、遠端IP地址

  • 呼入請求隊列(劃重點):到達多個連接請求,但是服務器正忙,並無法創建線程或進程去滿足它,那麼把這個連接丟入這個隊列(backlog),不止一次在中間件調優中看到該參數(參見Redis),隊列使用的規則

    • 正等待連接請求的一端有一個固定長度的連接隊列,該隊列中的連接已被TCP接受,但還沒被應用層所接受。注意區分TCP接受一個連接是將其放入這個隊列,而應用層接受連接是將其從該隊列中移除。
    • 應用層將指明該隊列的最大長度,這個值通常稱爲積壓值(backlog)
    • 當一個連接請求到達時,TCP使用一個算法,根據當前連接隊列中的連接數來確定是否接受這個連接。我們期望應用層說明的積壓值爲這一端點所能允許接受連接的最大數目。
    • 如果對於新的連接請求,該TCP監聽的端點的連接隊列中海油空間,TCP模塊將對SYN進行確認並完成連接的建立。但應用層只有在三次握手中的第三個報文段收到後纔會知道這個新鏈接。另外,當客戶進程的主動打開成功但服務器的應用層還不知道這個新的連接時,它可能會以爲服務器進程已經準備好接受數據了(如果發生這種情況,服務器的TCP僅將接受的數據放入緩衝隊列)
    • 如果對於新的連接請求,連接隊列中沒有空間,TCP將不會理會收到的SYN。也不發回任何報文段。如果應用層不能及時接受已被TCP接受的鏈接,這些連接可能佔滿整個連接隊列,客戶的主動打開最終將超時

四、數據交互規則

這一章節是一個小章節,主要講一下玉數據交換有關的規則,主要是ACK的延遲確認、Nagle算法、窗口大小的通告

1、ACK的延遲確認

在經典書籍翻譯是經受時延的確認,什麼意思呢?指的是通常TCP在接收到數據時並不立即發送ACK;相反,它會延遲發送,以便將ACK與需要沿該方向發送的數據一起發送。絕大多數實現採用的時延爲200ms,也就是說,TCP將以最大200ms的時延等待是否有數據一起發送。

2、Nagle算法

該算法要求一個TCP連接上最多隻能一個未被確認的未完成小分組,在該分組的確認到達之前不能發送其他的小分組。相反,TCP收集這些少量的分組,並在確認到來時以一個分組的方式發送出去。該算法的優越之處在於它是自適應的:確認到達的越快,數據也就發送的越快。而在希望減少微小分組數目的低速廣域網上,則會發送更少的分組。下圖是在xshell上面的Nagle選項

在這裏插入圖片描述

當我們關閉Nagle算法時,可以讓小消息必須無延時的發送,以便爲進行某種操作的交互用戶提供實時的反饋

3、通告窗口大小

TCP都在每個數據包上面向對方通告自己當前能處理的窗口大小,便於發送方以最優的策略發送數據包

五、TCP成塊的數據流

這一章的名字聽着很抽象,其實講的就是滑動窗口協議。TCP以一個段爲單位,每發一個段進行一次確認應答處理,這樣的傳輸方式有一個缺點。那就是,包的往返時間越長通信性能就越低。

爲了解決這個問題,TCP引入了窗口的概念。即使在往返時間較長的情況下,它也能控制網絡性能的下降,確認的應答不再是以每個分段,而是以更大的單位進行確認時,轉發時間將會被大幅度縮短。也就是說,發送端主機,在發送了一個段以後不必要一直等待確認應答,而是繼續發送。還記得我們之前說的MSS嗎?每一次的數據包大小不能超過MSS,每一波數據大小不能超過接收方的接收窗口大小。

在這裏插入圖片描述

1、滑動窗口

滑動窗口協議(Sliding Window Protocol),屬於TCP協議的一種應用,用於網絡數據傳輸時的流量控制,以避免擁塞的發生。該協議允許發送方在停止並等待確認前發送多個數據分組。由於發送方不必每發一個分組就停下來等待確認,因此該協議可以加速數據的傳輸,提高網絡吞吐量。其單位爲字節。

接下里,我們先看看看滑動窗口的可視化視圖,掌握了這個可視化圖,我們能更好理解滑動窗口的滑動二字意義在哪裏,是如何控制數據包傳輸的

在這裏插入圖片描述

  • 提供的窗口:接收方通告的窗口,它覆蓋了從第4字節到第9字節的區域
  • 當接收方確認數據後,這個滑動窗口不時地向右移動。窗口兩邊邊沿的相對運動增加或減少了窗口的大小

再接下來看看窗口的狀態變化

在這裏插入圖片描述

  • 窗口合攏:窗口左邊向右邊沿靠近。這種現象發生在數據被髮送和確認時。
  • 窗口張開:窗口有邊沿向右移動時將允許發送更多的數據。這種現象發生在另一端的接受進程讀取已經確認的數據並釋放了TCP的接收緩存時。
  • 如果左邊沿到達有邊沿:則稱其爲一個0窗口(接收方處理不過來了)
  • 窗口收縮:好像沒有這種情況,不解釋

雖然看完上面的視角圖,你可能會有些疑惑,我彙總了一次請求的數據交換與窗口的變化圖,仔細一品,感受滑動窗口的運作機制。

在這裏插入圖片描述

這其中

  • 發送方不必發送一個全窗口大小的數據
  • 來自接收方的一個報文段確認數據並把窗口向右邊移動。這是因爲窗口的大小是相對於確認序號的
  • 窗口的大小可以減小
  • 接收方在發送一個ACK前不必等待窗口被填滿

2、接收方通告的窗口大小問題

  • 由接收方提供的窗口大小通常可以由接收進程控制,這將影響TCP的性能
  • socket API 允許進程設置發送和接收的緩存的大小。接收緩存的大小是該連接上所能夠通過的最大窗口大小。有一些應用程序通過修改插口緩存大小來增加性能

3、PUSH標誌

發送方使用該標誌通知接收方將所收到的數據全部提交給接收進程。這裏的數據包括與PUSH一起傳送的數據以及接收方TCP已經爲接收進程收到的其他數據

4、什麼是慢啓動?

有了TCP的窗口控制,收發主機之間即使不再以一個數據段爲單位發送確認應答,也能夠發送大量數據包。然而,如果在通信剛開始時就發送大量數據,也可能會引起其他問題。

一般來說,在網絡出現擁堵時,如果突然發送一個較大量的數據,極有可能會導致整個網絡癱瘓。故有了慢啓動的過程。

慢啓動爲發送方的TCP增加了另一個窗口:擁塞窗口(congestion window),記爲cwnd。當與另一個網絡的主機建立TCP連接時,擁塞窗口被初始化爲1個報文段(即另一端通告的報文段大小)。每收到一個ACK,擁塞窗口就增加一個報文段(cwnd以字節爲單位,但是慢啓動以報文段大小爲單位進行增加)。發送方取擁塞窗口與通告窗口中的最小值作爲發送上限。擁塞窗口是發送方使用的流量限制,而通告窗口則是接受方使用的流量限制。

在這裏插入圖片描述

在這裏插入圖片描述

發送方開始時發送一個報文段,然後等待ACK。當收到該ACK時,擁塞窗口從1增加爲2,即可以發送兩個報文段。當收到這兩個報文段的ACK時,擁塞窗口就增加位4。這是一種指數增加的關係。

5、緊急窗口

還記得TCP頭中的URG字段嗎?它使一端可以告訴另一端有些具有某種方式的“緊急數據”已經放置在普通的數據流中。另一端被通知這個緊急數據已被放置在普通數據流中,由接收方決定如何處理。

可以通過設置TCP首部中的兩個字段來發出這種從一端到另一端的緊急數據已經被放置在數據流中的通知。URG bit 被置爲1,並且一個16 bit的緊急指針被置爲一個正的偏移量,該偏移量必須與TCP首部中的序號字段相加,以便得出緊急數據的最後一個字節的序號。

如Telnet 和 Rlogin。當交互用戶鍵入中斷鍵時,或FTP當交互用戶放棄一個文件傳輸時。

六、TCP的超時與重傳

1、擁塞避免

根據上文的確認機制我們可以知道,慢啓動是呈現指數級上漲的,速度是非常快的,但是如果接收方接收方處理不過來,或者是大家都因爲速度太快發生網絡擁堵的話,那快的意義就沒有了,所以呀,TCP需要在慢啓動一定的時間後,慢下來,我們稱它爲擁塞避免算法
但是這個擁塞避免算法是廣義的一個過程,包含了慢啓動的過程,又包含了快重傳快恢復超時重傳還有擁塞避免算法(這裏指的是真正的一個算法,而不是過程)過程,以下算法過程是從經典書中摘錄,結合圖,好好過兩遍,悟到了整個過程你就懂了。

在這裏插入圖片描述

  • 擁塞避免算法是一種處理丟失分組的方法。
  • 該算法假定由於分組受到損壞引起的丟失是非常少的,因此分組丟失就意味着源主機和目的主機之間的某處網絡上發生了擁塞。有兩種分組丟失的指示:發生超時和接收到重複的確認。
  • 擁塞避免算法和慢啓動算法是兩個目的不同、獨立的算法。但是當擁塞發生時,我們希望降低分組進入網絡的傳輸速率,於是可以調用慢啓動來做到這一點。在實際中這兩個算法通常在一起實現。

在這裏插入圖片描述
擁塞避免算法過程

  • 擁塞避免算法和慢啓動算法需要對每個連接維持兩個變量

    • 一個擁塞窗口cwnd
    • 一個慢啓動門限ssthresh
  • 對一個給定的連接

    • 初始化cwnd爲1個報文段
    • ssthresh爲65535個字節
  • TCP的輸出

    • 不能超過cwnd
    • 不能超過接收方通告窗口的大小
  • 當擁塞發生時(超時或收到重複確認)

    • ssthresh被設置爲當前窗口大小(cwnd和接收方通過窗口大小的最小值)的一半(但最少爲2個報文段),見下文的快速重傳與快速恢復
    • 此外,如果是超時引起了擁塞,則cwnd被設置爲1個報文段,然後進入慢啓動過程, 你可以認爲如果遇到超時,那您就重頭來吧
  • 當新的數據被對方確認時,就增加cwnd,但增加的方法依賴於我們是否正在進行慢啓動或擁塞避免

    • 如果cwnd小於或等於ssthresh,則正在進行的是慢啓動,慢啓動一直持續到我們回到當擁塞發生時所處位置的一半的時候才停止,然後轉爲執行擁塞避免。
    • 否則正在進行擁塞避免。擁塞避免算法要求每次收到一個確認時將 c w n d增加1 /c w n d。與慢啓動的指數增加比起來,這是一種加性增長(additive increase)。我們希望在一個往返時間內最多爲 c w n d增加1個報文段(不管在這個RT T中收到了多少個ACK),然而慢啓動將根據這個往返時間中所收到的確認的個數增加cwnd

2、快速重傳與快速恢復

從上文的擁塞避免算法中我們可以看到,當3次重複收到ACK的時候,代表網絡堵塞,有丟包的現象產生,所以TCP會降低速度,並重傳其報文段。

  • 快速重傳:當重複收到三個重複ACK時,我們就重傳丟失的數據報文段,而無須等待超時定時器溢出。

  • 快速恢復:當快速重傳後,立刻執行擁塞避免算法,即是快速恢復。

算法執行過程

  • 當收到3個重複ACK時,將ssrhresh設置爲當前擁塞窗口cwnd的一半。重傳丟失的報文段。設置cwnd爲ssthresh加上3倍報文段的大小
  • 每次收到另一個重複的ACK時,cwnd增加一個報文段大小併發送一個分組(如果新的cwnd允許發送)
  • 當下一個確認新數據的ACK到達時,設置cwnd爲ssthresh。這個ACK應該是在進行重傳後的一個往返時間內對步驟1中重傳確認。另外,這個ACK也應該是對丟失的分組和收到的第1個重複ACK之間的所有中間報文段的確認。這一步採用的是擁塞避免,因爲當分組丟失時我們將當前的速率減半

爲什麼一定要是三個重複ACK纔會觸發快速重傳?

假如這只是一些報文段的重新排序,則在重新排序的報文段被處理併產生一個新的ACK之前,只可能產生1~2個重複的ACK。如果一連串收到3個或3個以上的重複ACK,就非常可能是一個報文段丟失了。

重新分組

當TCP超時並重傳時,它不一定要重傳同樣的報文段。相反,TCP允許進行重新分組而發送一個較大的報文段,這將有助於提高性能。

七、TCP的堅持定時器

這一章開始,我們瞭解一些周邊的小知識。

什麼是堅持定時器?

當客戶端被通告窗口爲0時,客戶端將停止發送數據。會引起客戶設置其堅持定時器。如果該定時器時間到時客戶還沒有接收到一個窗口更新,它就探查這個空的窗口更新是否丟失。

計算堅持定時器時使用了普通的TCP指數退避。窗口探查包含一個字節,但是所返回的窗口爲0的ACK並不是確認該字節,因此這個字節被持續重傳。

堅持狀態與重傳超時之間的不同是TCP從不放棄發送窗口探查。這些探查每隔60s發送一次,這個過程將持續到或者窗口被打開,或者應用進程使用的連接被終止。

糊塗窗口綜合症

指的是少量的數據將通過連接進行交換,而不是滿長度的報文段

故障可能發生的原因

  • 接收方通告一個小的窗口
  • 發送少量的數據

避免措施

  • 接收方不通告小窗口
  • 發送方滿足這幾種條件之一才發送數據
    • 可以發送一個滿長度的報文段
    • 可以發送知識是接收方通告大小一半的報文段
    • 可以發送任何數據並且不希望接受ACK或者該連接上不能使用Nagle算法

八、TCP的保活定時器

保活定時器,主要是保持TCP連接的,比如你經常遇到的JDBC線程池,裏面就有一個保活的概念。TCP是一條虛擬的鏈路,雖然通信雙方進行握手建立虛擬通道,但是建立通道後如果不發生數據交互的話,那雙方都不知道對方是不是還保持socket會與自己繼續通訊,所以有了這個保活定時器。這也解決了之前疑惑的TCP連接的保活問題了。

通常是由服務器端設置這個功能

算法描述

  • 如果一個給定連接在兩個小時之內沒有任何動作,則服務器就向客戶發送一個探查報文段
  • 客戶主機狀態
    • 客戶主機依然正常運行
    • 客戶主機已經崩潰
    • 客戶主機已經崩潰並已經重新啓動
    • 客戶主機正常運行,但是從服務器不可達

九、TCP的未來和性能

TCP協議在草案中定義的窗口大小最大爲65535bit,那是當時的網絡情況比較差,這個窗口大小已經夠用了。現在可是5G時代65535算個啥,所以呀,TCP就在頭中的選項做了對窗口大小的擴展,以適應快速的網絡環境。
至於時間戳選項就沒得說了,用於計算包的往返時間,在wireshare給你展示包的發送時間,也是美美的。

  • 窗口擴大選項:通過定義一個選項實現對 16 bit的擴大操作 ( s c a l i n g o p e r a t i o n )來完成的。於是T C P在內部將實際的窗口大小維持爲32 bit的值
  • 時間戳選項:時間戳選項使發送方在每個報文段中放置一個時間戳值。接收方在確認中返回這個數值,
    從而允許發送方爲每一個收到的 A C K計算RT T

全文總結:之前對於TCP是陌生又熟悉,有了整套知識架構的支撐後,現在排查問題的過程中都覺得自信滿滿的,文章始終無法深入介紹TCP的完整知識,希望本文能基於你幫助,後面繼續深入看書+tcpdum+wireshark,我深信你終能喫透TCP
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章