計算機網路自頂向下方法:第三章 運輸層

炭燒生蠔發表於2019-04-08

先根據書中的複習題鞏固一遍, 最後回答常見問題TCP三次握手和四次揮手, 如有錯誤, 歡迎指出~

點選下面跳過複習題

TCP3次握手: 為什麼需要初始序號? 為什麼需要3次握手, 而不是兩次握手
TCP4次揮手

 

第二章: 運輸層

3.1~3.3節

R1. 假定網路層提供了下列服務.

  • 在源主機中的網路層接收最大長度1200位元組和來自運輸層的目的主機地址的報文段. 網路層則保證將該報文段交付給位於目的主機的運輸層. 假定在目的主機上能夠執行許多網路應用程式.

a. 設計可能最簡單的運輸層協議, 該協議將使應用程式資料到達位於目的主機的所希望的程式. 假設在目的主機中的作業系統已經為每個執行的應用程式分配了一個4位元組的埠號.

b. 修改這個協議, 使它向目的程式提供一個的"返回地址".

c. 在你的協議中, 該運輸層在計算機網路的核心中"必須做任何事"嗎?

 
答:

計算機網路自頂向下方法:第三章 運輸層
  • a. 我設計的最簡單運輸層協議將包括兩部分: 目的埠號和報文. 因為該協議只要使應用程式資料到達位於目的主機所需要的程式就可以了, 它將會在下發到源主機的網路層時加上目的主機的IP地址, 保證了主機之間的邏輯通訊. 到達目的主機的網路層後會把該運輸層報文段提取上交到運輸層, 運輸層根據目的埠好在本機的網路程式中找到有相同的埠號的目的程式, 並交付應用資料.
計算機網路自頂向下方法:第三章 運輸層
  • b. 為了提供讓目的程式返回的地址, 在需要加上一個源埠號欄位. 這樣目的程式就能通過把源埠號設定為目的埠號, 進而向源程式傳輸資料. (再加上一些其他欄位就是個UDP協議了)
  • c. 它並不需要做"任何事", 目前它只提供交付資料的功能, 不具備諸如擁塞控制, 確保資料完整性等功能.

 

R2. 考慮有一個星球,

  • 每個人都屬於某個六口之家, 每個家庭都住在自己的房子裡, 每個房子都有一個唯一的地址, 並且某給定家庭中的每個人有一個獨特的名字. 假定該星球有一個從源家庭到目的家庭交付信件的郵政服務. 該郵件服務要求: 1. 在一個信封中有一封信; 2. 在信封上清楚地寫上目的家庭的地址(並且沒有別的東西). 假設每個家庭有一名家庭成員代表為家庭中的其他成員收集和分發信件. 這些信件沒有必要提供任何有關信的接收者的提示.

a. 使用對上面複習題R1的解決方案作為啟發, 描述家庭成員代表能夠使用的協議, 以從傳送家庭成員向接收家庭成員交付信件.

b. 在你的協議中, 該郵政服務必須開啟信封並檢查信件內容才能提供它的服務嗎?

 
答:

  • a. 這個問題考察的是運輸層協議與上層應用層和下層網路層之間的關係. 下面描述一次收發郵件的過程.
場景 對映
每個家庭住自己的房子, 房子有唯一地址 每一臺主機都有自己的IP地址
家庭中每個人都有自己獨特的名字 主機中執行的每個程式都有自己唯一的埠號
家庭A一名成員代表家庭A收集全家庭的信件 某個運輸層協議, 通過套接字從應用程式獲取應用報文
家庭A代表將收集的所有郵件交給郵政服務 運輸層協議將運輸層報文段交付給網路層 (多路複用)
信封上除了目的家庭地址沒有別的東西, 郵政服務把郵件傳輸到目的家庭B 網路層會將報文段與目的地址IP封裝成資料包, 進行主機之間的網路傳輸
家庭B的代表從郵政服務獲得郵件 目的主機的運輸層從網路層中接收資料, 抽取出報文段
家庭B的代表把郵件分發給自己家裡的成員 目的主機的運輸層協議把資料通過套接字上交給應用程式 (多路分解)
  • b. 郵政服務不需要開啟信封並檢查信件內容, 因為它只負責把郵件從一個家庭住址傳送到另一個家庭. 它並不關心信件的內容. 好比網路層所提供的服務, 它會將傳輸層報文段封裝起來, 報文段的具體內容與它無關.

 

R3. 考慮在主機A和主機B之間有一條TCP連線.

  • 假設從主機A傳送到主機B的TCP報文段具有源埠號x和目的埠號y. 對於從主機B傳送到主機A的報文段, 源埠號和目的埠號分別是多少?
  • 答: 源埠號將設定為y, 目的埠號設定為x.

 

R4. 描述應用程式開發者為什麼可能選擇在UDP上執行程式而不是在TCP上執行的原因.

  • 這個問題問的是在什麼情況下, UDP的優點明顯蓋過TCP的缺點.
  • UDP協議是一種極為簡化的運輸層協議, 它不提供不必要的服務, 大概就是在IP協議上加上源和目的地的埠後等資訊, 所以它可以隨時地, 以任何速率向其他端系統傳送資料.
  • TCP協議有許多優良特性, 它確保資料完整性, 提供擁塞控制, 但這些特性會增加端到端通訊的時延.
  • 如果一個應用程式需要提供實時服務, 而且能夠容忍一定的分組丟失, 那麼UDP協議是更好的選擇.

 

R5. 在今天的因特網中, 為什麼語音和影像流量常常是經過TCP而不是經UDP傳送.

  • (提示: 我們尋找的答案與TCP的擁塞控制機制沒有關係)
  • 答: 為了確保資料的完整性, 分組丟失可能會對語音和影像質量產生影響.

 

R6. 當某應用程式執行在UDP上時, 該應用程式可能得到可靠的資料傳輸嗎? 如果能, 如何實現?

  • 可以的.
  • 需要通過應用層協議實現. 比如谷歌的Chrome瀏覽器中所使用的QUIC協議在UDP之上的應用層協議中實現了可靠性.

 

R7. 假定在主機C上的一個程式有一個具有埠號6789的UDP套接字.

  • 假定主機A和主機B都用目的埠6789向主機C傳送一個UDP報文段. 這兩臺主機的這些報文段在主機C都被描述為相同的套接字嗎? 如果是這樣的話, 在主機C的該程式將怎樣知道源於兩臺不同主機的這兩個報文段?

 

  • 答: 這兩臺主機的這些報文段在主機C會被描述為相同的套接字. 因為在傳輸UDP包的時候, 網路層會附帶上源和目的的IP地址的, 主機C的程式可以通過不同的源IP地址判別.
  • 畢竟主機A和B在選埠的時候不知道彼此具體會選什麼, 肯定會有選用一樣埠號的情況, 主機IP能把它們區分開.

 

R8. 假定在主機C埠80上執行一個Web伺服器.

  • 假定這個Web伺服器使用持續連線, 並且正在接收來自兩臺不同主機A和B的請求. 被髮送的所有請求都通過位於主機C的相同套接字嗎? 如果它們通過不同的套接字傳遞, 這兩個套接字都具有埠80嗎? 討論和解釋之.

 

  • 答: 這裡有個巧妙的關係為題目帶來歧義.
  • A和B的請求會通過80埠找到伺服器程式, 就這裡而言它們通過為與C的相同套接字, 這個套接字具有埠80.
  • 當它們與伺服器程式建立連線的時候, 伺服器程式會單獨為它們分配套接字, 通過專門的套接字響應客戶端的請求. 這兩個套接字就不具有80埠了.

 

R9. 在我們的rdt協議中, 為什麼需要引入序號?

  • 如果不引入序號會有什麼問題? 描述: 一個初始的rdt停等協議是這樣的: 傳送方傳送一個分組, 傳送方進入等待狀態, 不能從上層接收分組, 接收方接收到分組後如果分組正常則回覆ACK, 否則回覆NAK, 傳送方接收到ACK則回到初始狀態等待上層呼叫, 如果收到NAK則重傳該分組繼續等待.
  • 問題來了: 如果接收方的ACK, NAK分組在傳輸過程中受損, 傳送方該如何處理? 最簡單實用的方法就是重傳了, 也就是當傳送方不確定接收方是否收到分組就把分組重新傳送一遍.
  • 但是重發分組會帶來新的問題, 接收方在接收到重發的分組時, 它並不知道這是一個新的分組還是一個重傳的分組(對上一個分組已經確認過了).
  • 於是便引入序號, 這裡的序號用一個位元位表示0和1就能解決. 加入當前傳送方傳送帶有0序號的分組, 那麼接收方會進行響應. 傳送方如果接收到損壞的確認分組, 那麼它重傳一次帶有0序號的分組. 否則傳送帶1序號的下一個分組. 接收方根據分組的序號進行判斷, 如果當前分組的序號和上一個接受到的分組的序號相同, 說明這是一次重傳, 如果不相同說明是一個新的分組.
  • 以上基於一個簡單的停等協議進行描述.
計算機網路自頂向下方法:第三章 運輸層

 

R9. 在我們的rdt協議中, 為什麼需要引入定時器?

  • 在上面一題中瞭解引入序號是為了解決分組在傳播過程中因分組受損, 傳送方重傳分組而帶來的冗餘分組問題. 但是在因特網中, 分組除了會受損, 還可能丟失. 這裡探討該通過一個怎樣的機制解決分組丟失問題.
  • 如果傳送方傳送的分組或者接收方響應的確認在傳輸過程中丟失, 傳送方將收不到確認. 解決這問題的辦法仍是重傳分組, 但是應該在什麼時候進行重傳是值得商榷的. 網路中的延時具有非常大的不確定性, 如果等待足夠大的時延才重傳分組顯然會降低效率. 應該定一個固定的時間, 只要過了這個時間就認為分組丟失(儘管可能沒有丟失).
  • 這裡便引入了定時器, 在每傳輸一個分組時開啟一個定時器, 而且讓傳送方響應定時器計時後產生的中斷, 還有要關閉計時器的機制.

當集齊檢驗和, 序號, 定時器, 肯定和否定確認分組這些技術後, 一個基本的可靠資料傳輸協議已經構建好了.

 

R10. 假定傳送方和接收方之間的往返時延是固定的並且為傳送方所知. 假設分組能夠丟失的話, 在協議rdt3.0中, 一個定時器仍是必需的嗎? 試解釋之.

  • 如果傳送方知道了雙方固定的往返時延, 那麼就可以不需要定時器了. 因為定時器的存在就是為了估計一個雙方的往返時延值, 超過了就進行重傳. 現在知道具體且固定的往返時延, 那麼就可以準確地得出接受到確認分組的時間, 如果超過了該時間還沒有接收到確認就進行重傳.

 

R12. 在配套網站上使用Go-Back-N(回退N步)Java小程式.

a. 讓源傳送5個分組, 在這5個分組的任何一個到達目的地之前暫停該動畫. 然後毀掉第一個分組並繼續該動畫. 試描述發生的情況.

b. 重複該實驗, 只是現在讓第一個分組到達目的地並毀掉第一個確認. 再次描述發生的情況.

c. 最後嘗試傳送6個分組. 發生了什麼情況?

 

R13. 重複複習題R12, 但是現在使用Selective Repeat(選擇重傳)Java小程式. 選擇重傳和回退N步有很麼不同?

 

  • 上面的題目由於無法訪問到該小程式暫時跳過, 但是下面的補充會覆蓋掉上面兩個問題的知識點.

補充:

  • 跳過補充說明

    回退N步

  • 在R11過後已經基本建立起了一個可靠資料傳輸協議. 但是它傳輸分組的形式相當於序列傳輸, 對鏈路的利用率極低. 可不可以在等待收到確認分組時繼續傳送分組?
  • 答案是可以的. 但是會引入新的問題, 這樣像流水線一樣地傳送分組, 如何處理丟失, 損壞及延時過大的分組?
  • 解決流水線的差錯恢復有兩種基本方法是: 回退N步和選擇重傳.
  • 回退N步從字面上是很好理解的, 先傳送一個分組a, 在啟動計時器後陸續傳送b, c, d ... n, 如果a分組在傳輸過程中出現了問題, 那麼就從a開始重新傳輸n個分組.

計算機網路自頂向下方法:第三章 運輸層
  • 口頭描述一下回退N步的流程, 下面的FSM圖描述的更清晰. 首先會傳送base序號的分組, 並啟動計時器, 然後繼續按序傳送視窗內的分組, 如果到達了視窗的邊界base + N - 1處的分組就停下來, 也就是說傳送方需要維護髮送視窗的上下邊界. 而接收方接收到base分組後會根據base分組的序列號響應回去, 因此接收方只需要維護一個記錄分組n被接收到的變數.
  • 當base分組的計時器計時完還沒有收到確認, 認為出現分組丟失, 這時不管視窗有邊界擴到哪裡, 都從base開始重傳分組. 所以如果接收方接在收到base分組之前收到後面的分組(失序), 可以直接把失序的分組丟棄掉, 不需要快取, 因為傳送方必定會重傳一次.
  • 從這也能得出傳送方與接收方都是採用累計確認的方式處理分組.
計算機網路自頂向下方法:第三章 運輸層

 

選擇重傳

  • 在引入選擇重傳之前, 我們先看看回退N步協議會帶來什麼問題. 顯然回退N步是一個在流水線式分組傳輸下一個可靠的協議, 但是如果視窗比較大, 當base分組丟失後, 後面所有的分組都要進行重傳, 這會不會比較浪費呢? 考慮每個分組都丟失一下, 那麼重傳的次數將達到二次方的數量級.
  • 可不可以哪個分組丟失了就重傳哪個分組, 而不是重傳全部呢? 可以的, 這就引入了選擇重傳協議. 在理解了回退N步後選擇重傳應該不是個大問題.
計算機網路自頂向下方法:第三章 運輸層

 

  • 對於傳送方, 在send_base分組被確認後它視窗才會往左移動, 移動的長度取決於send_base分組旁邊有多少個連著的已經確認的分組(選擇重傳, 允許失序的分組被確認後快取起來, 等待被確認).
  • 對於接收方, 當接收到rcv_base分組後才會移動視窗, 移動的長度也取決於旁邊有多少個連著的失序(已快取)但未被確認的分組.
  • 從這能看出, 傳送方與接收方的視窗並不是同步移動的. 這裡會引入一個大問題. 見下圖:
計算機網路自頂向下方法:第三章 運輸層

 

  • 上圖描述的問題是現在分組的序列號的取值範圍是0~3, 也就是大小為4(之前講過0~1的), 視窗大小為3.
  • 假設傳送方傳送了分組0, 1, 2, 傳送方全部接收到, 傳送方的視窗移動3格, 等待3, 4, 5分組.
  • 不巧的是0, 1, 2三個分組的ACK分組都丟失了, 傳送方將重傳0, 1, 2三個分組.
  • 這時問題就來了, 假設0, 1, 2分組對應的序列分別為0, 1, 2. 但是4, 5分組對應的序列號也為0, 1. 為了確保傳送方的視窗能夠滑動, 接收方會快取rcv_base - N的分組(已經確認), 以便再次收到這個範圍上的冗餘分組時能夠傳送一個對應的ACK.
  • 這時傳送方傳送的分組0帶有序號0, 而接收方的既期待分組4(序號為0), 又快取有分組0(序號為0), 接收方將不知道收到的是分組0還是分組4.
  • 顯然, 如果視窗的長度比序號空間小1時, 可能出現接收方無法確定接受到的分組是一次重傳還是一個新的分組. - 書上給出的視窗取值範圍為: 視窗長度必須小於或等於序號空間大小的一半.

 

繼續是複習題

3.5節

R14. 是非判斷題

a. 主機A經過一條TCP連線向主機B傳送一個大檔案. 假設主機B沒有資料發往主機A. 因為主機B不能隨資料捎帶確認, 所以主機B將不向主機A傳送確認.
答: 錯誤. 主機B將不向主機A傳送確認這句話違背了一個可靠資料傳輸協議的基本原則. 首先要明確為了確保可靠的資料傳輸, 接收方向傳送方傳送確定報文是協議的一部分. 再分析推匯出這一錯誤結論的原因: 主機B不能隨資料捎帶確認. 書本上提出捎帶的概念時, 給的是一個具體場景, 傳送方要傳送一個字元, 接收方要返回該字元進行回顯, 所以順便把確認資訊放入到發給傳送方的資料的報文段中. 要區分清楚確認和捎帶確認之間的關係.

b. 在整個連線的過程中, rwnd的長度決不會變化.
答: 錯誤. rwnd = RcvBuffer - [LastByteRcvd - LastByteRead]. rwnd表示的是接收視窗的大小, 這取決於接收方應用程式從快取中讀取資料的速率和傳送方傳送的速率, 是會變化的.

c. 假設主機A通過一條TCP連線向主機B傳送一個大檔案. 主機A傳送但未被確認的位元組數不會超過接收快取的大小.
答: 正確. 講的就是TCP的流量控制.

d. 假設主機A通過一條TCP連線向主機B傳送一個大檔案. 如果對於這條連線的一個報文段的序號為m, 則對於後繼報文段的序號將必然是m + 1.
答: 錯誤. 序號是根據TCP資料的位元組流決定的, 而不是建立在報文序列之上. 後繼報文段的序號應該是m + n, 而n是最大報文段長度.

e. TCP報文段在它的首部中有一個rwnd欄位.
答: 錯誤. TCP報文段有接收視窗欄位, rwnd存放在接收視窗欄位中.

f. 假定在一條TCP連線中最後的SampleRTT等於1秒, 那麼對於該連線的TimeoutInterval的當前值必定大於等於1秒.
答: 正確. TimeoutInterval = EstimatedRTT + 4 * DevRTT.

g. 假設主機A通過一條TCP連線向主機B傳送一個序號為38的4個位元組的報文段. 在這個相同的報文段中, 確認號必定是42.
答: 錯誤. 概念性錯誤, 確認號是期待接收方傳送的序號.

 

R15. 假設主機A通過一條TCP連線向主機B傳送兩個緊挨著的TCP報文段. 第一個報文段的序號為90, 第二個報文段序號為110.

a. 第一個報文段中有多少資料?
答: 110 - 90 = 20個位元組.

b. 假設第一個報文段丟失而第二個報文段到達主機B. 那麼在主機B發往主機A的確認報文中, 確認號應該是多少?
答: 90. 在建立連線的時候主機B就知道要先接收90.

 

R16. 考慮在3.5節中討論的Talnet的例子.

  • 在使用者鍵入字元C數秒之後, 使用者又鍵入字元R. 那麼在使用者鍵入字元R之後, 總共傳送了多少個報文段, 這些報文段中的序號和確認欄位應該填入什麼?
  • 答: 由於使用者在鍵入C數秒後鍵入R, TCP沒有斷開連線. 所以鍵入R後有使用者到伺服器和伺服器到使用者兩個報文段. 使用者到伺服器: 序號44, 確認80, 伺服器到使用者: 序號80, 確認45

 

3.7節

R17. 假設兩條TCP連線存在於一個寬頻為Rbps的瓶頸鍊路上.

  • 它們都要傳送一個很大的檔案(以相同方向經過瓶頸鍊路), 並且兩者是同時開始傳送檔案. 那麼TCP將為每條連線分配什麼樣的傳輸速率?
  • 答: 這裡涉及到2條TCP連線的公平性問題, 很難保證兩條TCP連線分配均等的傳輸速率. 但是2條TCP連線的速率之和是會在R/2~R之間浮動的. 至於哪條快一點, 哪條慢一點是不確定的.

 

R18. 是非判斷題. 考慮TCP的擁塞控制. 當傳送方定時器超時時, 其ssthresh的值將被設定為原來值的一半.

  • 錯誤. 當傳送方定時器超時時, TCP傳送方將cwnd設定為1並重新開始慢啟動過程. 它還將第二個狀態變數的值ssthresh設定為cwnd/2, 即當檢測到擁塞時將ssthresh置為擁塞視窗值的一半.

 

R19. 在3.7節的"TCP分岔"討論中, 對於TCP分岔的響應時間, 斷言大約是4 * RTT(FE) + RTT(BE) + 處理時間. 評價該斷言.

  • 我認為該斷言是合理的. 它給出的是一條包含重要時延引數的公式. 在實際情況中, 某些引數可能可以省略, 但是在省略之前還是要經過考慮的.

 

插入對TCP協議的總結

  • 3.4節講的是如何從零建立起一個可靠高效的資料傳輸協議, 而3.5節基於3.4節的基礎具體講述TCP的實現, 這裡有必要對TCP協議進行一個簡單的總結.

 

TCP三次握手

在講述三次握手之前先看看TCP報文段結構

計算機網路自頂向下方法:第三章 運輸層

 

  • 對於三次握手問題, 我們暫時不考慮報文段中的其他欄位, 只看報文段中序號和確認號欄位. 對這兩個欄位有印象後, 下面開始描述一次完整的TCP三次握手過程.
  • 故事開始...
計算機網路自頂向下方法:第三章 運輸層
  1. 第一步: 客戶端TCP向伺服器端的TCP傳送一個特殊的TCP報文段, 該報文段不包含應用層資料. 報文段首部中的標誌位SYN置1, 簡稱為SYN報文段. 同時客戶端隨機選取一個初始序列號client_isn, 放置於SYN報文段的序號欄位中, 最後把該報文段經下層封裝傳送給伺服器. SYN的意思是: xxx伺服器, 我想向你發起TCP連線, 我的初始序號為client_isn.
  2. 第二步: 伺服器收到SYN報文段後, 響應一個SYNACK報文段. SYNACK報文段的SYN標誌位置1, 確認號欄位設定為client_isn + 1, 序號欄位由伺服器選擇自己的初始序號server_isn. SYNACK報文段的意思是: 我收到了你的SYN報文段, 序號為client_isn, 我同意該連線, 我自己的序號為server_isn.
  3. 第三步: 客戶端接收到SYNACK後要告知伺服器自己收到了. 於是傳送最後一個報文段, SYN標誌位置0, 把確認欄位設定為server_isn + 1, 並設定自己的序號. 這個報文意思是: 好的, 我知道你同意了, 我們開始傳輸資料吧.

 

在解釋序號和確認號之前先解釋一下為什麼是三次握手而不是兩次握手.
  • 其實如果上面的過程理解了, 就能回答這個問題了, 不過這裡有個漫畫幫助理解.
  • 先演示的是三次握手.
計算機網路自頂向下方法:第三章 運輸層

 

  • 接著演示兩次握手.
計算機網路自頂向下方法:第三章 運輸層
明白了為什麼是三次握手而不是四次揮手後, 再來看TCP報文段中的序號和確認號.
  • 序號:
  • 序號是建立在傳送的位元組流之上, 而不是建立在傳送的報文段的序列之上的. 意思是說如果把傳輸的資料看作是一個位元組文字, 序號則是對文字的首位元組進行編號.
  • 我知道還是很抽象, 看具體例子. 現在要通過TCP傳送一個500000位元組的大檔案, 最大報文長度為1000(一個報文段最多隻能裝1000個位元組). 那麼這次TCP傳輸就要分為500個報文段. 第一個報文段序號為0, 因為在500000位元組中首位元組的序號為0; 第二個報文段的序號為1000, 因為第一個報文段裝了1000個位元組, 第二個報文段從第1000個位元組開始裝起; 同理, 第三個報文段的序號為2000...
  • 為什麼要使用序號?
  • 傳送序號是為了告訴接收方, 下一次我將從哪個地方開始傳資料給你. 接收方同時也會期待下次從下一個位元組序列的位置開始接收傳送方的資料. 接收方會把這個位置寫到確認號中, 比如上面的例子, 接收方在接收到0序列分組後, 會在確認欄位填入1000, 下一次期待接收1000位置的位元組.
  • 由上可見: 主機A填充進報文段的確認號是主機A期望從主機B收到的下一位元組的序號.

 

TCP四次揮手

  • 四次揮手指的是TCP的兩端斷開連線時的四次報文段傳輸.
計算機網路自頂向下方法:第三章 運輸層

 

  1. 首先客戶端TCP向伺服器傳送一個特殊的TCP報文段, 其中FIN標誌位被置1.
  2. 伺服器收到該報文段後就向傳送方傳送一個確認報文段.
  3. 然後伺服器傳送自己的終止報文段, 同樣是把FIN位置1.
  4. 最後客戶端對伺服器的終止報文段傳送確認響應.
  • 兩次揮手行不行? 就是客戶端提出關閉, 伺服器響應後TCP就結束.
  • 答: 不行, 因為客戶單方面提出關閉的話, 伺服器還是可以向客戶端傳送資料, 必須雙方都提出關閉並得到確認後TCP連線才算關閉.

相關文章