1. TCP 可靠性如何保證?
- 通道可靠:用三次握手、四次揮手保證連線正確;
- 資料正確:分割槽編號、校驗和、超時重傳;
- 傳輸控制:流量控制、擁塞控制
2. 重傳機制
TCP可靠傳輸方式是序列號與確認應答。當傳送資料包丟失時,會用重傳機制解決。常見重傳機制有超時重傳、快速重傳、SACK、D-SACK。
2.1 超時重傳
TCP協議要求在傳送端每傳送一個報文段,就啟動一個定時器並等待確認資訊;接收端成功接收新資料後返回確認資訊。若在定時器超時前資料未能被確認,TCP就認為報文段中的資料已丟失或損壞,需要對報文段中的資料重新組織和重傳。
2.2 快速重傳
如果收到一個失序的報文段時, TCP需要立刻產生一個ACK,這個ACK不應該被延時,目的在於讓對方知道收到一個失序的報文,並告訴對方自己希望收到的報文seq,我們不知道這個重複的ACK的原因,因為還是會等待少量的重複ACK到來,如果連續收到3個或者3個以上的dup ACK,就被判斷這個報文被丟失了,於是就需要立即重傳丟失的資料段,這個地方不用等待定時器溢位。
3. 滑動視窗協議
在TCP協議中,傳送方和接受方通過各自維護自己的緩衝區。通過商定包的重傳機制等一系列操作,來解決不可靠的問題。為了增加網路的吞吐量,想將資料包一起傳送過去,便產生了“滑動視窗”協議 。
滑動視窗實現
在圖中,我們可看出灰色1號2號3號包已經發送完畢,並且已經收到Ack。這些包就已經是過去式。4、5、6、7號包是黃色的,表示已經發送了。但是並沒有收到對方的Ack,所以也不知道接收方有沒有收到。8、9、10號包是綠色的。是我們還沒有傳送的。這些綠色也就是我們接下來馬上要傳送的包。 可以看出我們的視窗正好是11格。後面的11-16還沒有被讀進記憶體。要等4號-10號包有接下來的動作後,我們的包才會繼續往下發送。
正常情況
可以看到4號包對方已經被接收到,所以被塗成了灰色。“視窗”就往右移一格,這裡只要保證“視窗”是7格的。 我們就把11號包讀進了我們的快取。進入了“待發送”的狀態。8、9號包已經變成了黃色,表示已經發送出去了。接下來的操作就是一樣的了,確認包後,視窗往後移繼續將未傳送的包讀進快取,把“待發送“狀態的包變為”已傳送“。
丟包情況
有可能我們包發過去,對方的Ack丟了。也有可能我們的包並沒有傳送過去。從傳送方角度看就是我們沒有收到Ack。
發生的情況:一直在等Ack。如果一直等不到的話,我們也會把讀進快取的待發送的包也一起發過去。但是,這個時候我們的視窗已經發滿了。所以並不能把12號包讀進來,而是始終在等待5號包的Ack。
超時重發
這個Ack是要按順序的。必須要等到5的Ack收到,才會把6-11的Ack傳送過去。這樣就保證了滑動視窗的一個順序。 這時候可以看出5號包已經接受到Ack,後面的6、7、8號包也已經發送過去已Ack。視窗便繼續向後移動。
4. 流量控制
如果傳送方把資料傳送得過快,接收方可能會來不及接收,這就會造成資料的丟失。所謂流量控制就是讓傳送方的傳送速率不要太快,要讓接收方來得及接收。原理這就是運用TCP報文段中的視窗大小欄位來控制,傳送方的傳送視窗不可以大於接收方發回的視窗大小。
接收端將自己可以接收的緩衝區大小放入 TCP 首部中的 “視窗大小” 欄位, 通過ACK端通知傳送端;視窗大小欄位越大, 說明網路的吞吐量越高;接收端一旦發現自己的緩衝區快滿了, 就會將視窗大小設定成一個更小的值通知給傳送端;傳送端接受到這個視窗之後, 就會減慢自己的傳送速度;如果接收端緩衝區滿了, 就會將視窗置為0; 這時傳送方不再發送資料, 但是需要定期傳送一個視窗探測資料段, 使接收端把視窗大小告訴傳送端
問題1:視窗關閉是什麼?怎麼解決?
現象:接收方若沒有快取足夠使用,就會發送零視窗大小的報文,此時傳送放將傳送視窗設定為0,停止傳送資料。之後接收方有足夠的快取,傳送了非零視窗大小的報文,但是這個報文在中途丟失,那麼傳送方的傳送視窗就一直為零導致死鎖 。
解決:TCP連線方收到零視窗通知就啟動計時器,傳送視窗探測報文。探測時,若接收視窗仍為0,那接收報文一方就重新啟動計時器;若不是0,死鎖局面打破。
問題2:糊塗視窗綜合徵是什麼?怎麼解決?
接收方騰出幾個位元組告訴傳送方視窗大小,而傳送方會義無反顧傳送這幾個位元組,導致報文利用率很低,這就是糊塗視窗綜合徵
解決方式:
1.讓接收方不通告小視窗給傳送方
if 視窗大小 < min{MSS,快取空間/2}, Then 視窗為0
if 視窗大小 >= MSS 或者接收方 快取空間/2 可用, Then 開啟視窗
2.讓傳送方避免發小資料——延時處理
if (等到視窗大小 >= MSS 或 資料大小>= MSS)&& 收到之前資料ACK回包,Then 發資料
5. 擁塞控制
TCP的擁塞控制由4個核心演算法組成:
- “慢啟動”(Slow Start)
- “擁塞避免”(Congestion voidance)
- “快速重傳 ”(Fast Retransmit)
- “快速恢復”(Fast Recovery)
為了在傳送端調節所要傳送的資料量,定義了一個“擁塞視窗”(Congestion Window),在傳送資料時,將擁塞視窗的大小與接收端ack的視窗大小做比較,取較小者作為傳送資料量的上限。
5.1 慢啟動
TCP源端一開始並不知道網路資源當前狀況,因此新建立的TCP連線不能一開始就傳送大量資料,而只能逐步增加每次傳送的資料量。
源端按cwnd大小發送資料,每收到一個ACK確認,cwnd就增加一個數據包傳送量。為了防止cwnd增長過大引起網路擁塞,還需設定一個慢開始門限ssthresh狀態變數。ssthresh的用法如下:
- 當cwnd<ssthresh時,使用慢開始演算法
- 當cwnd>ssthresh時,改用擁塞避免演算法
- 當cwnd=ssthresh時,慢開始與擁塞避免演算法任意
5.2 擁塞避免
擁塞避免演算法讓擁塞視窗緩慢增長,即每經過一個往返時間RTT就把傳送方的擁塞視窗cwnd加1,而不是加倍。這樣擁塞視窗按線性規律緩慢增長。
無論是在慢開始階段還是在擁塞避免階段,只要傳送方判斷網路出現擁塞(其根據就是沒有收到確認,雖然沒有收到確認可能是其他原因的分組丟失,但是因為無法判定,所以都當做擁塞來處理),就執行慢開始演算法,把慢開始門限ssthresh設定為出現擁塞時的傳送視窗大小的一半。然後把擁塞視窗設定為1。如下圖:
5.3 快重傳與快恢復
快重傳要求接收方在收到一個失序的報文段後就立即發出重複確認(為的是使傳送方及早知道有報文段沒有到達對方)而不要等到自己傳送資料時捎帶確認。快重傳演算法規定,傳送方只要一連收到三個重複確認就應當立即重傳對方尚未收到的報文段,而不必繼續等待設定的重傳計時器時間到期。
快重傳配合使用的還有快恢復演算法,有以下兩個要點:
①當傳送方連續收到三個重複確認時,就執行“乘法減小”演算法,把ssthresh門限減半。但是接下去並不執行慢開始演算法。
②考慮到如果網路出現擁塞的話就不會收到好幾個重複的確認,所以傳送方現在認為網路可能沒有出現擁塞。所以此時不執行慢開始演算法,而是將cwnd設定為ssthresh的大小,然後執行擁塞避免演算法。
問題1:流量控制和擁塞避免有何區別?
流量控制是端到端的控制,例如A通過網路給B發資料,A傳送的太快導致B沒法接收(B緩衝視窗過小或者處理過慢),這時候的控制就是流量控制,原理是通過滑動視窗的大小改變來實現。
擁塞控制是A與B之間的網路發生堵塞導致傳輸過慢或者丟包,來不及傳輸。防止過多的資料注入到網路中,這樣可以使網路中的路由器或鏈路不至於過載。擁塞控制是一個全域性性的過程,涉及到所有的主機、路由器,以及與降低網路效能有關的所有因素。