<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # TCP 首先還是先來解答這個常考面試題關于 TCP 部分的內容,然后再詳細去學習這個協議。 > 常考面試題:UDP 與 TCP 的區別是什么? TCP 基本是和 UDP 反著來,建立連接斷開連接都需要先需要進行握手。在傳輸數據的過程中,通過各種算法保證數據的可靠性,當然帶來的問題就是相比 UDP 來說不那么的高效。 ## 頭部 從這個圖上我們就可以發現 TCP 頭部比 UDP 頭部復雜的多。 ![](https://box.kancloud.cn/eb9c7da1cc09062368972683f26b5264_858x305.png) 對于 TCP 頭部來說,以下幾個字段是很重要的 * Sequence number,這個序號保證了 TCP 傳輸的報文都是有序的,對端可以通過序號順序的拼接報文 * Acknowledgement Number,這個序號表示數據接收端期望接收的下一個字節的編號是多少,同時也表示上一個序號的數據已經收到 * Window Size,窗口大小,表示還能接收多少字節的數據,用于流量控制 * 標識符 * URG=1:該字段為一表示本數據報的數據部分包含緊急信息,是一個高優先級數據報文,此時緊急指針有效。緊急數據一定位于當前數據包數據部分的最前面,緊急指針標明了緊急數據的尾部。 * ACK=1:該字段為一表示確認號字段有效。此外,TCP 還規定在連接建立后傳送的所有報文段都必須把 ACK 置為一。 * PSH=1:該字段為一表示接收端應該立即將數據 push 給應用層,而不是等到緩沖區滿后再提交。 * RST=1:該字段為一表示當前 TCP 連接出現嚴重問題,可能需要重新建立 TCP 連接,也可以用于拒絕非法的報文段和拒絕連接請求。 * SYN=1:當SYN=1,ACK=0時,表示當前報文段是一個連接請求報文。當SYN=1,ACK=1時,表示當前報文段是一個同意建立連接的應答報文。 * FIN=1:該字段為一表示此報文段是一個釋放連接的請求報文。 ## 狀態機 TCP 的狀態機是很復雜的,并且與建立斷開連接時的握手息息相關,接下來就來詳細描述下兩種握手。 ![](https://box.kancloud.cn/bd43c2f8389cb473e7b9b8bcdcebfcc4_1273x960.png) 在這之前需要了解一個重要的性能指標 RTT。該指標表示發送端發送數據到接收到對端數據所需的往返時間。 ### 建立連接三次握手 ![](https://box.kancloud.cn/11b9da310ba313bb9497f628cd36356a_666x426.png) 首先假設主動發起請求的一端稱為客戶端,被動連接的一端稱為服務端。不管是客戶端還是服務端,TCP 連接建立完后都能發送和接收數據,所以 TCP 是一個全雙工的協議。 起初,兩端都為 CLOSED 狀態。在通信開始前,雙方都會創建 TCB。 服務器創建完 TCB 后便進入 LISTEN 狀態,此時開始等待客戶端發送數據。 **第一次握手** 客戶端向服務端發送連接請求報文段。該報文段中包含自身的數據通訊初始序號。請求發送后,客戶端便進入 SYN-SENT 狀態。 **第二次握手** 服務端收到連接請求報文段后,如果同意連接,則會發送一個應答,該應答中也會包含自身的數據通訊初始序號,發送完成后便進入 SYN-RECEIVED 狀態。 **第三次握手** 當客戶端收到連接同意的應答后,還要向服務端發送一個確認報文。客戶端發完這個報文段后便進入 ESTABLISHED 狀態,服務端收到這個應答后也進入 ESTABLISHED 狀態,此時連接建立成功。 PS:第三次握手中可以包含數據,通過快速打開(TFO)技術就可以實現這一功能。其實只要涉及到握手的協議,都可以使用類似 TFO 的方式,客戶端和服務端存儲相同的 cookie,下次握手時發出 cookie 達到減少 RTT 的目的。 > 常考面試題:為什么 TCP 建立連接需要三次握手,明明兩次就可以建立起連接 因為這是為了防止出現失效的連接請求報文段被服務端接收的情況,從而產生錯誤。 可以想象如下場景。客戶端發送了一個連接請求 A,但是因為網絡原因造成了超時,這時 TCP 會啟動超時重傳的機制再次發送一個連接請求 B。此時請求順利到達服務端,服務端應答完就建立了請求,然后接收數據后釋放了連接。 假設這時候連接請求 A 在兩端關閉后終于抵達了服務端,那么此時服務端會認為客戶端又需要建立 TCP 連接,從而應答了該請求并進入 ESTABLISHED 狀態。但是客戶端其實是 CLOSED 的狀態,那么就會導致服務端一直等待,造成資源的浪費。 PS:在建立連接中,任意一端掉線,TCP 都會重發 SYN 包,一般會重試五次,在建立連接中可能會遇到 SYN Flood 攻擊。遇到這種情況你可以選擇調低重試次數或者干脆在不能處理的情況下拒絕請求。 ### 斷開鏈接四次握手 ![](https://box.kancloud.cn/96ab5f308fe0eb2aa3008eb54d7ff6e8_640x512.png) TCP 是全雙工的,在斷開連接時兩端都需要發送 FIN 和 ACK。 **第一次握手** 若客戶端 A 認為數據發送完成,則它需要向服務端 B 發送連接釋放請求。 **第二次握手** B 收到連接釋放請求后,會告訴應用層要釋放 TCP 鏈接。然后會發送 ACK 包,并進入 CLOSE\_WAIT 狀態,此時表明 A 到 B 的連接已經釋放,不再接收 A 發的數據了。但是因為 TCP 連接是雙向的,所以 B 仍舊可以發送數據給 A。 **第三次握手** B 如果此時還有沒發完的數據會繼續發送,完畢后會向 A 發送連接釋放請求,然后 B 便進入 LAST-ACK 狀態。 PS:通過延遲確認的技術(通常有時間限制,否則對方會誤認為需要重傳),可以將第二次和第三次握手合并,延遲 ACK 包的發送。 **第四次握手** A 收到釋放請求后,向 B 發送確認應答,此時 A 進入 TIME-WAIT 狀態。該狀態會持續 2MSL(最大段生存期,指報文段在網絡中生存的時間,超時會被拋棄) 時間,若該時間段內沒有 B 的重發請求的話,就進入 CLOSED 狀態。當 B 收到確認應答后,也便進入 CLOSED 狀態。 **為什么 A 要進入 TIME-WAIT 狀態,等待 2MSL 時間后才進入 CLOSED 狀態?** 為了保證 B 能收到 A 的確認應答。若 A 發完確認應答后直接進入 CLOSED 狀態,如果確認應答因為網絡問題一直沒有到達,那么會造成 B 不能正常關閉。 ## ARQ 協議 ARQ 協議也就是超時重傳機制。通過確認和超時機制保證了數據的正確送達,ARQ 協議包含停止等待 ARQ 和連續 ARQ 兩種協議。 ### 停止等待 ARQ **正常傳輸過程** 只要 A 向 B 發送一段報文,都要停止發送并啟動一個定時器,等待對端回應,在定時器時間內接收到對端應答就取消定時器并發送下一段報文。 **報文丟失或出錯** 在報文傳輸的過程中可能會出現丟包。這時候超過定時器設定的時間就會再次發送丟失的數據直到對端響應,所以需要每次都備份發送的數據。 即使報文正常的傳輸到對端,也可能出現在傳輸過程中報文出錯的問題。這時候對端會拋棄該報文并等待 A 端重傳。 PS:一般定時器設定的時間都會大于一個 RTT 的平均時間。 **ACK 超時或丟失** 對端傳輸的應答也可能出現丟失或超時的情況。那么超過定時器時間 A 端照樣會重傳報文。這時候 B 端收到相同序號的報文會丟棄該報文并重傳應答,直到 A 端發送下一個序號的報文。 在超時的情況下也可能出現應答很遲到達,這時 A 端會判斷該序號是否已經接收過,如果接收過只需要丟棄應答即可。 從上面的描述中大家肯定可以發現這肯定不是一個高效的方式。假設在良好的網絡環境中,每次發送數據都需要等待片刻肯定是不能接受的。那么既然我們不能接受這個不那么高效的協議,就來繼續學習相對高效的協議吧。 ### 連續 ARQ 在連續 ARQ 中,發送端擁有一個**發送窗口**,可以在沒有收到應答的情況下持續發送窗口內的數據,這樣相比停止等待 ARQ 協議來說減少了等待時間,提高了效率。 ### 累計確認 連續 ARQ 中,接收端會持續不斷收到報文。如果和停止等待 ARQ 中接收一個報文就發送一個應答一樣,就太浪費資源了。通過累計確認,可以在收到多個報文以后統一回復一個應答報文。報文中的 ACK 標志位可以用來告訴發送端這個序號之前的數據已經全部接收到了,下次請發送這個序號后的數據。 但是累計確認也有一個弊端。在連續接收報文時,可能會遇到接收到序號 5 的報文后,并未接收到序號 6 的報文,然而序號 7 以后的報文已經接收。遇到這種情況時,ACK 只能回復 6,這樣就會造成發送端重復發送數據的情況。 ## 滑動窗口 在上面小節中講到了發送窗口。在 TCP 中,兩端其實都維護著窗口:分別為發送端窗口和接收端窗口。 發送端窗口包含已發送但未收到應答的數據和可以發送但是未發送的數據。 ![](https://box.kancloud.cn/256d64c69471bbae3be544361ce6936f_660x270.png) 發送端窗口是由接收窗口剩余大小決定的。接收方會把當前接收窗口的剩余大小寫入應答報文,發送端收到應答后根據該值和當前網絡擁塞情況設置發送窗口的大小,所以發送窗口的大小是不斷變化的。 當發送端接收到應答報文后,會隨之將窗口進行滑動 ![](https://box.kancloud.cn/190e227454af571103c495ccb4e90b91_660x210.png) 滑動窗口是一個很重要的概念,它幫助 TCP 實現了流量控制的功能。接收方通過報文告知發送方還可以發送多少數據,從而保證接收方能夠來得及接收數據,防止出現接收方帶寬已滿,但是發送方還一直發送數據的情況。 ### Zero 窗口 在發送報文的過程中,可能會遇到對端出現零窗口的情況。在該情況下,發送端會停止發送數據,并啟動 persistent timer 。該定時器會定時發送請求給對端,讓對端告知窗口大小。在重試次數超過一定次數后,可能會中斷 TCP 鏈接。 ## 擁塞處理 擁塞處理和流量控制不同,后者是作用于接收方,保證接收方來得及接受數據。而前者是作用于網絡,防止過多的數據擁塞網絡,避免出現網絡負載過大的情況。 擁塞處理包括了四個算法,分別為:慢開始,擁塞避免,快速重傳,快速恢復。 ### 慢開始算法 慢開始算法,顧名思義,就是在傳輸開始時將發送窗口慢慢指數級擴大,從而避免一開始就傳輸大量數據導致網絡擁塞。想必大家都下載過資源,每當我們開始下載的時候都會發現下載速度是慢慢提升的,而不是一蹴而就直接拉滿帶寬。 慢開始算法步驟具體如下 1. 連接初始設置擁塞窗口(Congestion Window) 為 1 MSS(一個分段的最大數據量) 2. 每過一個 RTT 就將窗口大小乘二 3. 指數級增長肯定不能沒有限制的,所以有一個閾值限制,當窗口大小大于閾值時就會啟動擁塞避免算法。 ### 擁塞避免算法 擁塞避免算法相比簡單點,每過一個 RTT 窗口大小只加一,這樣能夠避免指數級增長導致網絡擁塞,慢慢將大小調整到最佳值。 在傳輸過程中可能定時器超時的情況,這時候 TCP 會認為網絡擁塞了,會馬上進行以下步驟: * 將閾值設為當前擁塞窗口的一半 * 將擁塞窗口設為 1 MSS * 啟動擁塞避免算法 ### 快速重傳 快速重傳一般和快恢復一起出現。一旦接收端收到的報文出現失序的情況,接收端只會回復最后一個順序正確的報文序號。如果發送端收到三個重復的 ACK,無需等待定時器超時而是直接啟動快速重傳算法。具體算法分為兩種: **TCP Taho 實現如下** * 將閾值設為當前擁塞窗口的一半 * 將擁塞窗口設為 1 MSS * 重新開始慢開始算法 **TCP Reno 實現如下** * 擁塞窗口減半 * 將閾值設為當前擁塞窗口 * 進入快恢復階段(重發對端需要的包,一旦收到一個新的 ACK 答復就退出該階段),這種方式在丟失多個包的情況下就不那么好了 * 使用擁塞避免算法 ### TCP New Ren 改進后的快恢復 **TCP New Reno** 算法改進了之前 **TCP Reno** 算法的缺陷。在之前,快恢復中只要收到一個新的 ACK 包,就會退出快恢復。 在 **TCP New Reno** 中,TCP 發送方先記下三個重復 ACK 的分段的最大序號。 假如我有一個分段數據是 1 ~ 10 這十個序號的報文,其中丟失了序號為 3 和 7 的報文,那么該分段的最大序號就是 10。發送端只會收到 ACK 序號為 3 的應答。這時候重發序號為 3 的報文,接收方順利接收的話就會發送 ACK 序號為 7 的應答。這時候 TCP 知道對端是有多個包未收到,會繼續發送序號為 7 的報文,接收方順利接收并會發送 ACK 序號為 11 的應答,這時發送端認為這個分段接收端已經順利接收,接下來會退出快恢復階段。 ## 小結 這一章節內容很多,充斥了大量的術語,適合大家反復研讀,已經把 TCP 中最核心最需要掌握的內容全盤托出了,如有哪里不明白的歡迎提問。 總結一下這一章節的內容: * 建立連接需要三次握手,斷開連接需要四次握手 * 滑動窗口解決了數據的丟包、順序不對和流量控制問題 * 擁塞窗口實現了對流量的控制,保證在全天候環境下最優的傳遞數據
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看