寫在前面
計算機網路分了五層(應用層,運輸層,網路層,鏈路層,物理層),《自頂向下》的第三章詳細講解了運輸層的兩大協議以及其背後原理,其中tcp協議是本章乃至整個計算機網路的一個重點內容,鑑於此,我覺得有必要對本章作個筆記,以鞏固運輸層的知識。
正文
運輸層的目的在於為不同主機(host)上的應用或者說程式提供邏輯通訊——通過運輸層協議,兩臺電腦彷彿直接相連一樣。應用無需知道底層內部實現的原理和細節,比如怎麼把遠隔世界兩地電腦上的資料進行相互傳輸。
本章的一些注意點:
- 運輸層協議僅僅實現在網路的邊緣處,例如主機,電腦,手機等。如路由器,交換機這些網路核心裝置,是沒有實現運輸層協議的
- 每一層協議僅僅檢查分組相應的協議層欄位
- 最常用的兩種輸入層協議,tcp和udp
- 運輸層的下面是網路層,網路層的目的在於為不同的主機提供邏輯通訊,而非主機上的程式
- 網路層常用協議是IP,其提供的是一種不可靠的資料傳輸服務
- 為了做到為不同主機(host)上的應用或者說程式提供邏輯通訊這一目的,運輸層協議必須能分辨出資料的來源和去向。為此,運輸層存在著兩種行為,多路複用和多路分解
多路複用
當運輸層收到來自上方應用層的資料時,運輸層會為資料封上一些頭部資訊,根據所有協議不同,封上的資訊也不一樣。這一行為,被稱為多路複用。
多路分解
當運輸層收到下方網路層傳輸來的資料時,運輸層會檢查多路複用時封上的資訊,從而正確的把資料定向到相應的程式。
如何使用運輸層的協議? 作業系統提供了被稱為socket的介面api供程式設計人員呼叫,對socket的形象理解是其是一種抽象,將複雜的實現(tcp, udp)協議的各種行為抽形成簡單的幾個函式給開發人員使用。就像瀏覽器將傳送請求報文這一http協議規定的行為,抽象成我們只需要輸入url然後回車即可。
這裡需要注意的一點是,在一般情況下,一個計算機埠只能被一個程式佔用。一個程式可以建立多個socket,多個tcp socket可以監聽同一個埠,並保證接受的資料依舊是正確的。但多個udp socket就無法監聽同一埠。這其中的差異源於tcp和udp協議的不同,tcp是面向連線的,其有足夠狀態的資訊來分辨資料來源,後定向到正確的socket。但udp不需要維持連線,僅僅通過埠號來決定資料的去向,所以會導致衝突。
udp的多路複用和分解
一個udp socket通過一個二元組(目的ip地址,目的埠號)來標識,當輸入層收到資料時,通過檢查這個二元組,來定向資料該去往哪一個udp socket。這也是為什麼多個udp socket無法監聽同一個埠的原因,因為系統無法再根據二元組來確定訊息的去向(它們的二元組是一樣的)。
TCP的多路複用分解
一個tcp socket通過一個四元組(源ip,源埠,目的ip,目的埠號)來標識,這也解釋為什麼多個tcp socket可以監聽同一個埠,儘管目的ip和目的埠號是一樣的,但是源ip和源埠的組合總是不同的。
UDP
相比於TCP來講,UDP是一個簡單的協議,就是把網路層IP提供的服務封裝了下,實現了多路複用和分解,提供了端到端程式間的通訊和錯誤檢驗服務。
相對於TCP來說:
- UDP是不可靠的傳輸服務
- 沒有流量和擁塞控制
但:
- 能夠夠精細的控制資料的傳送時間和速率
- 無需事先建立連線
- 無連線狀態
- 分組首部開銷小
封裝
在接收到應用層傳輸來資料後,在資料前方加上了四個欄位,分別是源埠號、目的埠號、長度(包括頭部)、檢驗和,應用資料。
可靠資料傳輸
資料傳輸可能遇到的問題:
- 傳輸中資料被損壞
- 資料丟失
- 資料可能亂序到達
解決方法:
- 檢驗和
- 序號
- 定時器
- 肯定和否定反饋分組
如何在保證可靠性的前提下,提高其效能?
- 通過引入流水線(pipelining)技術
引入流水線導致了:
- 序號範圍需要增加
- 收發雙方可能需要快取亂序到達的分組
- 以上兩個的具體實現取決於傳輸協議如何處理分組丟失、損壞的問題(是選擇回退N步,還是選擇重傳)
回退N步
其核心在於,傳送方會維持一個視窗,傳送方能傳送的資料量取決於視窗長度,並且當丟失時會重送所有未確認的分組。
接收方會丟棄亂序到達的快取
特點:
- 累計性ACK
- 單一定時器
選擇重傳
核心在於,收發雙方都會維持一個視窗,並且盡力保證視窗的狀態是同步的,因此當分包丟失時,傳送方只會重送丟失的分組。
接收方會快取亂序到達的分組
特點:
- 獨立性ACK
- 多個定時器
TCP
特點:
- 面向連線
- 全雙工的
- 點對點,不存在一次傳送將資料傳遞給多個接收方、
- 在合適的時候傳送 傳送快取 裡的資料
- 為每個資料封上一個TCP頭部
- TCP連線的每一端都具有傳送快取和接受快取
報文段結構
-
源埠號
-
目的埠號
-
序號(seq) - 所帶資料的第一個位元的序號,同時也是接收方期待的序號,等於接收方回覆報文中的ACK(n)中的n
-
確認號(ACK) - 對於一個ACK(n)來說,告訴對方n-1前的資料已經收到,下一次期待的序列號為n
-
首部長度
-
URG
-
ACK - 指示,用於指示報文中確認號欄位的值是有效的
-
PSH - 指示,立即傳送傳送快取裡的資料
-
RST - 指示,用於強制關閉連線
-
SYN - 指示,用於握手階段也就是建立連線的階段
-
FIN - 指示,用於正常關閉連線
-
接受視窗 - 用於TCP的流量控制功能
-
因特網檢驗和
-
緊急資料指標
-
選項
-
應用資料
可靠資料傳輸
- TCP協議為資料的每一Byte都編號,而非針對報文段
- 總是維持最老未經確認的1 Byte的計時器
- 每一次超時重置的計時器時間會加倍
- 其錯誤恢復機制是回退N步和選擇重傳的混合體
- 不會丟棄亂序到達的分組,而是快取起來
- 採用累計性ACK
- 只會重傳丟失報文段中的資料
快速重傳
當連續收到4個相同的ACK時(一個正常的ACK,三個正常ACK的重複),會觸發快速重傳,立即重發分組
流量控制
為了防止過高資料流量導致接收者的接受快取爆掉,接收者會在其tcp報文中通過 接受視窗 指示發收者還能傳送多少資料
接受視窗(rwnd)公式:
- rwnd = RcvBuffer - [LastByteRead - LastbyteRead]
- 且:LastByteSent - LastByteAcked <= rwnd
TCP連線管理
建立連線(三次握手)
- 客戶端傳送SYN位置1的報文段
- 服務端返回SYN為1,ACK為1的報文段
- 客戶端傳送ACK為1,且附帶資料的報文段
斷掉連線
- 客戶傳送FIN為1的報文段
- 服務端返回ACK為1的報文段
- 服務端傳送FIN為1的報文段
- 客戶端返回ACK為1的報文段
- 客戶端在一段時間後,關閉連線
擁塞控制
擁塞的代價
- 導致分組過長的排隊時延
- 需要重傳因快取溢位丟失的分組
- 高延時導致重送分組
- 丟包導致運輸相關分組的分組交換器所作的工作全部白費
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則會進入快速恢復狀態
TCP公平
TCP的公平性在於保證每個連線的吞吐量是平均的,而不是應用或程式間。