?
🎬?個人主頁:誰在夜里看海.
📖?個人專欄:《C++系列》《Linux系列》《算法系列》
???道阻且長,行則將至
目錄
📚引言
📚一、UDP協議
📖 1.概述
📖 2.特點
📚二、TCP協議?
📖 1.概述
📖 2.機制
🔖確認應答(ACK)
🔖超時重傳
🔖連接管理
🔖滑動窗口
🔖流量控制
🔖擁塞控制
🔖延遲、捎帶應答
📖3.總結
📚引言
在之前的一篇文章中,我們詳細介紹了 socket網絡編程(基于 TCP 和 UDP),并且在應用層,我們已經能夠熟練地調用API來編寫簡單的服務器和客戶端應用。然而,要更好地理解網絡編程,我們必須深入了解這兩種協議的傳輸機制和它們的工作原理。今天,我們將通過對 TCP 和 UDP協議的進一步剖析,探索它們在實際傳輸中的差異、優勢和局限性。
🔗文章鏈接:《【Linux-網絡】初識計算機網絡 & Socket套接字 & TCP/UDP協議(包含Socket編程實戰)》
📚一、UDP協議
📖 1.概述
UDP(User Datagram Protocol,用戶數據報協議)是面向報文的協議,即數據是通過報文的形式進行傳輸,類似于寄信。與 TCP 協議相比,它更加簡潔和高效,體現在更少的報文段信息以及沒有TCP協議的各種機制。
下面是UDP報文段的標準格式:
UDP數據報由 頭部 和 數據部分 兩部分組成:
UDP頭部(8字節):
① 源端口號(16位):表示發送數據的應用端口。
② 目的端口號(16位):表示接收數據的應用端口。
③ 長度(16位):表示整個UDP報文的長度,包括頭部和數據部分的總長度。最大值為64k字節。
④ 校驗和(16位):用于檢測傳輸過程中的數據完整性。雖然UDP是可選的,但如果IPv6被使用,校驗和是必須的。
UDP數據部分:包括從源應用傳來的數據,數據部分的大小由上面提到的 長度字段 決定。
???由于UDP數據包的最大長度為64k,當要數據大于這個長度時,就需要進行分包傳輸。
📖 2.特點
與 UDP 的簡潔性相對應地,UDP是 無連接的、不可靠的。
1???面向報文:UDP是面向報文的協議,意味著每次發送的數據包都是一個獨立的單位。
2???較小的頭部開銷:UDP頭部僅包含 8個字節,相比TCP的20字節頭部,UDP的頭部開銷更小。
3???不可靠性:UDP不保證數據的可靠傳輸,也不保證數據的順序。如果數據丟失,發送方沒有重傳機制,接收方無法知道數據丟失。
由于UDP協議的 低延遲 和 簡潔性,它特別適合用于對實時性要求高、但對數據可靠性要求較低的場景,例如實時視頻通話、在線游戲等。
UDP協議提供的是一種不可靠的數據傳輸方式,適用于對實時性要求高的場景。然而,當我們需要確保數據包的可靠傳輸,避免丟包時,TCP協議則成為更合適的選擇。?
📚二、TCP協議?
📖 1.概述
TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接、可靠的傳輸層協議。它確保數據能夠準確、按順序地傳輸到目的地。為了保證數據傳輸的可靠性和穩定性,TCP報文段就需要包含更多信息。
下面是TCP報文段的標準格式:
其中序列號、確認號、標志位(ACK、SYN等)、窗口大小這些數據段需要結合TCP的特殊傳輸機制來理解,這里我們先區分一下UDP的報文長度和TCP的首部長度:
?前者表示整個報文段的長度,后者僅表示報文頭的長度,這是為什么呢?
?UDP中報文長度這一數據段的作用是使接收方可以正確提取數據,而在TCP中這一職責由序列號+首部長度共同完成,其中序列號表示的是數據區的長度。之所以要標明報頭長度是因為,TCP報頭是不定長的,除了固定數據段之外,還有可選數據段。
TCP的選項數據段是TCP頭部的可選字段,允許在連接建立后對TCP連接進行進一步的配置和優化。選項字段用于擴展TCP協議的功能,提供額外的控制信息,以適應不同的應用需求。
下面我們來一一介紹TCP的各種機制。
📖 2.機制
🔖確認應答(ACK)
我們提到,TCP協議提供的是可靠傳輸,這當中非常重要的一點是,要避免數據丟包問題,由于網絡是不穩定的,數據丟包是很正常的現象。那么發送方怎么知道發送的數據有沒有丟失呢?很簡單,讓接收方接受數據后回應一下,表示數據收到了,這就是TCP的確認應答機制。
但是當發送方發送多個數據包后,怎么知道收到的應答是對應哪個數據包的呢,這就需要TCP中的確認號和序列號字段了。
序列號:每個發送的數據段都被賦予一個唯一的序列號,用于標識數據流中的每一個字節。這個序列號是TCP可靠傳輸的基礎,接收方根據序列號判斷數據是否丟失或者是否按正確順序到達。
確認號:接收方使用確認號來告訴發送方,自己已經成功接收到的數據的最后一個字節的序列號。確認號是接收方期望接收的下一個字節的序列號。
每一個ACK都帶有對應的確認序列號,表示已接收了哪些數據,下一個數據應該從哪里開始。
🔖超時重傳
基于確認應答機制,當發送方過了一段時間后,還沒有收到來自接收方的確認應答,就可以判定數據包丟失了,此時就需要重新發送數據包,這就是超時重傳機制。
這里的丟包分為兩種情況:
① 發送的數據包本身丟失了;② 接收方的確認應答丟失了。
無論是哪種情況,都需要重新發送數據包,而對于第二種情況,接收方會收到兩個相同的數據包,這個時候根據序列號判斷,如果序列號相同,則認為兩個數據包相同,會將重復的數據包丟棄,并不影響。
?這個超時的時間該如何確定呢?
數據包傳輸到達的時間是會受網絡環境影響變化的,如果超時時間設置的太長,會影響重傳的效率;如果超時時間設置的過短,則有可能會頻繁發送重復的數據包。
?TCP為了保證在任何環境下都能比較高性能的通信,會動態計算這個超時時間。
以Linux為例,超時時間以500ms為單位,如果重傳一次還沒有得到應答,則等待2*500ms后再進行重傳;之后還得不到應到,則等待4*500ms......直到累計一定的重傳次數后,TCP判定網絡或目標主機出現異常,強制關閉連接。
🔖連接管理
基于TCP協議進行通信的雙方,一個基本的前提條件就是,雙方都確保能正常發送和接受數據,這樣才能保證通信的穩定與可靠性。所以在通信發生之前,需要對雙方的發送、接受能力進行驗證;同樣地,在通信結束時,也需要確保雙方都已關閉連接信道,避免單方面發送數據卻不能被接收也等不到應答的情況。這就是三次握手與四次揮手機制。?
在理解三次握手與四次揮手之前,我們需要了解一個預備知識,那就是TCP報文段的標志位。
TCP報文段中的標志位(也叫控制位)用于控制TCP連接的建立、維護和終止。每個TCP報文段中都有一個6位的標志字段,分別是:
① URG(緊急標志):用于指示數據段中有緊急數據需要處理
② ACK(確認標志):表示確認號字段有效,即接收方通過確認號來告知發送方它期望接收的下一個字節的序列號
③ PSH(推送標志):表示接收方應該立即將數據推送給應用層
④ RST(重置標志):強制斷開TCP連接,用于一方出現錯誤或不可恢復的異常的情況
⑤ SYN(同步標志):用于連接的建立,表示請求連接或響應連接請求
⑥ FIN(終止標志):用于連接的斷開,表示發送方沒有數據要發送,并請求關閉連接
在TCP三次握手過程中,SYN標志位會在第一次和第二次握手時被使用:
1?? 客戶端發起連接時,會發送一個帶SYN標志的報文,表示請求建立連接。
2?? 服務器響應客戶端請求時,也會發送一個帶SYN標志的報文來表示同意連接。
在TCP四次揮手過程中,FIN標志位被用來發起和響應連接的終止:
1?? 主動關閉連接的一方會發送帶有FIN標志的報文,表示它已經完成數據傳輸并希望關閉連接。
2?? 被動關閉的一方也會發送帶有FIN標志的報文作為確認,表示它同意終止連接。?
下面是三次握手的全過程:
① 第一次握手:通信發起方向接收方發送SYN報文,請求連接(打開寫端,表示我要寫數據了)
② 第二次握手:接收方收到SYN報文,回復ACK報文,表示同意連接請求(打開讀端,表示我能收到數據);并同時也發送SYN報文(打開寫端,我也要寫數據了)
③ 第三次握手;發起方收到SYN報文,同意回復ACK報文(打開讀端,表示我也能收到數據)
四次揮手的全過程:
① 第一次揮手:斷開連接發起方向接收方發送FIN報文,表示希望關閉連接(關閉寫端,表示不再寫數據了)
② 第二次揮手:接收方收到FIN請求,回復ACK表示同意(關閉讀端,我不再等待接收數據了)
③ 第三次揮手:接收方發送FIN請求(關閉寫端,我也不寫數據了)?
④ 第四次揮手:發起方收到FIN請求,回復ACK表示同意(關閉讀端,我也不等待接收數據了)
從上面的步驟來看,其實第二次握手是包含兩步的:接收方打開讀端與寫端,這與第二次揮手、第三次揮手是對應上的,問題來了:
?① 為什么要把接收方打開讀端與寫端的操作合并為一步;② 為什么接收方斷開讀端和寫端的操作不能合并成一步。
?先回答第一個問題,我們要知道,每一個標志位的獨立發送都需要獨立的報文段,接收方要分別發送ACK與SYN的話就需要占用兩個報文段,既然如此,為什么不把這兩步合成一步,節省資源呢,于是就有了第二次握手。
?對于第二個問題,斷開連接發起方發送FIN報文的意思是,不會再發送數據了,也就是關閉了寫端,但這并不意味著讀端也關閉了;同樣地,接收方在收到FIN報文后回復ACK的意思是,關閉讀端,但也不意味著寫端就要一并關閉,相反地,它依舊可以發送數據,對方也依舊可以收到數據,因此二、三揮手要分開來執行。
在TCP協議中,連接的建立與斷開遵循嚴格的狀態變化流程。理解連接發起方、接收方以及斷開發起方、接收方的狀態變化對理解TCP的三次握手(連接建立)和四次揮手(連接終止)至關重要。
連接建立(TCP三次握手)
① 連接發起方(客戶端)
? ? ? ? 初始狀態:CLOSED(連接關閉);
????????發送SYN請求:客戶端進入 SYN_SENT 狀態,發送一個SYN報文;
????????接收ACK響應:?確認連接建立,進入 ESTABLISHED 狀態,開始數據的雙向傳輸。
②?連接接收方(服務器)
????????初始狀態:LISTEN(監聽狀態)
????????接收SYN請求:?進入 SYN_RCVD 狀態,并發送一個帶有SYN和ACK標志的響應報文(SYN-ACK),表示同意建立連接。
????????等待確認:?收到客戶端的確認ACK報文后,連接成功建立,進入 ESTABLISHED 狀態,開始數據的雙向傳輸。
三次握手過程狀態變化圖
- 客戶端(發起方):
CLOSED
→SYN_SENT
→ESTABLISHED
- 服務器(接收方):
LISTEN
→SYN_RCVD
→ESTABLISHED
連接斷開(TCP四次揮手)?
① 連接斷開發起方(客戶端/服務器)
1. 初始狀態:ESTABLISHED(已建立連接);
2. 發送FIN請求:此時,該端點的寫端被關閉,進入 FIN_WAIT_1 狀態;
3. 等待ACK響應: 主動關閉方在 FIN_WAIT_1 狀態等待接收方的ACK報文確認其斷開請
4. 等待接收方的FIN:?此時,主動關閉方進入 TIME_WAIT 狀態,等待足夠的時間確保接收方收到了最后的ACK報文。
②?連接斷開接收方(服務器/客戶端)
1. 初始狀態:ESTABLISHED(已建立連接);
2. 接收FIN請求: 被動關閉的一方在 ESTABLISHED 狀態收到主動關閉方的FIN報文后,進入 CLOSE_WAIT 狀態,表示確認收到對方的斷開請求,并準備關閉自己的寫端。
3. 發送ACK響應: 被動關閉方發送ACK報文,確認收到對方的FIN報文。此時,它的寫端被關閉,但接收端仍然保持開放,允許接收剩余的數據。
4. 發送FIN: 當被動關閉方完成數據接收后,主動發送帶有FIN標志的報文,表示自己也沒有數據要發送了,進入 LAST_ACK 狀態。
5. 等待確認: 被動關閉方等待對方的ACK確認,確認連接完全斷開后,進入 CLOSED 狀態。
四次揮手過程狀態變化圖
- 主動關閉方:
ESTABLISHED
→FIN_WAIT_1
→FIN_WAIT_2
→TIME_WAIT
→CLOSED
- 被動關閉方:
ESTABLISHED
→CLOSE_WAIT
→LAST_ACK
→CLOSED
🔖滑動窗口
基于確認應答機制,如果每發送一次報文,都需要等待應答,收到ACK后再發送下一個報文,這樣做會大大影響性能。于是我們可以一次性發送多個報文,并且同時等待多個應答,因為發送的報文是基于序列號順序發送的,所以可以看作一個滑動窗口,窗口內部是已發送但還未收到應答的報文,當收到應答后,右移窗口的左端;發送新報文后,右移動窗口右端。這就是滑動窗口機制。
?如果在發送過程中出現丟包,該如何解決?這里分兩種情況:
① 數據包已抵達,但ACK丟了。這種情況下,基于超時重傳機制,發送方會重新發送數據包,直到接收到相應的ACK為止
② 數據包丟失了。例如,發送方一共發送了序列號為1~5000的數據包,但是當中1001~2000的數據包丟失了,其余的沒有丟失。在這種情況下,接收方返回的確認序列號會一直為1001,表示1001開頭的報文沒有收到,此時發送方得知后會重新發送1001~2000的數據包,此時接收方返回的確認序列號為5001(因為2001~5000的數據包已經收到了)。
這種機制被稱為“高并發重傳機制”。
🔖流量控制
接收方收到數據包后時并不會立即處理,而是暫存在接收緩沖區中,而緩沖區的空間時有限的,這就意味著如果發送方一次性發送過多數據包,就會出現由于緩沖區空間不足而丟包的情況。?為了避免這種情況的發送,發送方就需要控制發送速度,就需要借助流量控制機制。
控制速度的依據是接收方的緩沖區剩余空間大小,而發送方該怎么得知這一信息呢,就需要借助TCP報文段中的“窗口大小”字段。
接收方依據緩沖區剩余空間,設置窗口大小并通過ACK應答報文告知發送方,如果窗口大小變小,發送方就會減緩發送速度;如果窗口大小為0,發送方就停止發送數據,但是會時不時發送窗口探測,用于探測請求接收方窗口更新。
?即使發送方不進行窗口探測,接受方在緩沖區有空間剩余之后還是會發送窗口更新報文,但是為什么發送方還是需要時不時進行探測呢?
?因為接收方的窗口更新報文有可能丟失,如果發送方不探測,接收方就不會重傳
🔖擁塞控制
基于流量控制機制,發送方在數據發送的過程中可以很好地控制速度,但是還存在一個問題,那就是在剛建立通信連接,第一次發送數據時,并不知道接收方的緩沖區情況,此時并不能確定該發送多少數據。于是TCP引入慢啟動機制,即一開始只發送少量數據,目的是探測對方的“吞吐量”大小,清楚情況后,再決定用什么速度傳輸數據。
那么這個傳輸速度具體該如何確定呢?這里要引入“擁塞窗口”的概念:
數據發送開始時,擁塞窗口為1;此后每收到一個ACK,擁塞窗口加1,并取擁塞窗口與ACK中窗口大小的較小值作為本次發送數據的大小。
如此一來,數據發送速率是呈指數級增長的,但是這到了后面,速度會變得很不可控,并且很大概率會出現丟包(發送速度過快),因此要對速度進行限制,就需要借助“慢啟動閾值”這一概念。
當擁塞窗口超過閾值時,就不再按指數級增長,而是按線性增長。這個閾值初始為窗口最大值,之后每發送一次超時重傳,閾值變為原來的一半,并且擁塞窗口置為1(將閾值慢慢逼近一個合理值,既保證了傳輸效率,又減少了出現丟包的可能性)
🔖延遲、捎帶應答
接收方在ACK應答的同時,也在處理緩沖區的數據,也就是說,如果ACK立即應答,其時效性會比較低下(剩余空間遠大于窗口值,因為一部分數據已被處理),于是TCP引入了延遲應答機制。接收方在接收數據之后,會等待一段時間再發送ACK應答,這樣在一定程度上可以確保窗口大小的時效性。
基于延遲應答,接收方的數據包發送和ACK應答可以共用一個數據段,這樣可以大大節約資源,第二次握手就是很好的例子。?
📖3.總結
TCP協議通過以上多種機制確保了數據傳輸的可靠性,并且通過一系列優化手段提升傳輸性能。因此,以上機制可以大致分為兩類:可靠性機制和性能優化機制。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?可靠性機制 | ? ? ? ? ? ? ? ? ? ? ? ? ? 性能優化機制 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 校驗和 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?滑動窗口 |
? ? ? ? ? ? ? ? ? ? ? ? 序列號(按序到達) | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?快速重傳 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?確認應答 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?延遲應答 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?超時重發 | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?捎帶應答 |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?連接管理 | |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?流量控制 | |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?擁塞控制 |
以上就是【深入拆解TCP核心機制與UDP的無狀態設計】的全部內容,歡迎指正~?
碼文不易,還請多多關注支持,這是我持續創作的最大動力!