先根據書中的複習題鞏固一遍, 最後回答常見問題TCP三次握手和四次揮手, 若有錯誤, 歡迎指出~html
點擊下面跳過複習題
TCP3次握手: 爲何須要初始序號? 爲何須要3次握手, 而不是兩次握手
TCP4次揮手java
第二章: 運輸層
3.1~3.3節
R1. 假定網絡層提供了下列服務.
- 在源主機中的網絡層接收最大長度1200字節和來自運輸層的目的主機地址的報文段. 網絡層則保證將該報文段交付給位於目的主機的運輸層. 假定在目的主機上可以運行許多網絡應用進程.
a. 設計可能最簡單的運輸層協議, 該協議將使應用程序數據到達位於目的主機的所但願的進程. 假設在目的主機中的操做系統已經爲每一個運行的應用進程分配了一個4字節的端口號.web
b. 修改這個協議, 使它向目的進程提供一個的"返回地址".小程序
c. 在你的協議中, 該運輸層在計算機網絡的核心中"必須作任何事"嗎?瀏覽器
答:緩存
- a. 我設計的最簡單運輸層協議將包括兩部分: 目的端口號和報文. 由於該協議只要使應用程序數據到達位於目的主機所須要的進程就能夠了, 它將會在下發到源主機的網絡層時加上目的主機的IP地址, 保證了主機之間的邏輯通訊. 到達目的主機的網絡層後會把該運輸層報文段提取上交到運輸層, 運輸層根據目的端口好在本機的網絡進程中找到有相同的端口號的目的進程, 並交付應用數據.
- b. 爲了提供讓目的進程返回的地址, 在須要加上一個源端口號字段. 這樣目的進程就能經過把源端口號設置爲目的端口號, 進而向源進程傳輸數據. (再加上一些其餘字段就是個UDP協議了)
- c. 它並不須要作"任何事", 目前它只提供交付數據的功能, 不具有諸如擁塞控制, 確保數據完整性等功能.
R2. 考慮有一個星球,
- 每一個人都屬於某個六口之家, 每一個家庭都住在本身的房子裏, 每一個房子都有一個惟一的地址, 而且某給定家庭中的每一個人有一個獨特的名字. 假定該星球有一個從源家庭到目的家庭交付信件的郵政服務. 該郵件服務要求: 1. 在一個信封中有一封信; 2. 在信封上清楚地寫上目的家庭的地址(而且沒有別的東西). 假設每一個家庭有一名家庭成員表明爲家庭中的其餘成員收集和分發信件. 這些信件沒有必要提供任何有關信的接收者的提示.
a. 使用對上面複習題R1的解決方案做爲啓發, 描述家庭成員表明可以使用的協議, 以從發送家庭成員向接收家庭成員交付信件.服務器
b. 在你的協議中, 該郵政服務必須打開信封並檢查信件內容才能提供它的服務嗎?網絡
答:tcp
- 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三次握手過程.
- 故事開始...
- 第一步: 客戶端TCP向服務器端的TCP發送一個特殊的TCP報文段, 該報文段不包含應用層數據. 報文段首部中的標誌位SYN置1, 簡稱爲SYN報文段. 同時客戶端隨機選取一個初始序列號client_isn, 放置於SYN報文段的序號字段中, 最後把該報文段經下層封裝發送給服務器. SYN的意思是: xxx服務器, 我想向你發起TCP鏈接, 個人初始序號爲client_isn.
- 第二步: 服務器收到SYN報文段後, 響應一個SYNACK報文段. SYNACK報文段的SYN標誌位置1, 確認號字段設置爲client_isn + 1, 序號字段由服務器選擇本身的初始序號server_isn. SYNACK報文段的意思是: 我收到了你的SYN報文段, 序號爲client_isn, 我贊成該鏈接, 我本身的序號爲server_isn.
- 第三步: 客戶端接收到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的兩端斷開鏈接時的四次報文段傳輸.
- 首先客戶端TCP向服務器發送一個特殊的TCP報文段, 其中FIN標誌位被置1.
- 服務器收到該報文段後就向發送方發送一個確認報文段.
- 而後服務器發送本身的終止報文段, 一樣是把FIN位置1.
- 最後客戶端對服務器的終止報文段發送確認響應.
- 兩次揮手行不行? 就是客戶端提出關閉, 服務器響應後TCP就結束.
- 答: 不行, 由於客戶單方面提出關閉的話, 服務器仍是能夠向客戶端發送數據, 必須雙方都提出關閉並獲得確認後TCP鏈接纔算關閉.