正在學習計算機網絡課程,以下是學習《計算機網絡-自頂向下方法》的一些筆記,部分圖片來自mooc網 哈爾濱工業大學 計算機網絡課程:https://www.icourse163.org/course/HIT-154005
文章目錄
1. TCP:面向連接的傳輸協議
1.1 TCP概述
- 面向連接的( connection- oriented) :這兩個進程必須先相互"握手",即它們必須相互發送某些預備報文段,以建立確保數據傳輸的參數。
- TCP 協議只在端系統中運行,而不在中間的網絡元素(路由器和鏈路層交換機)中運行
- 中間的網絡元素不會維持 TCP 連接狀態。 事實上,中間路由器對 TCP 連接完全視而不見,它們看到的是數據報,而不是連接。
- 連接建立過程常被稱爲三次握手 ( three-way handshake)
- 點對點:一個發送方,一個接收方
- 全雙工服務(full-duplex service) :同一連接能傳輸雙向的數據流
- 發起連接的進程被稱爲客戶進程,而另一個進程被稱爲服務器進程。
- TCP 連接的組成:兩臺主機上的緩存、連接狀態變量、socket等
1.2 TCP報文段結構
- 源端口號(source port)和目的端口號(dest port):被用於多路複用/分解來自或送到上層應用的數據。
- 同 UDP 一樣, TCP 首部也包括檢驗和字段( checksum field)
- 序號字段 (sequence number field) 和 確認號字段( acknowledgment number field) :這些字段被 TCP 發送方和接收方用來實現可靠數據傳輸服務,討論見後。
- 接收窗口字段 (receive window field) :應用與流量控制,該字段用於指示接收方願意接受的字節數量。
- 4 bit 的首部長度字段 (header length field) : 有選項字段,所以 TCP 首部的長度是可變的。 (通常,選項字段爲空,所以 TCP 首部的典型長度就是 20 字節 )
- 選項字段 ( options field) :可選與變長的,用於雙方協商最大報文段長度時,或在高速網絡環境下用作窗口調節因子時使用。
- 6 bit 的 標誌字段 (flag field) :
- ACK 比特用於指示確認字段中的值是有效的;
- RST、 SYN 和 FIN 比特用於連接建立和拆除;
- 當 PSH 比特被設置的時候,就指示接收方應立即將數據交給上層(一般不用);
- URG 比特用來指示報文段裏存在着被髮送端的上層實體置爲"緊急"的數據(一般不用),緊急數據的最後一個字節由 16 比特的緊急數據指針字段指出 。
- 序號與確認號:這兩個字段是 TCP 可 靠傳輸服務的關鍵部
- 1)序號:建立在傳送的字節流之上,而不是建立在傳送的報文段的序列之上。 因此一個報文段的序號是該報文段首字節的字節流編號。
- 例如:TCP 將某數據流構建成 500 個報文段,最大報文段長度爲1000字節,則第一個報文段分配序號 0 ,第二個序號 1000 … ,每一個序號被填入到相應 TCP 報文段首部的序號字段中
- 建立TCP連接時,雙方隨機選擇序列號
- 2)確認號:TCP 是全雙工的,因此確認號是希望接收到的下一個字節的序號
- 例1:主機 A 已收到了來自主機 B 的編號爲 0-535 的所有宇節,同時假設它打算髮送一個報文段給主機 B。 主機 A 等待主機 B 的數據流中字節 536 及之後的所有字節。 所以主機 A 就會在它發往主機 B 的報文段的確認號字段中填 上 536。
- 例2:主機 A 己收到一個來自主機 B 的包含字節 0-535 的報文段,以 及另一個包含字節 900 -1000 的報文段。但主機 A 還沒有收到字節 536 -899 的報文段。主機 A 爲了重新構建主機 B 的數據流,仍在等待字節 536 (和其後的字節) 。因此,A 到 B 的下一個報文段將在確認號字段中包含 536。
- 由例2看出,TCP 只確認該流中至第一個丟失字節爲止的字節,所以 TCP 被稱爲提供累積確認( cumulative acknowledgment) 。
- 在例2中,亂序到達的第三個報文段(字節 900 - 1000) 怎麼處理呢?即TCP 連接中收到失序報文段時該怎麼辦?—— TCP 規範中沒有規定,由 TCP 的編程人員做出決策(丟棄或暫時保存)
- 1)序號:建立在傳送的字節流之上,而不是建立在傳送的報文段的序列之上。 因此一個報文段的序號是該報文段首字節的字節流編號。
1.3 TCP可靠數據傳輸
1.3.1 概述
- TCP 在 IP 層提供的不可靠服務基礎上實現可靠數據傳輸,TCP 提供可靠數據傳輸的方法涉及我們在之前所學的許多原理。
- 使用了流水線機制
- 使用了累積確認
- 使用了單一的重傳計時器(與 SR 不一樣,因爲定時器的管理需要相當大的開銷)
- 觸發重傳的事件:超時、收到重複 ACK
1.3.2 合理的重傳超時時間
- 如何設置定時器的合理的超時時間?
- 設置過短:不必要的重傳
- 設置過長:對段丟失的反應太慢
- 但是一定要大於 RTT( round trip time),而 RTT 又是變化的
- TCP 是如何測量估計 RTT ?
- 報文段的樣本 RTT( SampleRTT) :從某報文段被髮出(即交給 IP) 到對該報文段的確認被收到之間的時間量
- TCP 維持一個 SampleRTT 均值 (稱爲 EstimatedRTT) ,EstimatedRTT是一個 SampleRTT 值的加權平均值,α 參考值是 0.125
- EstimatedRTT = (1 -α) · EstimatedRTT + α · SampleRTT
- 即考慮了歷史信息也考慮了最新的測量值,這種平均被稱爲指數加權移動平均 (Exponential Weighted Moving Average , EWMA)
- 除了估算 RTT 外,測量 RTT 的變化也是有價值:
- RTT 偏差 DevRTT,用於估算 SampleRTT 一般會偏離 EstimaLedRTT 的程度:
- DevRTT = (1 -β) · DevRTT +β · | SampleRTT - EstimatedRTT |
- 同樣是指數加權移動平均
- 最終得出定時器超時時間的設置:
- EstimatedRTT 加上一定餘量。 當 SampleRTT 值波動較大時,這個餘量應該大些;當波動較小時,這個餘量應該小些。 因此, DevRTT值應該在這裏發揮作用了。
- TimeoutInterval = EstimatedRTT + 4 · DevRTT
1.3.3 可靠數據傳輸的實現
- TCP 發送方的三個事件
- 從應用層收到數據:
- 將數據封裝在一個報文段中並把該報文段交給 IP
- 報文段包含一個序號,就是該報文段第一個數據字節的字節流編號
- 如果定時器還沒有爲某些其他報文段而 運行,則當報文段被傳給 E 時, TCP 就啓動該定時器。
- 該定時器的過期間隔是 TimeoutInterval
- 超時:
- 重傳引起超時的報文段
- 重啓定時器
- 收到 ACK:
- TCP 將 ACK 的值 y 與它的變量 SendBase 進行比較
- 狀態變量 SendBase 是最早未被確認的字節的序號
- SendBase -1 是指接收方已正確按序接收到的數據的最後一個字節的序號
- TCP 採用累積確認,所以 y 確認了字節編號在 y 之前的所有字節都已經收到
- 如果 y > SendBase,則該 ACK 是在確認一個或多個先前未被確認的報文段。
- 更新 SendBase
- 如果窗口中還有未被確認的分組,則重新啓動定時器
- TCP 將 ACK 的值 y 與它的變量 SendBase 進行比較
- 幾個例子:
- 例1:由於確認丟失而重傳
- 例2:報文段100沒有重傳
- 例3:累積確認避免了第一個報文段的重傳
- 例1:由於確認丟失而重傳
- 從應用層收到數據:
1.3.4超時間隔加倍
- 這是大多數 TCP 實現中所做的一些修改
- 當超時事件發生時, TCP 重傳具有最小序號的還未被確認的報文段。只是每次 TCP 重傳時都會將下一次的超時間隔設爲先前值的兩倍。因此,超時間隔在每次重傳後會呈指數型增長
- 然而,每當定時器在另兩個事件(即收到上層應用的數據和收到 ACK)中的任意一 個啓動時, Timeoutlnterval 由最近的 EstimatedRTT 值與 DevRTT 值推算得到。
- 這種修改提供了一個形式受限的擁塞控制。
- 定時器超時很可能是由網絡擁塞引起的
- 在擁塞的時候,如果發送方持續重傳分組,會使擁塞更加嚴重
- 因此,TCP 使用更文雅的方式,每個發送方的重傳都是經過越來越長的時間間隔後進行的。
1.3.5快速重傳機制
- 超時觸發重傳存在的問題之一是超時週期可能相對較長。 當一個報文段丟失時,這種較長的超時週期迫使發送方延遲重傳丟失的分組,因而增加了端到端時延。
- 先看一下 TCP 接收方的 ACK 生成策略:
- 發送方一個接一個地發送大量的報文段,如果一個報文段丟失,就很可能引起許多一個接一個的冗餘 ACK
- 如果 TCP 發送方接收到對相同數據的 3 個冗餘 ACK,則假定在該報文段之後的報文段已經丟失,TCP 就執行快速重傳(fast retransmit) :即在該報文段的定時器過期之前重傳丟失的報文段
1.3.6 GBN or SR?
- TCP 是一個 GBN 協議 還是一個 SR 協議?
- 前面講過, TCP 確認是累積式的,正確接收但失序的報文段是不會被接收方逐個確認的
- 因此,TCP 發送方僅需維持已發送過但未被確認的字節的最小序號 ( SendBase) 和下一個要發送的字節的序號 ( NextSeqNum) 。 在這種意義下, TCP 看起來更像一個 GBN 風格的協議
- 但是, 許多 TCP 實現會將正確接收但失序的報文段緩存起來。假設 n(n < N)的確認報文丟失,但是其餘 N-1個確認報文在分別超時以前到達發送端,
- GBN 不僅會重傳分組 n, 還會重傳所有後繼的分組 n+1, n+2, … , N
- TCP 則將重傳至多一個報文段,即報文段 n
- 此外,如果對報文段 n +1 的確認報文在報文段 n 超時之前到達, TCP 甚至不會重傳報文段 n
- 對 TCP 提出的一種修改意見是所謂的選擇確認 ,它允許 TCP 接收方有選擇地確認失序報文段,而不是累積地確認最後一個正確接收的有序報文段。此時,TCP 看起來就很像我們通常的 SR 協議。
- 因此, TCP 的差錯恢復機制也許最好被分類爲 GBN 協議與 SR 協議的混合體。
1.4 TCP的流量控制
- 一條 TCP 連接的兩個主機都爲該連接設置了接收緩存RcvBuffer。該TCP連接接收到正確、按序的字節後,它就將數據放入接收緩存。
- 應用進程會從該緩存中讀取數據。 如果應用程序讀取數據緩慢,而發送方發送得太多太快,發送的數據就會很容易地使該連接的接收緩存溢出。
- 流量控制服務( flow-control service) : TCP 爲它的應用程序提供了流量控制服務,以消除發送方使接收方緩存溢出的可能性。本節假設 TCP 接收方丟棄失序的報文段。
- 速度匹配服務:即發送方的發送速率與接收方應用程序的讀取速率相匹配
- 接收方有RcvBuffer:
- 其中接收窗口 RcvWindow 用於提示發送方該接收方還有多少可用的緩存空間,RcvWindow = RcvBuffer - [LastByteRcvd - LastByteRead ]
- 接收方通過在報文段的頭部字段將 RcvWindow 告訴發送方,發送方限制自己已經發生的但還未收到 ACK 的數據不超過接收方的空閒 RcvWindow 的尺寸,具體:
- 發送方 輪流跟蹤兩個變量, LastByteSent 和LastByteAcked
- 這兩個變量之間的差LastByteSent - LastByteAcked ,就是發送方發送到連接中但未被確認的數據量
- 將該數據量控制在值 RcvWindow 以內,就可以保證不會使接收緩存溢出
- 一個小問題:假設接收緩存已經存滿,使得發送方收到 RcvWindow =0,則發送方將停止發送數據。而當接收方的接收緩存已經有新的空間時,發送方又不可能知道。即主機 A 被阻塞而不能再發送數據!
- 解決: TCP 規範中要求接收方的接收窗口爲 0 時,發送方繼續發送只有一個字節數據的報文段。 這些報文段將會被接收方確認。 最終緩存將開始清空,並且確認報文裏將包含一個非 0 的 RcvWindow 值
- UDP 並不提供流量控制
1.5 TCP連接管理
如何建立和拆除一條 TCP 連接?
- TCP 連接的建立過程:3 次握手 ( three- way handshake)
- 第一步:客戶端的 TCP 向服務器端的 TCP 發送SYN 報文段
- 不包含應用層數據,但在報文段的首部中的一個標誌位 (即 SYN 比特)被置爲 1
- 客戶會隨機地選擇一個初始序號( client_isn) ,此編號放置於該起始的 TCP SYN 報文段的序號字段中。
- 第二步:服務器端收到 SYN 報文段,回覆允許連接的報文段SYNACK 報文段
- 服務器爲該 TCP 連接分配 TCP 緩存和變量
- 這個允許連接的報文段也不包含應用層數據,但是 SYN 比特被置爲 1 ;並且 TCP 報文段首部的確認號字段被置爲 client_ isn + 1 ;,服務器選擇自己的初始序號 (server_isn) ,其放置到 TCP 報文段首部的序號字段中
- SYNACK 的含義:我收到了你發起建立連接的 SYN 分組,該分組帶有初始序號 client_isn。 我同意建立該連接。 我自己的初始序號是 server_isn
- 第三步:客戶端收到 SYNACK ,對此向服務器發送一個 ACK,表明自己收到了服務器的允許連接的報文段
- 客戶通過將值 server_isn + 1 放置到回覆報文段首部的確認字段中來完成此項工作
- 可以在該報文段攜帶客戶到服務器的數據
- SYN 比特被置爲 0
- 客戶也要給該連接分配緩存和變量
- 第一步:客戶端的 TCP 向服務器端的 TCP 發送SYN 報文段
- 完成這 3 個步驟,客戶和服務器主機就可以相互發送包括數據的報文段了。 在以後每一個報文段中, SYN 比特都將被置爲 0。
- TCP 連接的關閉:
- 第一步:客戶 TCP 向服務器進程發送一個特殊的 TCP 報文段(首部的一個標誌位 FIN 比特被設置爲 1 )
- 第二步:當服務器接收到 FIN 後,向發送方回送一個 ACK。 然後,服務器關閉連接,發送自己的 FIN
- 第三步:服務器收到 FIN,回覆 ACK,並進行定時等待:如果收到 FIN,則重新發送 ACK
- 第四步:服務器收到 ACK,連接關閉
2.擁塞控制原理
- 非正式定義:太多主機發送了太多數據或者發送的速度太快,以至於網絡無法處理
- 表現:
- 分組丟失(路由器緩存溢出)
- 分組延遲過大(在路由器緩存中排隊)
- 之後將詳細研究 TCP 用於擁塞控制的特定方法。 這裏,我們指出在實踐中所採用的兩種主要擁塞控制方法:
- 端到端擁塞控制
- 網絡層沒有爲運輸層擁塞控制提供顯式支持
- 端系統必須通過對網絡行爲的觀察(如分組 丟失與時延)來推斷
- TCP採用這種方法
- 網絡輔助的擁塞控制
- 網絡層構件(路由器)向發送方提供關於網絡中擁塞狀態的顯式反饋信息
- 這種反饋可以簡單地用一個比特來指示鏈路中的擁塞情況
- 擁塞信息從網絡反饋到發送方通常有兩種方式
- 路由器把反饋信息直接發給發送方
- 路由器在分組中標記擁塞產生,再由接收方向發送方通知該網絡擁塞
- 端到端擁塞控制
3.TCP擁塞控制原理
- TCP 必須使用端到端擁塞控制而不是使網絡輔助的擁塞控制,因爲 IP 層不向端系統提供顯式的網絡擁塞反饋
- TCP 所採用的方法是讓每一個發送方根據所感知到的網絡擁塞程度來限制其能向連接發送流量的速率,主要有以下三個問題:
- 第一,一個 TCP 發送方如何限制它向其連接發送流量的速率?
- 第二,一個 TCP 發送方如何感知從它到目的地之間的路徑上存在擁塞?
- 第三,當發送方感知到端到端的擁塞時,如何合理地改變其發送速率?
- 第一個問題:
- 運行在發送方的 TCP 擁塞控制機制跟蹤一個額外的變量,即擁塞窗口 (congestion window,cwnd)
- 它對一個 TCP 發送方能向網絡中發送流量的速率進行了限制
- 發送方的發送速率大概是 cwnd / RTT 字節/秒
- 通過調節 cwnd 的值,發送方因此能調整它向連接發送數據的這率
- 第二個問題:
- 發生丟包事件(超時或收到 3 個冗餘 ACK) ,發送方就認爲在路徑上出現了擁塞的指示
- 第三個問題:
- 加性增 - 乘性減:AIMD
- 慢啓動:Slow Start(SS)
- AIMD:
- 逐漸增加發送速率,謹慎探測可用帶寬,直到發生 loss
- Additive Increase:每個 RTT 將 cwnd 增大一個MSS —— 擁塞避免的思想
- Multiplicative Decrease:發生 loss 後將 cwnd 減半
- 慢啓動:
- 在慢啓動狀態, cwnd 的值以 1 個 MSS 開始並且每當傳輸的報文段首次被確認就增加 1 個 MSS。 因此, TCP 發送速率起始慢,但在慢啓動階段以指數增長。
- 何時結束這種指數增長?
- 1.如果存在一個由超時指示的丟包事件(即擁塞),則將 cwnd 設置爲 1 並重新開始慢啓動過程。還將第二個狀態變量的值 ssthresh ( "慢啓動闊值"的速記) 設置爲 cwnd / 2
- 2.當 cwnd 的值等於或超過 ssthresh 時, 結束慢啓動並且 TCP 轉移到擁塞避免模式更爲謹慎地增加 cwnd,即進入線性增長階段
- 3.如果檢測到 3 個冗餘 ACK ,則 cwnd 的值減爲一半,然後線性增長
- 擁塞避免
- 上文提到,一旦進入該狀態, cwnd 的值大約是上次遇到擁塞時的值的一半, 距離擁塞並不遙遠!
- 因此採用了一種保守的方法:每個 RTT 只將 cwnd 的值增加一個 MSS (線性增長)
- 總結:
- 當 cwnd < ssthresh 時,慢啓動階段,指數增長
- 當 cwnd >= ssthresh 時,擁塞避免階段,線性增長
- 當收到 3 個重複 ACK 時, cwnd 的值和 ssthresh 的值都減爲一半
- 當超時發生時,cwnd 直接設爲 1,ssthresh 減爲一半
- 在慢啓動狀態, cwnd 的值以 1 個 MSS 開始並且每當傳輸的報文段首次被確認就增加 1 個 MSS。 因此, TCP 發送速率起始慢,但在慢啓動階段以指數增長。