一、為什么TCP是可靠傳輸?
1. 停止等待協議
-
- 通過確認與超時重傳機制實現可靠傳輸
- 在發送完一個分組后,必須暫時保留已發送的分組的副本。
- 分組和確認分組都必須進行編號。
- 超時計時器的重傳時間應當比數據在分組傳輸的平均往返時間更長一些。

出現差錯或丟失的時候,發送方會將自己備份的副本再重傳一次,直到收到接收的確認信息。當接收方收到重復的數據時,會直接丟棄,但是會給發送方請確認自己已經收到了。

2. 改進的停止等待協議——連續ARQ協議和滑動窗口協議
上面的停止等待協議每發送一組數據就必須等到接收方回復確認后,再發起第二組數據,如果出現超時重傳的話,效率更低。因此為了提高傳輸的效率,改進了等待傳輸協議。
連續ARQ協議和滑動窗口協議的機制是以接收方回復確認為單位,每次連續發送一個滑動窗口指定的數據組。示例圖如下:

2.1 什么是滑動窗口協議?(發送方怎么發送數據)
滑動窗口是由發送方維護的類似指針的變量,在每收到一個接收方的確認消息后,該指針向前移動並發送數據,到窗口指定大小的數據組時停下,等待接收方的確認。示意看圖:

2.2 接收方怎么回復確認?
累積確認機制
發送方不對收到的分組逐個發送確認,而是對按序到達的最后一個分組發送確認,這樣就表示:到這個分組為止的所有分組都已正確收到了。
優點:容易實現,即使確認丟失也不必重傳。
缺點:不能向發送方反映出接收方已經正確收到的所有分組的信息。

Go-back-N(回退 N)
為了解決上述同一窗口中數據組不能完整確認的問題,連續ARQ協議采用了回退機制。比如說:發送方發送了前 5 個分組,而中間的第 3 個分組丟失了。這時接收方只能對前兩個分組發出確認。發送方無法知道后面三個分組的下落,而只好把后面的三個分組都再重傳一次。這就叫做 Go-back-N(回退 N),表示需要再退回來重傳已發送過的 N 個分組。
結論:當通信線路質量不好時,連續 ARQ 協議會帶來負面的影響。可能還不如傳統的停止等待協議。
3. TCP可靠傳輸的實現
-
- TCP 連接的每一端都必須設有兩個窗口——一個發送窗口和一個接收窗口。
- TCP 的可靠傳輸機制用字節的序號進行控制。TCP 所有的確認都是基於序號而不是基於報文段。
- TCP 兩端的四個窗口經常處於動態變化之中。
- TCP連接的往返時間 RTT 也不是固定不變的。需要使用特定的算法估算較為合理的重傳時間。
3.1 以字節為單位的滑動窗口技術
滑動窗口是面向字節流的,為了方便記住每個分組的序號,下面的圖解以一個分組假設100個字節,為了方便畫圖表示,將分組進行編號簡化表示,如圖所示,但是要記住,每一個分組的序號是多少。

3.2 改進的確認——選擇確認(SACK)
TCP通信時,如果發送序列中間某個數據包丟失,TCP會通過重傳最后確認的分組后續的分組,這樣原先已經正確傳輸的分組也可能重復發送,降低了TCP性能。SACK(Selective Acknowledgment,選擇確認)技術,使TCP只重新發送丟失的包,不用發送后續所有的分組,而且提供相應機制使接收方能告訴發送方哪些數據丟失,哪些數據已經提前收到等。在建立 TCP 連接時,就要在 TCP 首部的選項中加上“允許 SACK”的選項,而雙方必須都事先商定好。原來首部中的“確認號字段”的用法仍然不變。只是以后在 TCP 報文段的首部中都增加了 SACK 選項,以便報告收到的不連續的字節塊的邊界。
選擇性確認最多表示4個邊界:由於首部選項的長度最多只有 40 字節。需要一個字節指明是SACK選項,另一個字節指明占多少字節。而指明一個邊界就要用掉 4 字節。在選項中最多只能指明 4 個字節塊的邊界信息。因4個字節塊共8個邊界信息。

抓包分析:

3.3 超時重傳時間的選擇
重傳機制是 TCP 中最重要和最復雜的問題之一。TCP 每發送一個報文段,就對這個報文段設置一次計時器。只要計時器設置的重傳時間到但還沒有收到確認,就要重傳這一報文段。那么這個重傳時間到底應該設置多少呢?這里面有學問。以下是我截取的“手抄報”,暫時看不懂。建議跳過。
加權平均往返時間
TCP 保留了 RTT 的一個加權平均往返時間 RTTS(這又稱為平滑的往返時間)。第一次測量到 RTT 樣本時,RTTS 值就取為所測量到的 RTT 樣本值。以后每測量到一個新的 RTT 樣本,就按下式重新計算一次 RTTS:

超時計時器設置的超時重傳時間RTO

往返時間的測量

Karn算法

二、TCP的流量控制
流量控制(flow control)就是讓發送方的發送速率不要太快,既要讓接收方來得及接收,也不要使網絡發生擁塞。利用滑動窗口機制可以很方便地在 TCP 連接上實現流量控制。
流量控制舉例說明:

零窗口處理——持續計數器
考慮上面的例子中,當A發送的數據已經到達B的接收窗口上限,此時A就必須等待B處理了部分數據后,待接收窗口有空閑的時候,再次發送數據,那么A是怎么知道B的接收窗口何時有空閑呢?這時就用到了持續計時器。
TCP 為每一個連接設有一個持續計時器。只要 TCP 連接的一方收到對方的零窗口通知,就啟動持續計時器。若持續計時器設置的時間到期,就發送一個零窗口探測報文段(僅攜帶 1 字節的數據),而對方就在確認這個探測報文段時給出了現在的窗口值。若窗口仍然是零,則收到這個報文段的一方就重新設置持續計時器。若窗口不是零,則死鎖的僵局就可以打破了。
三、TCP的傳輸效率
關於TCP的傳輸效率問題,需要從三方面來考慮,1.何時發送;2.少字節發送數據問題;3.糊塗窗口綜合症問題
3.1 TCP報文的發送時機:
第一種機制是 TCP 維持一個變量,它等於最大報文段長度 MSS。只要緩存中存放的數據達到 MSS 字節時,就組裝成一個 TCP 報文段發送出去。
第二種機制是由發送方的應用進程指明要求發送報文段,即 TCP 支持的推送(push)操作。
第三種機制是發送方的一個計時器期限到了,這時就把當前已有的緩存數據裝入報文段(但長度不能超過 MSS)發送出去。
3.2 少量字節發送數據問題:
問題描述:如果應用程序一次產生一字節數據,這樣會導致網絡由於太多的包而過載。如:從鍵盤輸入的一個字符,占用一個字節,可能在傳輸上造成41字節的包,其中包括1字節的有用信息和40字節的標題數據。
解決方案(NAGLE算法):發送端的應用進程將欲發送的數據逐個字節地送到TCP緩存,則發送端就將第一個字符先發送出去。將后面到達的字符都緩存起來。當接收端收到對第一個字符確認后,再將緩存中的所有字符裝成一個報文段發送出去,同時繼續對隨后到在的字符進行緩存。只有在收到對前一個報文段確認后才繼續發送下一個報文段。
3.3 糊塗窗口綜合症問題:
問題描述:設想一種情況:接收端緩存已滿,而交互式的應用進程一次只從緩存中讀取一個字符,然后向發送端發送確認,並將窗口設置1個字節。接着發送端又發來1個字符。接收端發回確認,仍然將窗口設置為1個字節。這樣下去,網絡效率非常低。
解決方案:接收端等待一段時間,使得緩存已有足夠空間容納;或者緩存已有一半空的空間,再向發送端發送確認。
