前言
正在學習計算機網絡這門課程,順便做個筆記,記錄一下知識點。
參考資料:
中科大鄭烇老師全套《計算機網絡(自頂向下方法 第7版,James F.Kurose,Keith W.Ross)》課程:https://www.bilibili.com/video/BV1JV411t7ow?p=1
《計算機網絡(自頂向下方法 第7版,James F.Kurose,Keith W.Ross)》
第三章:傳輸層
概述和傳輸層服務
傳輸層為運作在不同主機上的應用程序提供邏輯通信服務(以封包為機關)。
提供程序-程序之間的通信
傳輸協定運作在端系統中:
- 發送方:将應用層的封包分成封包段(添加段頭,形成本層資料單元),然後傳遞給網絡層。
- 接收方:将封包段重組成封包(去掉段的頭部資訊,取出段的内容),然後以位元組流的形式傳遞給應用層
傳輸層向上層提供多種協定:
- Internet: TCP和UDP
傳輸層VS網絡層
網絡層服務:主機之間的邏輯通信。
傳輸層服務:程序間的邏輯通信。(主機之間服務的細分)
- 依賴于網絡層的服務:延時、帶寬。
- 對網絡層的服務進行增強:資料丢失、順序混亂、加密。
- 有些服務是不可以加強的:帶寬、延遲。
-
傳輸層向上層提供的服務其中很重要的一個功能就是複用(源端)以及解複用(目标端)。(後文詳細介紹)
下面舉個例子來說明傳輸層的服務:
假設Ann家與Bill家各有12個小孩,定期,各家的12個小孩會向對方家的12個小孩進行書信往來。那麼一次單向通信就需要12×12=144封信件。現在假定是Ann家的孩子們向Bill家的孩子們發送信件。但是一封一封的發送過于繁瑣,孩子們會這樣解決問題:由Ann家的老大将信件全部收集起來,打包一起發送到Bill家。Bill家的老大收到信件後就會分發給不同的孩子。
在這個例子中:
- 兩個家庭 = 于兩個主機
- 每個小孩 = 不同的程序
- 信封中的信件 = 應用層封包
- Ann和Bill = 傳輸協定:
- Ann将信件打包的過程(聚合) = 複用
- Bill将打包的信件分發(拆分) = 解複用
- 送信的郵件服務 = 網絡層協定
Internet傳輸層協定:
- TCP:可靠的、保序的傳輸(提供位元組流的服務)
- 多路複用、解複用
- 擁塞控制
- 流量控制
- 建立連接配接
- UDP:不可靠、不保序的傳輸(提供資料報的服務)
- 多路複用、解複用
- 沒有為盡力而為的IP服務添加更多的其它額外服務
二者都是在IP提供的服務的基礎之上提供服務(IP提供的服務:best effort)
二者都不能提供的服務:
- 延時保證
- 帶寬保證
多路複用與解複用
我們已經知道,IP向傳輸層提供的提供的服務是主機-主機的,而傳輸層提供的服務是程序-程序的,如何在傳輸層實作這一細分的服務的實作,所依靠的就是端口号。
此外:引入Socket的目的就是使層間傳遞的資料盡可能少。
TCP和UDP都分别有各自的端口号,但二者使用端口的方式并不一樣。
先來描述述一下多路複用/解複用的概念:
-
在發送方主機多路複用:
從多個套接字接收來自多個程序的封包,根據套接字對應的IP位址和端口号等資訊對封包段用頭部加以封裝 (該頭部資訊用于以後的解複用)
-
在接收方主機多路解複用:
根據封包段的頭部資訊中的IP位址和端口号将接收到的封包段發給正确的套接字(和對應的應用程序)
TCP的多路複用/解複用
之前我們介紹過,TCP的Socket和四元組相捆綁,代表兩個程序之間的會話關系。
四元組包含:源端IP,源端程序端口;目标端IP,目标端程序端口。
發送方複用:
- 應用層将程序的資訊向傳輸層傳遞,其中包含兩個部分:
和Socket
。Message
- Socket包含源端程序端口以及目标端程序端口,這時就會将這兩個端口封裝在封包段(Segment)中(這裡還會封裝一些其他資訊,我們先不考慮)。段以及源端IP和目标端IP再向下層網絡層傳輸。
- 網絡層接收來自上層的段以及IP資訊,并進行封裝。由此便可以借助下層提供的服務将其傳輸道目标主機。
接收方解複用:
- 網絡層接收到傳輸來的分組,把頭部資訊去掉,剩下的段的部分交給傳輸層。
- 傳輸層得到段可以通過頭部資訊知道源端IP、源端程序端口、目标端IP以及目标端程序端口。并可以将資訊繼續向應用層傳遞,交給對應的程序。

補充:
伺服器能夠在一個TCP端口上同時支援多個TCP套接字。
Web伺服器對每個連接配接用戶端有不同的套接字。
UDP的多路複用/解複用
UDP的Socket和二進制組相捆綁。
二進制組包含:本地IP,本地程序端口。
發送方複用:
- 應用層将Message、Socket與目标IP和目标程序端口向傳輸層傳遞(注意UDP Socket同TCP不同,不包含目标IP與目标程序端口)。
- 傳輸層将源程序端口以及目标程序端口封裝在頭部,形成封包段,向網絡層傳遞。
- 網絡層繼續将源IP和目标IP封裝起來形成資料報(datagram),并借助下層提供的服務将其傳輸道目标主機。
接收方解複用:
- 網絡層接收到傳來的資料報,把頭部資訊去掉,将封包段以及目标IP和目标程序端口向傳輸層傳遞。
- 傳輸層接收下層傳來的資訊,繼續解封裝,将資料向應用層傳遞,交給對應的程序。
補充:
傳輸層TCP/UDP封包段格式:
對于UDP的多路解複用:如果兩個不同源IP位址/源端口号的資料報,但是有相同的目标IP位址和端口号,則被定位到相同的UDP套接字,發給同一個應用程序。(這點同TCP不一樣)
是以可以這樣記憶:不管是TCP四元組還是UDP二進制組,必須元組内資訊全部一緻,才會對應同一個Socket,發送給同一個程序。
無連接配接傳輸:UDP
UDP在IP提供的服務之上并沒有增加過多的額外的服務,僅增加了多路複用/解複用。是以UDP也是“盡力而為”的服務。并可能發生如下問題:
- 資料丢失
- 送到應用程序的封包段亂序
UDP的另一個特征就是無連接配接:
- UDP發送端和接收端之間沒有握手
- 每個UDP封包段都被獨立地處理
UDP被用于:
- 流媒體(丢失不敏感,速率敏感、應用可控制傳輸速率)
- 事務性的應用(僅一次通信)
- DNS
- SNMP(簡單的網絡管理協定)
如果想使用UDP協定,同時又希望具有可靠性,那麼這種可靠性服務隻能由程序本身(應用層)提供。可以應用特定的差錯恢複。
UDP封包段格式:
頭部為8Byte,包括:源端口号、目标端口号、長度(包括頭部在内的整個封包段的長度)、校驗和(checksum)。(均為2Byte)
UDP存在的必要性:
- 不建立連接配接 (會增加延時)。
- 簡單:在發送端和接收端沒有連接配接狀态(伺服器無需維護用戶端狀态,用戶端也無需維護與源端某一程序的通訊狀态)。
- 封包段的頭部很小(開銷小)。是以一個封包段的載荷(應用程式資料)就比較大。
- 無擁塞控制和流量控制:UDP可以盡可能快的發送封包段。
UDP校驗和
校驗和的目的:檢測在被傳輸封包段中的差錯 (如比特反轉)。
發送方:
- 将封包段的内容視為16bit的整數
- 校驗和:封包段的加法和(1的補運算)
- 發送方将校驗和放在UDP的校驗和字段
接受方:
- 計算接收到的封包段的校驗和
- 檢查計算出的校驗和與校驗和字段的内容是否相等:
- 不相等——檢測到差錯(一定錯)
- 相等——一種情況是沒有差錯;另一種情況也許會出現殘存錯誤。
校驗和的具體實作:
将封包段的資料(包含一些頭部資訊),拆分成16bit一組(不足的補零)。将這些16bit的整數相加。
-
進位復原:
16bit整數相加可能會有進位,這是就把進位加到計算結果的最後一位。最後求得的校驗和是處理進位的結果的反碼。
目标端重複發送方一樣的操作,但是沒有最後的取反碼的步驟,将其計算出的結果同發送方的檢驗和相加,如果沒有差錯,應該是16位“1”(=1111111111111111),否則沒有通過校驗。
可靠資料傳輸的原理
可靠資料傳輸(Reliable data transfer,rdt)在應用層、傳輸層和資料鍊路層都很重要。(是網絡Top 10問題之一)
可靠資料傳輸的原理
rdt
需要提供的是可靠的服務(在上層),可是它卻要依賴與下層不可靠的
udt
服務(可能會丢失、可能會亂序),是以下層信道的不可靠特點決定了可靠資料傳輸協定( rdt )的複雜性。
-
和rdt_send()
是傳輸層與應用層的層間接口;deliver_data()
-
和udt_send()
是傳輸層與網絡層的層間接口。rdt_rcv()
下面我們來具體講述傳輸層是如何實作可靠傳輸機制的。
在展開講述之前先提前做個鋪墊,如何漸進式地描述這一問題:
- 先假設底層信道傳輸是可靠的(實際上并非如此),那麼上層就不需要任何機制就可以保證可靠傳輸,于是我們會将下層的可靠性一點一點剝落,同樣的上層就會相應地增加可靠傳輸機制。這便是接下來的講解思路。
- 雖然資訊傳輸是雙向流動的,但是我們可以隻考慮單向資料傳輸。(雙向的資料傳輸問題實際上是2個單向資料傳輸問題的綜合)
- 使用有限狀态機 (FSM) 來描述發送方和接收方:
- FSM(有限狀态機):實際上就是描述協定工作機制的形式化的描述方案。
節點代表狀态;邊代表節點狀态之間的遷移;邊上的标記(label):分母代表事件、分子代表采取的動作。計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記
rdt1.0:在可靠信道上的可靠資料傳輸
首先假設信道傳輸:
- 沒有比特出錯
- 沒有分組丢失
發送方:
- 應用層将資料傳送下來
- 傳輸層隻做兩件事情:
- 添加頭部資訊,封裝為包(packet)
- 借助于下層的服務将資料發送出去
接收方:
- 等待下層傳來的資料
- 傳輸層依舊隻做兩件事:
- 解封裝
- 将資料向上層傳遞
rdt1.0的FSM描述:
rdt2.0:具有比特差錯的信道
假設下層信道傳輸可能出現比特翻轉(比特差錯)
解決方案就是采用上文提到過的校驗和。
發送方在向接收方發送資料時,會采用校驗和來判斷資料傳輸有無差錯,并且接收方會有一個回報機制:
- 确認(ACK):如果通過了校驗和,接收方會發送ACK資訊,顯式地告訴發送方分組已被正确接收。
- 否定确認( NAK):如果未通過校驗和,接收方會發送NAK資訊,顯式地告訴發送方分組發生了差錯。接着發送方會重新發送分組。
發送方會有一個緩存,以便發送分組失敗後可以重新将分組發送給接收方。
發送方:
- 接收來自上層的資料
- 計算校驗和并封裝為packet;借助下層的服務将資料發送出去
- 轉變為等待ACK/NAK的狀态:
- 如果接收到NAK資訊,重新發送packet,并繼續維持等待狀态
- 如果接收到ACK資訊,轉為接收上層資訊并發送資料的狀态
接收方:
- 接收下層傳來的packet,并計算校驗和:
- 如果通過(未腐敗的(notcorrupt))校驗和,解封裝,将資料向上層傳遞,向并發送方發送ACK确認資訊
- 如果為通過(腐敗的(corrupt))校驗和,則向發送方發送NAK資訊
rdt2.0的FSM描述:
rdt2.1:停止等待協定
停等協定:發送方發送一個分組,然後等待接收方的應答。(一次隻發送一個等待确認資訊)
我們仔細思考就會察覺,rdt2.0有一個緻命的錯誤:如果接收方的回報資訊(ACK/NAK)發生了差錯該如何處理?
理想很豐滿,現實很骨感。接受方說:“正确收到”,那麼發送方繼續傳送下一個包;接收方說:“發生錯誤”,則發送方重新傳包。就怕接收方來了一句:“歪比巴蔔”,這就容易給發送方整懵了。
是以說rdt2.0的協定機制并不完備。
為此引入新的機制:序号(sequence number)
停等協定由于一次隻發送一個等待确認的資訊,是以隻需要一位就可以識别(0、1)排序。
發送方:
- 會在每一個分組中添加序号(P0、P1)
- 如果發送方接收到的回報資訊出錯(無法識别),無論是ACK還是NAK,發送方都會重新發送舊的分組。
接收方:
- 如果是NAK出錯,那麼正好接收來重新傳送的分組,如果通過校驗,發送ACK确認資訊;否則發送NAK。
- 如果是ACK出錯,那麼這時接收方就會收到重複的分組,由于分組增添了序号,那麼接收方會将該分組丢掉,不再向上層傳遞。接着會向發送方發送ACK确認資訊,以請求發送後續分組。
rdt2.1的FSM描述:
- 發送方處理出錯的ACK/NAK
- 接收方處理出錯的ACK/NAK
注意:
rdt2.1中,接收方并不知道發送方是否正确收到了其ACK/NAK資訊(沒有安排确認的确認)。
那考慮是否在發送方安排确認的确認機制呢?那麼如此我們如何判斷确認的确認是否正确。是以事實上這樣的“套娃”設計意義并不大,并不能完美的解決問題。
rdt2.2:無NAK的協定
- 功能同rdt2.1,但隻使用ACK(ack需要編号)
-
接收方對最後正确接收的分組發ACK,以替代NAK。
接收方必須顯式地包含被正确接收分組的序号。
用情商課堂的方式了解很簡單:當發送方發送了編号為1的分組(這時它應該等待ACK1)
- 低情商:接收方發來了NAK資訊→1号分組出錯了
- 高情商:接收方發來了ACK0→1号分組出錯了
- 這就為之後的流水線協定做好了基礎(一次發送多個資料機關)。
- 使用對前一個資料機關的ACK,代替本資料機關的NAK
- 這樣可以使确認資訊減少一半,協定處理簡單
當然如果ACK資訊發送錯誤依然有可能導緻接收方接收分組重複,解決方案仍和rdt2.1是一樣的:
rdt2.2的FSM描述(部分):
rdt3.0:具有比特差錯和分組丢失的信道
假設下層的傳輸信道除了比特差錯之外還可能丢失分組。
如果出現了分組丢失的情況:一方面接收方在等待分組,另一方面發送方在等待确認資訊。是以會出現死鎖的情況。(rdt2.2還無法處理這種情況)
是以會引入新的機制:逾時重傳
- 需要
(倒計時定時器)countdown timer
發送方會等待ACK資訊一段合理的時間,如果在這段時間内沒有收到ACK資訊,就會重新傳輸分組(一旦逾時,發送方就會認為分組已經丢失)。
合理的時間:
- 傳輸層timeout時間是适應式的
- 鍊路層的timeout時間确定的
接下來會有新的問題:如果隻是發送方的ACK資訊丢失,或者隻是分組(或ACK資訊)被延時,那麼就會導緻接收方收到的分組重複。這個問題在rdt2.1中就已經解決。
rdt3.0的FSM描述(發送方):
rdt3.0的運作:
- 過早逾時(延遲的ACK)也能夠正常工作;但是效率較低,一半的分組和确認是重複的(逾時之後的分組和ACK都是發送兩次的);
- 是以設定一個合理的逾時時間也是比較重要的。
rdt3.0的性能:
rdt3.0可以工作(功能比較完備),但鍊路容量比較大的情況下,性能很差。
鍊路容量比較大,一次發一個PDU 的不能夠充分利用鍊路的傳輸能力。
舉個例子:A地到B地相距甚遠,驅車從A地到B地需要很長的時間,但是停等協定隻允許高速公路上一次跑一輛汽車(實際上高速公路可以容納很多車輛)。是以鍊路越大,停等協定對鍊路的使用率就越低。
即:網絡協定限制了實體資源的利用。
具體可以舉例計算(如下圖):
流水線協定(Pipelined protocols)
為了提高鍊路使用率,接下來就引入了流水線的方式。
上文提到造成鍊路使用率低下的原因是停等協定每次隻允許發送一個分組,那麼我們就可以考慮一次發送多個分組以提高使用率,但是這個值并不會增加到100%,随着能夠同時發送分組的數量的增加,到了後期瓶頸就由停等協定轉移到了鍊路帶寬。
流水線協定:允許發送方在未得到對方确認的情況下一次發送多個分組。
- 必須增加序号的範圍:用多個bit表示分組的序号
- 在發送方/接收方要有緩沖區:
- 發送方緩存:未得到确認,可能需要重傳;
- 接收方緩存:上層使用者取用資料的速率 ≠ 接收到的資料速率;接收到的資料可能亂序,排序傳遞(可靠)
有兩種通用的流水線協定:
- Go-back-N:回退N(GBN)
- Selective Repeat:選擇重傳(SR)
在介紹以上兩種協定時我們先做一些鋪墊,先來介紹一個通用協定:滑動視窗(slide window)協定
該協定根據發送方以及接收方視窗大小的不同可以分為:
- 停止等待協定:send_window = 1, receive_window = 1
- 回退N協定:send_window > 1,receive_window = 1
-
選擇重傳協定:send_window > 1,receive_window > 1
發送方視窗(send_window)大于1的協定我們就稱之為流水線協定。
發送緩沖區:
- 形式:記憶體中的一個區域,落入緩沖區的分組可以發送
- 功能:用于存放已發送,但是沒有得到确認的分組
- 必要性:需要重發時可用
- 發送緩沖區的大小:一次最多可以發送多少個未經确認的分組
- 停止等待協定 = 1
- 流水線協定 > 1,合理的值,不能很大,鍊路使用率不能夠超100%
- 發送緩沖區中的分組:
- 未發送的:落入發送緩沖區的分組,可以連續發送出去;
- 已經發送出去的、等待對方确認的分組:發送緩沖區的分組隻有得到确認才能删除
發送視窗:
- 指的是發送緩沖區的一個範圍(是發送緩沖區的一個子集)。
- 存放已發送但是未确認的分組。(實際上發送傳視窗是那些已發送但是未經确認分組的序号構成的空間)
- 發送視窗的最大值 ≤ 發送緩沖區的值
- 發送視窗的滑動過程:
- 一開始:沒有發送任何一個分組
- 後沿 = 前沿
- 之間為發送視窗的尺寸 = 0
計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記 - 發送視窗的移動:前沿移動
- 每發送一個分組,前沿前移一個機關
- 發送視窗前沿移動的極限:不能夠超過發送緩沖區
注意:綠色部分為發送緩沖區計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記 - 發送視窗的移動:後沿移動
- 後沿移動的條件:收到老分組(後沿)的确認
- 結果:發送緩沖區罩住新的分組,來了分組可以發送
- 後沿移動的極限:不能夠超過前沿
計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記
- 一開始:沒有發送任何一個分組
接收視窗:
- 接收視窗 (receiving window) = 接收緩沖區
- 接收視窗用于控制哪些分組可以接收:
- 隻有收到的分組序号落入接收視窗内才允許接收
- 若序号在接收視窗之外,則丢棄
-
接收視窗尺寸 Wr = 1,則隻能順序接收
舉例:
- Wr=1,在0的位置;隻有0号分組可以接收
- 向前滑動一個,罩在1的位置,如果來了第2号分組,則丢棄
計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記 - 接收視窗尺寸 Wr > 1 ,則可以亂序接收(但送出給上層的分組,要按序送出)
- 滑動:
- 低序号的分組到來(按序),接收視窗移動;
- 高序号分組亂序到,緩存但不傳遞(因為要實作rdt,不允許失序),不滑動
- 發送确認:
- 接收視窗尺寸 = 1 ; 發送連續收到的最大的分組确認(累計确認)
- 接收視窗尺寸 > 1 ; 收到哪個分組,就發送那個分組的确認(非累計确認)
綠色區域表示可接收的分組。計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記 - 滑動:
正常情況下兩個視窗的互動:
- 發送視窗:
- 有新的分組落入發送緩沖區範圍,發送 → 前沿滑動
- 來了老的低序号分組的确認 → 後沿向前滑動 → 新的分組可以落入發送緩沖區的範圍
- 接收視窗:
- 收到分組,落入到接收視窗範圍内,接收
- 發送确認給發送方
- 如果低序号分組确認收到,向前滑動接收視窗
- 否則不滑動
異常情況下GBN的兩視窗互動:
- 發送視窗:
- 新分組落入發送緩沖區範圍,發送 → 前沿滑動
- 逾時重發機制讓發送端将發送視窗中的所有分組發送出去(低序号開始的連續的已發送但未确認的分組全部重新發送)
- 來了老分組的重複确認 → 後沿不向前滑動 → 新的分組無法落入發送緩沖區的範圍(此時如果發送緩沖區有新的分組可以發送)
- 接收視窗:
- 收到亂序分組,沒有落入到接收視窗範圍内,抛棄
- (重複)發送老分組的确認,累計确認
異常情況下SR的兩視窗互動:
- 發送視窗:
- 新分組落入發送緩沖區範圍,發送 → 前沿滑動
- 逾時重發機制讓發送端将逾時的分組重新發送出去
- 來了亂序分組的确認 → 後沿不向前滑動 → 新的分組無法落入發送緩沖區的範圍(此時如果發送緩沖區有新的分組可以發送)
- 接收視窗:
- 收到亂序分組,落入到接收視窗範圍内,接收
- 發送該分組的确認,單獨确認
由此我們小結一下GBN協定和SR協定的異同:
- 相同點:
- 發送視窗 > 1
- 一次能夠可發送多個未經确認的分組
- 不同點:
- GBN :接收視窗尺寸 = 1
- 接收端:隻能順序接收
- 發送端:從表現來看,一旦一個分組沒有發成功,如:0、1、2、3、4; 假如1未成功,2、3、4都發送出去 了,要傳回1再發送1、2、3、4。
- 累計确認:cumulative ack
- 發送端擁有對最老的未确認分組的定時器:
- 隻需設定一個定時器
- 當定時器到時時,重傳所有未确認分組
- 發送視窗的最大值(序号大小為n):2n-1
- SR: 接收視窗尺寸 > 1
- 接收端:可以亂序接收
- 發送端:發送0、1、2、3、4,一旦1未成功,2、3、4,已發送,無需重發,隻選擇性發送1。
- 非累計确認/獨立确認:individual ack
- 發送方為每個未确認的分組保持一個定時器:
- 當逾時定時器到時,隻是重發到時的未确認分組
- 發送視窗的最大值(序号大小為n):2n-1
- GBN :接收視窗尺寸 = 1
列出下表對比一下GBN協定和SR協定:
GBN | SR | |
---|---|---|
優點 | 簡單,所需資源少(接收方一個緩存單元) | 出錯時,重傳一個代價小 |
缺點 | 一旦出錯,回退N步代價大 | 複雜,所需要資源多(接收方多個緩存單元) |
适用範圍:
- 出錯率低:比較适合GBN,出錯非常罕見,沒有必要用複雜的SR,為罕見的事件做日常的準備和複雜處理
- 鍊路容量大(延遲大、帶寬大):比較适合SR而不是GBN,一旦出錯代價太大
面向連接配接的傳輸:TCP
TCP概述
- 點對點:一個發送方,一個接收方
-
可靠的、按順序的位元組流:沒有封包邊界
TCP不提供封包界限:發送方可能發送兩個封包,接收方可能會收到一個大的封包,也可能收到四個小的封包。應用程序之間封包的界限需要應用程序自己去維護。
- 提供管道化(流水線)的協定:
- TCP擁塞控制和流量控制設定視窗大小
- 發送和接收有緩存
- 全雙工資料:
- 在同一連接配接中資料流雙向流動(一方程序可同時發送資料和接收資料)
- 面向連接配接:在資料交換之前,通過握手(交換控制封包) 初始化發送方、接收方的狀态變量
- 有流量控制:發送方不會淹沒接收方
MSS:最大封包段大小
MTU:最大傳輸單元
TCP封包段結構
說明:
- 源端口号、目标端口号:16bit
- 序号并不是封包段的序号,而是封包段的資料載荷(body)部分的第一個位元組在整個位元組流中的偏移量。(對位元組計數)
一般情況下序号并不是從0或1這樣固定的序号開始:為了避免長時間滞留在網絡中的分組所包括的段對新的連接配接造成影響。
- 确認号:依然是位元組計數
- 如果接收方傳來的ACK為555,則表示接收方已經接收到了554及之前所有的位元組,并希望發送方下一個傳來555位元組的資料。(累計确認)
- 接收方處理亂序的封包段:可以緩存,也可以丢棄。
- 首部長度:4個位元組為機關,表示該TCP段的首部資料大小。
-
RSF(RST、SYN、FIN)标志位:主要是用于兩個應用程序進行TCP連接配接的标志位。
不同标志位的組合代表不同的握手(後面會提到),以及連接配接釋放請求、确認等。
- 接受視窗:用于流量控制。如果接收方的接收視窗為X,則表示接收方可以接收X位元組的資料。
- 校驗和:同UDP中的校驗和作用一緻。
TCP确認号和序号執行個體:
TCP往返延時(RTT)和逾時
分析可能的情況:TCP逾時應該設定的比RTT長。如果設定太短,就會發生沒必要的重傳;如果太長,那麼對封包段丢失的反應太慢。但是RTT是在不斷變化的,是以我們需要定期測量RTT。
SampleRTT:測量從封包段發出到收到确認的時間。
僅用目前的SampleRTT是不合理的,應該對幾個最近的測量值求平均。
具體公式如下:
EstimatedRTT = (1- α) × EstimatedRTT + α × SampleRTT
- 指數權重移動平均
- 過去樣本的影響呈指數衰減
- 推薦值:α = 0.125
進一步我們需要考慮EstimatedRTT的變化範圍:
- EstimtedRTT + 安全邊界時間
- EstimatedRTT變化大 (方差大) → 較大的安全邊界時間
- SampleRTT會偏離EstimatedRTT多遠:
- DevRTT = (1-β) × DevRTT + β × |SampleRTT-EstimatedRTT|
- (推薦值:β = 0.25)
由此我們可以計算逾時時間間隔:
TimeoutInterval = EstimatedRTT + 4 × DevRTT
TCP的可靠資料傳輸(rdt)
- TCP在IP不可靠服務的基礎上建立了rdt
- 管道化的封包段:GBN or SR(TCP是兩種的混合)
- 累積确認(像GBN)
- 設定單個重傳定時器(像GBN)
- 是否可以接受亂序的,TCP沒有規範。可以緩存亂序封包段,也可以丢棄。
- 通過以下事件觸發重傳:
- 逾時(隻重發那個最早的未确認段:SR)
- 重複的(三次備援)确認:
- 例子:收到了ACK50,之後又收到3個ACK50
在分析TCP如何建立rdt,我們依舊采取以上講可靠資料傳輸原理的流程,一步一步增加功能。
TCP發送方
首先考慮簡化的TCP發送方:
- 忽略重複的确認
- 忽略流量控制和擁塞控制
- TCP發送方事件:
- 從應用層接收資料:
- 用nextseq建立封包段
- 序号nextseq為封包段首位元組的位元組流編号
- 如果還沒有運作,啟動定時器
- 定時器與最早未确認的封包段關聯
- 逾時:
- 重傳後沿最老的封包段
- 重新啟動定時器
- 收到确認:
- 如果是對尚未确認的封包段确認
- 更新已被确認的封包序号
- 如果目前還有未被确認的封包段,重新啟動定時器
- 如果是對尚未确認的封包段确認
- 從應用層接收資料:
- TCP重傳(左圖為ACK丢失,右圖為ACK逾時):
(下圖為累計确認)
在RFC中對産生TCP ACK的建議(如下表)
接收方的事件 | TCP接收方動作 |
---|---|
所期望序号的封包段按序到達。 所有在期望序号之前的資料都已經被确認 | 延遲的ACK。對另一個按序封包段的到達最多等待500ms。如果下一個封包段在這個時間間隔内沒有到達,則發送一個ACK。 |
有期望序号的封包段到達。另一個按序封包段等待發送ACK(接收到連續的兩個段) | 立即發送單個累積ACK,以确認兩個按序封包段。 |
比期望序号大的封包段亂序到達。檢測出資料流中的間隔 | 立即發送重複的ACK,指明下一個期待位元組的序号 |
能部分或完全填充接收資料間隔的封包段到達。 | 若該封包段起始于間隔(gap)的低端,則立即發送ACK。 |
快速重傳
産生快速重傳的原因:逾時周期往往太長(在重傳丢失封包段之前的延時太長)。
快速重傳:在定時器過時之前重發封包段
- 由三個備援ACK觸發
它假設跟在被确認的資料後面的資料丢失了:
- 第一個ACK是正常的;
- 收到第2個該段的ACK,表示接收方收到一個該段後的亂序段;
- 收到第3,4個該段的ack,表示接收方收到該段之後的2個 ,3個亂序段,可能性非常大段丢失了
如果發送方收到同一資料 的3個備援ACK,重傳最小序号的段。
TCP流量控制
流量控制:接收方控制發送方,不讓發送方發送的太多、太快以至于讓接收方的緩沖區溢出。
- 接收方在其向發送方的TCP段頭部的
字段“通告”其rwnd
大小空閑buffer
- RcvBuffer大小通過socket選項設定 (典型預設大小為4096 位元組)
- 很多作業系統自動調整 RcvBuffer
- 發送方限制未确認(“inflight”)位元組的個數 ≤ 接收方發送過來的rwnd值
- 保證接收方不會被淹沒
連接配接管理
在正式交換資料之前,發送方和接收方握手建立通信關系:
- 同意建立連接配接(每一方都知道對方願意建立連接配接)
- 同意連接配接參數(準備、初始化資源)
建立連接配接
首先考慮2次握手總是可行的嗎?(僅一方發送連接配接請求,另一方收到後發送連接配接确認)
有很多因素會導緻2次握手的失敗:
- 變化的延遲(連接配接請求的段沒有丢,但可能逾時)
- 由于丢失造成的重傳 (e.g. req_conn(x))
- 封包亂序
- 互相看不到對方
2次握手的失敗場景:
說明
在用戶端接收伺服器發來的連接配接确認之前定時器到時,那麼用戶端就會再發送一條新的連接配接建立請求,如此伺服器會消耗資源去維護許多不必要的“半連接配接”。
資料逾時會導緻伺服器将老資料按照新的資料處理。
是以2次握手是不可取的,由此引入了3次握手。
SYNbit = 1 表示建立連接配接請求
3次握手可以有效地解決半連接配接和接收老資料的問題
3次握手的FSM表示:
關閉連接配接
- 用戶端,伺服器分别關閉它自己這一側的連接配接
- 發送FIN bit = 1的TCP段
- 一旦接收到FIN,用ACK回應
- 接到FIN段,ACK可以和它自己發出的FIN段一起發送
- 可以處理同時的FIN交換
這樣的連接配接拆除方式并不完美:
會存在一方拆除連接配接,另一方還維持連接配接的情況。
擁塞控制原理
擁塞的非正式定義: “太多的資料需要網絡傳輸,超過了網絡的處理能力。”
擁塞控制與流量控制不同:擁塞控制指的是網絡的問題,流量控制指的是接收方的問題。
擁塞的表現:
- 分組丢失 (路由器緩沖區溢出)
- 分組經曆比較長的延遲(在路由器的隊列中排隊)
擁塞是網絡中前10位的問題
産生擁塞的原因/代價
場景一:
- 2個發送端,2個接收端
- 一個路由器,具備無限大的緩沖
- 輸對外連結路帶寬:R
- 沒有重傳
- 如左圖:當λin逐漸增加時,λout也在增加,當λin達到R/2時,λout達到最大值,也就是說每個連接配接的最大吞吐量為R/2。
- 如右圖:從延遲的角度看,當進入的速率λin接近鍊路鍊路帶寬R時,延遲陡增。
場景二:
- 一個路由器,有限的緩沖
- 分組丢失時,發送端重傳
- 應用層的輸入=應用層輸出:λin = λout
- 傳輸層的輸入包括重傳:λin ≥ λout
理想化場景:發送端有完美的資訊,即發送端知道什麼時候路由器的緩沖是可用的。
- 隻在緩沖可用時發送
- 不會丢失:λ’in = λin
- 這樣情況依然同上:
- 但是這樣的代價很大:每個路由器都需要告知發送方自己的空閑緩沖區有多大,不好實作。
理想化場景二:掌握丢失資訊。即分組可以丢失,在路由器由于緩沖器滿而被丢棄。
- 如果知道分組丢失了,發 送方重傳分組
- 會丢失:λ’in > λin
分析:這樣一來,為了讓λout逼近于R/2,就需要讓λ’in比既定的輸出要大(因為存在分組丢失)。
- 重傳的丢失分組
- 沒有必要重傳的重複分組
代價:
- 為了達到一個有效輸出,網絡需要做更多的工作(重傳)
- 沒有必要的重傳,鍊路中包括了多個分組的拷貝(逾時)
- 是那些沒有丢失,經曆的時間比較長(擁塞狀态)但是逾時的分組
因為網絡擁塞而導緻接收效率降低,而為了提高接收效率,就會增加發送量,如此一來會加劇網絡擁塞,如果不加以控制,那麼網絡最終會癱瘓。這也是擁塞的特性。
場景三:
- 4個發送端
- 多重路徑
- 逾時/重傳
從宏觀上來看,各方都不停地向網絡中發送資料,就會發生網絡擁塞的一個極緻:整個網絡出現死鎖的情況
代價:當分組丢失時,任何“關于這個分組的上遊傳輸能力” 都被浪費了。
擁塞控制方法
- 端到端擁塞控制:
- 沒有來自網絡的顯式回報
- 端系統根據延遲和丢失事件推斷是否有擁塞
- TCP采用此方法
- 網絡輔助的擁塞控制:
- 路由器提供給端系統以回報資訊
- 單個bit置位,顯示有擁塞 (SNA, DECbit,TCP/IP ECN, ATM)
- 顯式提供發送端可以采用的速率
- 路由器提供給端系統以回報資訊
首先來了解網絡輔助的擁塞控制,以 ATM ABR 擁塞控制為例
ABR: available bit rate: ATM網絡的其中一個模式
- “彈性服務”
- 如果發送端的路徑“輕載 ”
- 發送方盡可能使用可用帶寬
- 如果發送方的路徑擁塞了:
- 發送方限制其發送的速度到一個最小保障速率上
RM (資源管理) 信元:
- 由發送端發送,在資料信元中間隔插入
- RM信元中的比特被交換機設定 (“網絡輔助”)
- NI bit: no increase in rate (輕微擁塞)速率不要增加了
- CI bit: congestion indication 擁塞訓示
- 發送端發送的RM 信元被接收端傳回, 接收端不做任何改變
- 在RM信元中的2個位元組 ER (explicit rate)字段
- 擁塞的交換機可能會降低信元中ER的值
- 發送端發送速度是以是最低的可支援速率
- 資料信元中的EFCI bit: 被擁塞的交換機設定成1
- 如果在管理信元RM前面的資料信元EFCI被設定成了1, 接收端在傳回的RM信元中設定CI bit
TCP擁塞控制
TCP采用端到端的擁塞控制。
端到端的擁塞控制機制:
- 路由器不向主機有關擁塞的回報資訊
- 路由器的負擔較輕
- 符合網絡核心簡單的TCP/IP架構原則(複雜性放在網絡邊緣,傳輸層及以上)
- 端系統根據自身得到的資訊,判斷是否發生擁塞,進而采取動作
擁塞控制的幾個問題:
- 如何檢測擁塞:
- 輕微擁塞
- 擁塞
- 控制政策:
- 在擁塞發送時如何動作,降低速率
- 輕微擁塞,如何降低
- 擁塞時,如何降低
- 在擁塞緩解時如何動作,增加速率
- 在擁塞發送時如何動作,降低速率
擁塞感覺
- 某個段逾時了(丢失事件 ):擁塞
- 逾時時間到,某個段的确認沒有來
- 原因1:網絡擁塞(某個路由器緩沖區沒空間了,被丢棄),機率大
- 原因2:出錯被丢棄了(各級錯誤,沒有通過校驗,被丢棄),機率小
- 一旦逾時,就認為擁塞了,有一定誤判,但是總體控制方向是對的
- 有關某個段的3次重複ACK:輕微擁塞(如下圖)
- 段的第1個ack,正常,确認綠段,期待紅段
- 段的第2個重複ack,意味着紅段的後一段收到了,藍段亂序到達
- 段的第2、3、4個ack重複,意味着紅段的後第2、3、4個段收到了,橙段亂序到達,同時紅段丢失的可能性很大(後面3個段都到了,紅段都沒到)
- 網絡這時還能夠進行一定程度的傳輸,擁塞但情況要比第一種好
計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記
速率控制方法
- 維持一個擁塞視窗的值:
CongWin
-
發送端限制已發送但是未确認的資料量(的上限):
LastByteSent - LastByteAcked ≤ CongWin
-
進而粗略地控制發送方的往網絡中注入的速率(如下公式):
rate≈ConWinRTTbytes/secrate ≈ \frac{ConWin}{RTT} bytes/sec rate≈RTTConWinbytes/sec
- CongWin是動态的,是感覺到的網絡擁塞程度的函數:
- 逾時或者3個重複ack,CongWin會下降:
- 逾時時:CongWin降為1MSS,進入SS階段然後再倍增到CongWin/2(每個RTT),進而進入CA階段
- 3個重複ack :CongWin降為CongWin/2,CA階段
- 如果沒有逾時:CongWin會上升
- SS(慢啟動)階段:加倍增加(每個RTT)
- CA(擁塞避免)階段:線性增加(每個RTT)
- 逾時或者3個重複ack,CongWin會下降:
聯合控制的方法:
TCP擁塞控制和流量控制的聯合動作。
發送端控制發送但是未确認的量同時也不能夠超過接收視窗,滿足流量控制要求:
- SendWin = min {CongWin, RecvWin}
- 同時滿足擁塞控制和流量控制要求
TCP擁塞控制政策
- 慢啟動
- AIMD:線性增、乘性減少
- 逾時事件後的保守政策
TCP慢啟動:
-
連接配接剛建立, CongWin = 1 MSS
例如: MSS = 1460bytes & RTT = 200 msec,則初始速率 = 58.4kbps
- 但是可用帶寬可能遠大于MSS/RTT,是以應該盡快加速,到達希望的速率
- 當連接配接開始時,指數性增加(每個RTT)發送速率直到發生丢失事件
- 每一個RTT, CongWin加倍
- 每收到一個ACK時,CongWin加1
- 慢啟動階段:隻要不逾時或3個重複ack,一個RTT,CongWin加倍
- 初始速率很慢,但是加速卻是指數性的
AIMD:
-
乘性減:
丢失事件後将CongWin降為1,将CongWin/2作為門檻值,進入慢啟動階段(倍增直到 CongWin/2)
-
加性增:
當CongWin > 門檻值時,一個RTT如沒有發生丢失事件 ,将CongWin加1MSS: 探測
政策不同:
- 當收到3個重複的ACKs:
- CongWin 減半
- 視窗(緩沖區大小)之後線性增長
- 當逾時事件發生時:
- CongWin被設定成 1 MSS,進入SS階段
- 之後視窗指數增長
- 增長到一個門檻值(上次發生擁塞的視窗的一半)時 ,再線性增加
再次強調一下何時候應該将指數性增長變成線性增長:
在逾時之前,當 CongWin變成上次發生逾時的視窗的一半時
具體實作:
- 變量:Threshold
- 出現丢失,Threshold設定成 CongWin的1/2
小結
事件 | 狀态 | TCP 發送端行為 | 解釋 |
---|---|---|---|
以前沒有收到ACK的data被ACKed | 慢啟動 (SS) | CongWin = CongWin + MSS If (CongWin > Threshold) ,狀态變成 “CA” | 每一個RTT CongWin 加倍 |
以前沒有收到ACK的data 被ACKed | 擁塞避免 (CA) | CongWin = CongWin+MSS × (MSS/CongWin) | 加性增加, 每一個RTT對 CongWin 加一個 1 MSS |
通過收到3個重複的ACK,發現丢失的事件 | SS or CA | Threshold = CongWin/2,CongWin = Threshold+3,狀态變成“CA”, | 快速重傳, 實作乘性的減,CongWin 沒有變成1 MSS. |
逾時 | SS or CA | Threshold = CongWin/2,CongWin = 1 MSS,狀态變成“SS” | 進入slow start |
重複的 ACK | SS or CA | 對被ACKed 的segment, 增加重複ACK的計數 | CongWin and Threshold 不變 |
TCP吞吐量
使用視窗window尺寸W和RTT來描述TCP的平均吞吐量(忽略慢啟動階段,假設發送端總有資料傳輸):
- W:發生丢失事件時的視窗尺寸(機關:位元組)
- 平均視窗尺寸:3/4W
-
平均吞吐量:RTT時間吞吐3/4W
avgTCPthtuput=34WRTTbytes/secavg TCPthtuput = \frac{3}{4}\frac{W}{RTT} bytes/sec avgTCPthtuput=43RTTWbytes/sec
計算機網絡學習筆記-傳輸層前言第三章:傳輸層後記
TCP公平性
公平性目标: 如果 K個TCP會話分享一個鍊路帶寬為R的瓶頸,每一個會話的有效帶寬為 R/K
分析為什麼TCP是公平的(2個競争的TCP會話為例,假設兩個會話的RTT相等):
- 加性增加,斜率為1, 吞吐量增加
- 乘性減,吞吐量比例減少
(具體省略詳細解釋,但是這個平衡的過程真的很神奇)
考慮并行TCP連接配接:
- 如果帶寬為R的鍊路支援了 9個TCP連接配接
- 如果新的應用要求建1個TCP連接配接,獲得帶寬R/10
- 如果新的應用要求建11個TCP 連接配接,獲得帶寬R/2
後記
本篇已完結
(如有補充或錯誤,歡迎評論區留言)