TCP協議如何保證可靠傳輸
概述:
TCP協議保證數據傳輸可靠性的方式主要有:
(校 序 重 流 擁)
校驗和:
發送的數據包的二進制相加然后取反,目的是檢測數據在傳輸過程中的任何變化。如果收到段的檢驗和有差錯,TCP將丟棄這個報文段和不確認收到此報文段。
確認應答+序列號(累計確認+seq):
接收方收到報文就會確認(累積確認:對所有按序接收的數據的確認)
TCP給發送的每一個包進行編號,接收方對數據包進行排序,把有序數據傳送給應用層。
超時重傳:
當TCP發出一個段后,它啟動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。
流量控制:
TCP連接的每一方都有固定大小的緩沖空間,TCP的接收端只允許發送端發送接收端緩沖區能接納的數據。當接收方來不及處理發送方的數據,能提示發送方降低發送的速率,防止包丟失。TCP使用的流量控制協議是可變大小的滑動窗口協議。
接收方有即時窗口(滑動窗口),隨ACK報文發送
擁塞控制:
當網絡擁塞時,減少數據的發送。
發送方有擁塞窗口,發送數據前比對接收方發過來的即使窗口,取小
慢啟動、擁塞避免、擁塞發送、快速恢復
應用數據被分割成TCP認為最適合發送的數據塊。
TCP的接收端會丟棄重復的數據。
校驗和
確認應答和序列號
序列號:TCP傳輸時將每個字節的數據都進行了編號,這就是序列號。
確認應答:TCP傳輸的過程中,每次接收方收到數據后,都會對傳輸方進行確認應答。也就是發送ACK報文。
這個ACK報文當中帶有對應的確認序列號,告訴發送方,接收到了哪些數據,下一次的數據從哪里發。
序列號的作用不僅僅是應答的作用,有了序列號能夠將接收到的數據根據序列號排序,並且去掉重復序列號的數據。
這也是TCP傳輸可靠性的保證之一。
超時重傳
在進行TCP傳輸時,由於確認應答與序列號機制,也就是說發送方發送一部分數據后,都會等待接收方發送的ACK報文,並解析ACK報文,判斷數據是否傳輸成功。
如果發送方發送完數據后,遲遲沒有等到接收方的ACK報文,這該怎么辦呢?而沒有收到ACK報文的原因可能是什么呢?
首先,發送方沒有接收到響應的ACK報文原因可能有兩點:
a、數據在傳輸過程中由於網絡原因等直接全體丟包,接收方沒有接收到。
b、接收方接收到了響應的數據,但是發送的ACK報文響應卻由於網絡原因丟包了。
TCP在解決這個問題的時候引入了一個新的機制,叫做超時重傳機制。
簡單理解就是發送方在發送完數據后等待一個時間,時間到達沒有接收到ACK報文,那么對剛才發送的數據進行重新發送。
如果是剛才第一個原因,接收方收到二次重發的數據后,便進行ACK應答。
如果是第二個原因,接收方發現接收的數據已存在(判斷存在的根據就是序列號,所以上面說序列號還有去除重復數據的作用),那么直接丟棄,仍舊發送ACK應答。
那么發送方發送完畢后等待的時間是多少呢?如果這個等待的時間過長,那么會影響TCP傳輸的整體效率,如果等待時間過短,又會導致頻繁的發送重復的包。如何權衡?
由於TCP傳輸時保證能夠在任何環境下都有一個高性能的通信,因此這個最大超時時間(也就是等待的時間)是動態計算的。
注意:
超時以500ms(0.5秒)為一個單位進行控制,每次判定超時重發的超時時間都是500ms的整數倍。
重發一次后,仍未響應,那么等待2*500ms的時間后,再次重傳。等待4*500ms的時間繼續重傳。以一個指數的形式增長。
累計到一定的重傳次數,TCP就認為網絡或者對端出現異常,強制關閉連接。
連接管理
流量控制
接收端在接收到數據后,對其進行處理。如果發送端的發送速度太快,導致接收端的結束緩沖區很快的填充滿了。此時如果發送端仍舊發送數據,那么接下來發送的數據都會丟包,繼而導致丟包的一系列連鎖反應,超時重傳呀什么的。而TCP根據接收端對數據的處理能力,決定發送端的發送速度,這個機制就是流量控制。
簡單來說就是接收方處理不過來的時候,就把窗口縮小,並把窗口值告訴發送端。
在這里只考慮A向B發送數據,假設在連接在建立時,B告訴A:我的接收窗口rwnd=400(receiver window),不過在報文中已經省略了
如果接收到窗口大小的值為0,那么發送方將停止發送數據。並定期的向接收端發送窗口探測數據段,讓接收端把窗口大小告訴發送端。
擁塞控制
如果網絡出現擁塞,分組將會丟失,此時發送方會繼續重傳,從而導致網絡擁塞程度更高。因此當出現擁塞時,應當控制發送方的速率。
這一點和流量控制很像,但是出發點不同。流量控制是為了讓接收方能來得及接收,而擁塞控制是為了降低整個網絡的擁塞程度。
TCP 主要通過四個算法來進行擁塞控制:慢開始、擁塞避免、快重傳、快恢復。
慢開始算法原理
發送方需要維護一個叫做擁塞窗口(cwnd)的狀態變量,注意擁塞窗口與發送方窗口的區別:擁塞窗口只是一個狀態變量,實際決定發送方能發送多少數據的是發送方窗口。
為了便於討論,做如下假設:
- 接收方有足夠大的接收緩存,因此不會發生流量控制;
- 雖然 TCP 的窗口基於字節,但是這里設窗口的大小單位為報文段。
當TCP連接進行初始化是,將擁塞窗口置為1。
圖中的窗口單位不再使用字節而使用報文段。
慢開始門限的初始值設置為16個報文段,即ssthresh=16;
慢開始和擁塞避免
1.然后開始慢開始算法(指數增長)。當cwnd=16時開始執行擁塞避免算法,呈現線性增長。
2.當擁塞窗口cwnd=24時出現超時,發送方判定為網絡擁塞,於是調整門限值ssthresh=cwnd/2=12,同時設置擁塞窗口為1,進入慢開始階段。
3.按照慢開始算法,發送方每收到一個新報文段的確認ACK擁塞窗口值增加。當cwnd=12時(圖中點3)執行擁塞避免算法
快重傳和快恢復
4 .當cwnd=16時(圖中點4)出現了一個新的情況,就是發送方連續收到3個對統一報文段的重復確認(3-ACK)。發送方執行快重傳和快恢復算法。
5 在圖中點4,發送方知道只是丟失了個別的報文段,於是不啟動慢開始,而是先進行快重傳然后執行快恢復算法。
發送方設置調整門限值ssthresh=cwnd/2=8, 同時擁塞窗口cwnd=ssthresh=8(點5),然后進行擁塞避免算法
快重傳:收到3個同樣的確認就立刻重傳,不等到超時;
快恢復:cwnd不是從1重新開始。
滑動窗口
實際中的傳輸方式,
需要說明一下,如果你不了解TCP的滑動窗口這個事,你等於不了解TCP協議。
我們都知道,TCP必需要解決的可靠傳輸以及包亂序(reordering)的問題,
所以,TCP必需要知道網絡實際的數據處理帶寬或是數據處理速度,這樣才不會引起網絡擁塞,導致丟包。
發送方滑動窗口示意圖:
上圖中分成了四個部分,分別是:(其中那個黑模型就是滑動窗口)
#1已收到ack確認的數據。
#2已發出但還沒收到ack的。
#3在窗口中還沒有發出的(接收方還有空間)。
#4窗口以外的數據(接收方沒空間)
注意:
滑動窗口里是 已發出但未收到ACk、還未發出的 數據
下面是個滑動后的示意圖(收到36的ack,並發出了46-51的字節):
參考博客:
http://uule.iteye.com/blog/2429131
https://www.cnblogs.com/deliver/p/5471231.html