自頂向下 | 帶你遨遊運輸層
- 2020 年 3 月 18 日
- 筆記
前言
本文已經收錄到我的
Github
個人部落格,歡迎大佬們光臨寒舍:
學習導圖:
一.運輸層概述
- 運輸層為運行在不同主機上的應用程式之間提供邏輯通訊
- 應用報文加上運輸層首部形成運輸層報文段,報文段通過網路層被封裝成網路層分組(數據報)向目的地發送
Q1:運輸層和網路層的關係
- 運輸層:運行在不同主機上的應用程式之間提供邏輯通訊
- 網路層:提供主機之間的通訊
舉個例子來說明兩者關係:
有兩個家庭,一家位於廣州,一家位於北京,每家有 3個孩子。這兩個家庭的孩子們喜歡彼此通訊,每封信都用單獨的信封通過傳統的郵政服務發送。每個家庭有一個孩子負責收發郵件,北京家庭是 阿京,而廣州家庭是 阿州。每周阿京去她所有的兄弟姐妹那裡收集郵件,並將這些郵件交到郵遞員處上。當信件到達北京家庭時,阿京也負責將信件發到她的兄弟姐妹手上,廣州家庭中 阿州也負責類似工作
- 網路層——郵遞員
- 運輸層——阿京和阿州
- 應用程式——兄弟姐妹
- 主機——兩個家庭
通過運輸層協議,兩台電腦彷彿直接相連一樣。應用無需知道底層內部實現的原理和細節,比如怎麼把遠隔世界兩地電腦上的數據進行相互傳輸
Q2:注意點
- 運輸層協議僅僅實現在網路的邊緣處,例如主機,電腦,手機等。如路由器,交換機這些網路核心設備,是沒有實現運輸層協議的
- 每一層協議僅僅檢查分組相應的協議層欄位
- 最常用的兩種輸入層協議,
TCP
和UDP
- 運輸層的下面是網路層,網路層的目的在於為不同的主機提供邏輯通訊,而非主機上的進程
- 網路層常用協議是
IP
,其提供的是一種不可靠的數據傳輸服務 - 為了做到為不同主機 (
host
) 上的應用或者說進程提供邏輯通訊這一目的,運輸層協議必須能分辨出數據的來源和去向。為此,運輸層存在著兩種行為,多路復用和多路分解
二.多路復用與多路分解
- 多路復用:當運輸層收到來自上方應用層的數據時,運輸層會為數據封上一些頭部資訊,根據所有協議不同,封上的資訊也不一樣
用上面的兩個家庭的例子進行形象化地闡述就是:多路復用就是阿州和阿京將兄弟姐妹的信一起交給郵遞員
- 多路分解:當運輸層收到下方網路層傳輸來的數據時,運輸層會檢查多路復用時封上的資訊,從而正確的把數據定向到相應的進程
Q1:如何使用運輸層的協議?
作業系統提供了被稱為 socket
的介面 api
供編程人員調用,對 socket
的形象理解是其是一種抽象,將複雜的實現 (tcp/udp
) 協議的各種行為抽形成簡單的幾個函數給開發人員使用。就像瀏覽器將發送請求報文這一 http
協議規定的行為,抽象成我們只需要輸入 url
然後回車即可
這裡需要注意的一點是:
- 在一般情況下,一個電腦埠只能被一個進程佔用
- 一個進程可以創建多個
Socket
,多個TCP
Socket
可以監聽同一個埠,並保證接受的數據依舊是正確的 - 多個
UDP Socket
就無法監聽同一埠 -
這其中的差異源於
TCP
和UDP
協議的不同TCP
是面向連接的,其有足夠狀態的資訊來分辨數據來源,後定向到正確的socket
UDP
不需要維持連接,僅僅通過埠號來決定數據的去向,所以會導致衝突
三.UDP
和TCP
的多路復用和分解
Q1:UDP
的多路復用和分解
一個 UDP Socket
通過一個二元組 (目的 IP
地址,目的埠號) 來標識,當輸入層收到數據時,通過檢查這個二元組,來定向數據該去往哪一個 UDP Socket
。這也是多個 UDP Socket
無法監聽同一個埠的原因
Q2:TCP
的多路復用分解
一個 TCP Socket
通過一個四元組 (源 IP
,源埠,目的 IP
,目的埠號) 來標識,這也解釋為什麼多個 TCP Socket
可以監聽同一個埠,儘管目的 IP
和目的埠號是一樣的,但是源 IP
和源埠的組合總是不同的
四.UDP
4.1 UDP
基本概念
相比於 TCP
來講,UDP
是一個簡單的協議,就是把網路層 IP
提供的服務封裝了下,實現了多路復用和分解,提供了端到端進程間的通訊和錯誤檢驗服務
相對於 TCP
來說:
缺點:
UDP
是不可靠的傳輸服務- 沒有流量和擁塞控制
優點:
- 能夠夠精細的控制數據的發送時間和速率
- 無需事先建立連接
- 無連接狀態
- 分組首部開銷小
UDP
報文端結構:
- 源埠號:發送方的埠號
- 目的埠號:接收方埠號
- 長度:包括首部在內的報文長度
- 檢驗和:用來差錯檢驗。只發現錯誤不糾正,錯了就扔。然後重發
4.2 可靠數據傳輸
Q1:數據傳輸可能遇到的問題:
- 傳輸中數據被損壞
- 數據丟失
- 數據可能亂序到達
Q2:解決方法:
- 檢驗和
- 序號
- 定時器
- 肯定和否定回饋分組
Q3:如何在保證可靠性的前提下,提高其性能?
- 通過引入流水線 (
pipelining
) 技術
引入流水線導致了:
- 序號範圍需要增加
- 收發雙方可能需要快取亂序到達的分組
- 以上兩個的具體實現取決於傳輸協議如何處理分組丟失、損壞的問題 (是選擇回退 N 步,還是選擇重傳)
Q4:如何處理分組丟失、損壞的問題
A.回退 N
步
- 其核心在於,發送方會維持一個窗口,發送方能發送的數據量取決於窗口長度,並且當丟失時會重送所有未確認的分組
-
接收方會丟棄亂序到達的快取
-
特點:
1.累計性
ACK
2.單一定時器
B.選擇重傳
- 核心在於,收發雙方都會維持一個窗口,並且儘力保證窗口的狀態是同步的,因此當分包丟失時,發送方只會重送丟失的分組
-
接收方會快取亂序到達的分組
-
特點:
1.獨立性
ACK
2.多個定時器
五.TCP
5.1 TCP
基本概念
A.特點:
- 面向連接
- 全雙工的
- 點對點,不存在一次發送將數據傳遞給多個接收方、
- 在合適的時候發送 發送快取 里的數據
- 為每個數據封上一個
TCP
頭部 TCP
連接的每一端都具有發送快取和接受快取
B.報文段結構
部分參數解釋:
-
序號 (
seq
) :所帶數據的第一個比特的序號,同時也是接收方期待的序號,等於接收方回復報文中的ACK
(n) 中的 n -
確認號 (
ack
) : 對於一個ACK
(n) 來說,告訴對方 n-1 前的數據已經收到,下一次期待的序列號為 n -
ACK
:指示,用於指示報文中確認號欄位的值是有效的 -
PSH
:指示,立即發送_發送快取_里的數據 -
RST
:指示,用於強制關閉連接 -
SYN
: 指示,用於握手階段也就是建立連接的階段 -
FIN
:指示,用於正常關閉連接 -
接受窗口 :用於
TCP
的流量控制功能
5.2 可靠數據傳輸
-
TCP
協議為數據的每一Byte
都編號,而非針對報文段 -
總是維持最老未經確認的 1
Byte
的計時器 -
每一次超時重置的計時器時間會加倍
-
其錯誤恢復機制是回退 N 步和選擇重傳的混合體
- 不會丟棄亂序到達的分組,而是快取起來
- 採用累計性
ACK
- 只會重傳丟失報文段中的數據
- 快速重傳:當連續收到 4 個相同的
ACK
時 (一個正常的ACK
,三個正常ACK
的重複),會觸發快速重傳,立即重發分組
5.3 流量控制
- 為了防止過高數據流量導致接收者的接受快取爆掉,接收者會在其
TCP
報文中通過 接受窗口 指示發收者還能發送多少數據
接受窗口 (rwnd
) 公式:
rwnd = RcvBuffer - [LastByteRead - LastbyteRead]
- 且:
LastByteSent - LastByteAcked <= rwnd
5.4 TCP
連接管理
Q1:建立連接(三次握手)
- 客戶端發送
SYN
位置 1 的報文段 - 服務端返回
SYN
為 1,ACK
為 1 的報文段 - 客戶端發送
ACK
為 1,且附帶數據的報文段
形象化地理解:
TCP 三次握手
就好比兩個人在街上隔著50米看見了對方,但是因為霧霾等原因不能100%確認,所以要通過招手的方式相互確定對方是否認識自己。張三首先向李四招手(
syn
),李四看到張三向自己招手後,向對方點了點頭擠出了一個微笑(ack
)。張三看到李四微笑後確認了李四成功辨認出了自己(進入estalished
狀態)但是李四還有點狐疑,向四周看了一看,有沒有可能張三是在看別人呢,他也需要確認一下。所以李四也向張三招了招手(
syn
),張三看到李四向自己招手後知道對方是在尋求自己的確認,於是也點了點頭擠出了微笑(ack
),李四看到對方的微笑後確認了張三就是在向自己打招呼(進入established
狀態)。於是兩人加快步伐,走到了一起,相互擁抱
Q2:斷開連接(四次揮手)
- 客戶發送
FIN
為 1 的報文段 - 服務端返回
ACK
為 1 的報文段 - 服務端發送
FIN
為 1 的報文段 - 客戶端返回
ACK
為 1 的報文段 - 客戶端在一段時間後,關閉連接
形象化地理解:
張三揮手(
fin
)——李四傷感地微笑(ack
)——李四揮手(fin
)——張三傷感地微笑
六.擁塞控制
Q1:擁塞的代價
- 導致分組過長的排隊時延
- 需要重傳因快取溢出丟失的分組
- 高延時導致重送分組
- 丟包導致運輸相關分組的分組交換器所作的工作全部白費
Q2:TCP
的擁塞控制
-
TCP
採用端到端的擁塞控制 -
三個主要問題:
- 一個 TCP 的發送方如何限制自己的發送流量的速率?
通過設置一個擁塞窗口 (cwnd
), 並且保證:LastByteSent - LastByteAcked <= min{cwnd, rwnd}
- 如何感知其發送路徑擁塞了?
timeout
- 收到一次正常
ACK
後連續收到三次正常ACK
的重複
- 感到擁塞時,採用什麼樣的演算法改變發送速率?
- 慢啟動
cwnd
的值從 1 MSS
開始,並且對每一個 ACK
,cwnd
值變為原來的 2 倍,直到超過閾值 (ssthresh
),轉為擁塞避免模式
- 擁塞避免
在每一個 RRT
時間,cwnd
的值增加一個 MSS
- 快速恢復
cwnd
的值降為一半加上重複收到的重複 ACK
的數量,並且每一個 ACK
,cwnd
的值增加一個 MSS
在實踐中,一旦 timeout
就會會到慢啟動的狀態,多次重複 ACK
則會進入快速恢復狀態
Q3:TCP
公平
TCP
的公平性在於保證每個連接的吞吐量是平均的,而不是應用或進程間
七.再談握手和揮手
7.1 為啥一定要三次握手,兩次不行嗎?
弄清這個問題,我們需要先弄明白三次握手的目的是什麼,能不能只用兩次握手來達到同樣的目的。
- 第一次握手:客戶端發送網路包,服務端收到了。 這樣服務端就能得出結論:客戶端的發送能力、服務端的接收能力是正常的。
- 第二次握手:服務端發包,客戶端收到了。 這樣客戶端就能得出結論:服務端的接收、發送能力,客戶端的接收、發送能力是正常的。不過此時伺服器並不能確認客戶端的接收能力是否正常。
- 第三次握手:客戶端發包,服務端收到了。 這樣服務端就能得出結論:客戶端的接收、發送能力正常,伺服器自己的發送、接收能力也正常。
因此,需要三次握手才能確認雙方的接收與發送能力是否正常。
試想如果是用兩次握手,可能會出現下面這種情況:
如客戶端發出連接請求,但因連接請求報文丟失而未收到確認,於是客戶端再重傳一次連接請求。後來收到了確認,建立了連接。數據傳輸完畢後,就釋放了連接,客戶端共發出了兩個連接請求報文段,其中第一個丟失,第二個到達了服務端,但是第一個丟失的報文段只是在某些網路結點長時間滯留了,延誤到連接釋放以後的某個時間才到達服務端,此時服務端誤認為客戶端又發出一次新的連接請求,於是就向客戶端發出確認報文段,同意建立連接,不採用三次握手,只要服務端發出確認,就建立新的連接了,此時客戶端忽略服務端發來的確認,也不發送數據,則服務端一致等待客戶端發送數據,浪費資源
7.2 為啥揮手要四次?
這是因為服務端在LISTEN
狀態下,收到建立連接請求的SYN
報文後,把ACK
和SYN
放在一個報文里發送給客戶端。而關閉連接時,當收到對方的FIN
報文時,僅僅表示對方不再發送數據了但是還能接收數據,所以服務端可以立即close
,也可以發送一些數據給客戶端後,再發送FIN
報文給客戶端來表示同意現在關閉連接,因此,服務端ACK
和FIN
一般都會分開發送。
如果文章對您有一點幫助的話,希望您能點一下贊,您的點贊,是我前進的動力
本文參考鏈接:
- 《電腦網路-自頂向下方法》
- 面試官,不要再問我三次握手和四次揮手
- TCP的三次握手四次揮手
- 跟著動畫來學習TCP三次握手和四次揮手
- 第三章-運輸層-閱讀筆記
- 第三章:運輸層 |《電腦網路:自頂向下方法》