TCP/IP学习笔记(四)TCP超时重传及拥塞控制
TCP是可靠的傳輸層協(xié)議,但這并不意味著一端發(fā)送的數(shù)據(jù)一定可以到達(dá)另一端,因?yàn)閭鬏斶^(guò)程中遇到的情況是不可控的,很有可能就有某些數(shù)據(jù)發(fā)生丟失,所以”可靠”其實(shí)并不可靠。
不過(guò)畢竟現(xiàn)如今的網(wǎng)絡(luò)設(shè)備還算完善,傳輸過(guò)程中由于硬件錯(cuò)誤導(dǎo)致數(shù)據(jù)丟失的情況基本可以忽略,那么,數(shù)據(jù)丟失的原因就只能是:傳輸路徑過(guò)于擁堵,導(dǎo)致某些路由器或鏈路緩沖區(qū)無(wú)法再容納多余數(shù)據(jù),那么對(duì)于新來(lái)的數(shù)據(jù)包就只能丟掉。
為了解決這一問(wèn)題,保證就算傳輸過(guò)程中遇到再多麻煩,也盡量使數(shù)據(jù)可以順利到達(dá)對(duì)端,TCP引入擁塞控制用于緩解網(wǎng)絡(luò)中的擁堵情況,同時(shí)采用超時(shí)重傳機(jī)制解決數(shù)據(jù)的丟失問(wèn)題
超時(shí)重傳機(jī)制
超時(shí)重傳機(jī)制主要是為了解決數(shù)據(jù)包在傳輸過(guò)程中丟失的問(wèn)題,在上一篇關(guān)于TCP流量控制的介紹中已經(jīng)簡(jiǎn)單接觸過(guò)超時(shí)重傳的概念。TCP每發(fā)送一個(gè)報(bào)文段,就會(huì)為這個(gè)報(bào)文段開(kāi)啟一個(gè)定時(shí)器,如果定時(shí)器溢出時(shí)仍然沒(méi)有收到接收端的應(yīng)答報(bào)文,那么TCP就認(rèn)為這個(gè)報(bào)文段在傳輸過(guò)程中丟失,然后重新發(fā)送這個(gè)報(bào)文段。這便是超時(shí)重傳機(jī)制
以<TCP/IP詳解>中的例子為例,通過(guò)tcpdump抓包分析觀察TCP的重傳
首先和遠(yuǎn)方的某個(gè)服務(wù)器進(jìn)行連接,發(fā)送一些數(shù)據(jù)以確認(rèn)連接正常,隨后拔掉本機(jī)以太網(wǎng)電纜,發(fā)送另一條數(shù)據(jù)
tcpdump的輸出結(jié)果為
可以看到,前三行表示TCP的三次握手,四五行分別表示發(fā)送的”hello world”報(bào)文段以及應(yīng)答報(bào)文段,隨后的若干行表示TCP多次嘗試重新發(fā)送”and hi”報(bào)文段,最后一行發(fā)送復(fù)位報(bào)文段,終止連接
本質(zhì)上就是當(dāng)?shù)谝淮伟l(fā)送”and hi”報(bào)文段時(shí)啟動(dòng)了定時(shí)器,然而在規(guī)定的時(shí)間內(nèi)沒(méi)有收到對(duì)端的回復(fù),所以重新發(fā)送”and hi”報(bào)文段,并重啟定時(shí)器(重啟的定時(shí)器時(shí)間會(huì)增大)
擁塞控制
超時(shí)重傳是為了解決數(shù)據(jù)丟失的問(wèn)題,而數(shù)據(jù)丟失的原因很大程序上是由于傳輸路徑擁塞導(dǎo)致的。在正常的傳輸過(guò)程中,數(shù)據(jù)是從一個(gè)路由器跳到下一個(gè)路由器,每個(gè)路由器都有自己的緩沖區(qū),新來(lái)的數(shù)據(jù)會(huì)存放在緩沖區(qū)中,與此同時(shí)路由器也在不斷地將緩沖區(qū)中的數(shù)據(jù)發(fā)送給下一個(gè)路由器。但是如果某個(gè)路由器接收數(shù)據(jù)的速率大于發(fā)送數(shù)據(jù)的速率,就會(huì)導(dǎo)致緩沖區(qū)數(shù)據(jù)累積,最終填滿緩沖區(qū)。此時(shí)如果再有數(shù)據(jù)到來(lái),緩沖區(qū)已經(jīng)無(wú)法容納它們,只能將它們丟掉,造成數(shù)據(jù)丟失
這就是所謂的擁塞現(xiàn)象,本質(zhì)就是傳輸路徑上的節(jié)點(diǎn)不平衡。為了解決這一問(wèn)題,就需要當(dāng)出現(xiàn)擁塞現(xiàn)象時(shí)立即減少發(fā)送端發(fā)送的數(shù)據(jù)量,為路徑上的某些節(jié)點(diǎn)提供清空緩沖區(qū)的時(shí)間,同時(shí)也避免了不必要的重傳。
但是,發(fā)送端如何才能得知網(wǎng)絡(luò)中發(fā)生了擁塞呢。因?yàn)橛捎谟布e(cuò)誤造成的數(shù)據(jù)丟失是很罕見(jiàn)的,所以發(fā)送端假定,如果出現(xiàn)了數(shù)據(jù)丟失,那么就可以認(rèn)定發(fā)生了擁塞。TCP提供了若干緩解擁塞的算法,如
- 慢啟動(dòng)算法
- 擁塞避免算法
- 快速重傳算法
- 快速恢復(fù)算法
下面會(huì)分別介紹這幾種算法
由上一篇內(nèi)容可知,TCP有一個(gè)叫做流量控制的機(jī)制,它與擁塞控制非常相似,但是仍然有一些差異
- 流量控制是端對(duì)端的控制機(jī)制,兩端各自通知對(duì)方允許的窗口大小以防止對(duì)端發(fā)送過(guò)多數(shù)據(jù)導(dǎo)致自己來(lái)不及處理造成接收緩沖區(qū)被填滿
- 擁塞控制不是端對(duì)端的控制機(jī)制,它是為了緩解從一端到另一端這條路徑上的擁堵問(wèn)題
不過(guò)二者都是通過(guò)限制發(fā)送方發(fā)送的數(shù)據(jù)包個(gè)數(shù)來(lái)解決問(wèn)題,所以上述算法無(wú)非就是降低發(fā)送端發(fā)送速率,緩解網(wǎng)絡(luò)壓力
慢啟動(dòng)
慢啟動(dòng)算法的核心思想是當(dāng)連接剛建立時(shí)允許發(fā)送的報(bào)文段個(gè)數(shù)很少,隨后不斷增加允許發(fā)送的報(bào)文段個(gè)數(shù)直到規(guī)定的閥值
慢啟動(dòng)為發(fā)送方TCP提供了另一個(gè)窗口:擁塞窗口,記為cwnd。在對(duì)滑動(dòng)窗口的介紹中得知,發(fā)送方滑動(dòng)窗口不能大于對(duì)端允許的窗口大小(稱為通知窗口)。通過(guò)通知窗口,發(fā)送方可以得知接收方可以接收的數(shù)據(jù)個(gè)數(shù),從而根據(jù)這個(gè)大小設(shè)置自己的滑動(dòng)窗大小。
有了擁塞窗口的限制,發(fā)送方的滑動(dòng)窗口大小就不能大于擁塞窗口和通知窗口的最小值(多數(shù)情況是等于最小值),TCP就會(huì)根據(jù)這個(gè)最小值發(fā)送數(shù)據(jù)。擁塞窗口在連接建立時(shí)被初始化為1個(gè)報(bào)文段,此后每接收到一個(gè)應(yīng)答報(bào)文,就將擁塞窗口增加,直到增加到慢啟動(dòng)閥值
擁塞窗口增加的規(guī)則是增加對(duì)端接收的報(bào)文段數(shù)。
比如發(fā)送方連續(xù)發(fā)送兩個(gè)報(bào)文段,然后兩個(gè)應(yīng)答報(bào)文段先后被發(fā)給發(fā)送方,那么擁塞窗口會(huì)先后執(zhí)行兩次加一。然而如果對(duì)端將這兩個(gè)應(yīng)答合并成一個(gè)應(yīng)答報(bào)文段發(fā)回發(fā)送端,由于對(duì)端一次應(yīng)答了兩個(gè)報(bào)文段,那么擁塞窗口就直接加二
根據(jù)應(yīng)答報(bào)文段中對(duì)端希望下次接收的序列號(hào)和發(fā)送端滑動(dòng)窗口的左邊界序列號(hào),可以計(jì)算出對(duì)端接收的報(bào)文段數(shù)。
另外,為了表示方便,擁塞窗口的單位是報(bào)文段,一個(gè)報(bào)文段中可能有多個(gè)字節(jié)數(shù)據(jù)。而通知窗口的單位是字節(jié)數(shù),也就是序列號(hào)數(shù)。注意區(qū)分
上圖展現(xiàn)了慢啟動(dòng)算法過(guò)程中擁塞窗口大小的變化情況,擁塞窗口初始為1個(gè)報(bào)文段,所以TCP一次只能發(fā)送一個(gè)報(bào)文段
當(dāng)TCP將這一個(gè)數(shù)據(jù)發(fā)送并得到對(duì)端應(yīng)答后,擁塞窗口加一變?yōu)?。此時(shí)可以發(fā)送兩個(gè)報(bào)文段,然后接收到其中一個(gè)報(bào)文段的應(yīng)答報(bào)文段,擁塞窗口加一變?yōu)?。此時(shí)擁塞窗口為3,由于存在一個(gè)已經(jīng)發(fā)送但是沒(méi)有收到應(yīng)答報(bào)文段,此時(shí)還允許發(fā)送兩個(gè)報(bào)文段,所以接下來(lái)TCP連續(xù)發(fā)送了兩個(gè)報(bào)文段,如此往復(fù)
當(dāng)然,TCP不能放任擁塞窗口這么瘋長(zhǎng)下去,所以設(shè)置了一個(gè)閥值,當(dāng)擁塞窗口增長(zhǎng)到這個(gè)閥值時(shí),慢啟動(dòng)算法就結(jié)束了,隨后會(huì)執(zhí)行擁塞避免算法
擁塞避免算法
擁塞避免算法是當(dāng)擁塞窗口增長(zhǎng)到一定程度時(shí)采取的一種算法,該算法的核心思想是減緩擁塞窗口的增加速度,每接收到一個(gè)應(yīng)答就將擁塞窗口加一
注意擁塞避免算法和慢啟動(dòng)算法對(duì)于擁塞窗口的增加是有區(qū)別的。當(dāng)對(duì)端將多個(gè)應(yīng)答合并成一個(gè)應(yīng)答報(bào)文發(fā)送時(shí)(由于延遲ACK,通常都會(huì)合并發(fā)送),慢啟動(dòng)算法會(huì)將擁塞窗口增加多個(gè)報(bào)文段數(shù)而擁塞避免算法只加一個(gè)
慢啟動(dòng)算法和擁塞避免算法通常配合使用,二者需要TCP發(fā)送端維護(hù)一個(gè)擁塞窗口cwnd和一個(gè)慢啟動(dòng)門限ssthresh(閥值),算法工作過(guò)程為
- 對(duì)一個(gè)給定的連接,初始擁塞窗口為1個(gè)報(bào)文段,同時(shí)設(shè)置慢啟動(dòng)門限為65536字節(jié)
- TCP輸出例程的輸出不能超過(guò)擁塞窗口和通知窗口的大小(二者的最小值是滑動(dòng)窗口的最大值)
- 執(zhí)行慢啟動(dòng)算法,擁塞窗口呈指數(shù)增長(zhǎng),當(dāng)增長(zhǎng)到慢啟動(dòng)門限時(shí)改為擁塞避免算法,使得擁塞窗口呈線性加法增長(zhǎng)
- 當(dāng)擁塞發(fā)生時(shí),將慢啟動(dòng)門限ssthresh改為當(dāng)前窗口的一半,但不能小于2個(gè)報(bào)文段(當(dāng)前窗口指的是滑動(dòng)窗口),然后將擁塞窗口設(shè)置為1一個(gè)報(bào)文段,重新開(kāi)始慢啟動(dòng)算法
圖中慢開(kāi)始指的就是慢啟動(dòng)算法
由圖片可以看到,當(dāng)發(fā)生擁塞時(shí)擁塞窗口立即降為1個(gè)報(bào)文段大小,使得發(fā)送方可以發(fā)送的報(bào)文段數(shù)量急劇下降,這就為傳輸路徑上的節(jié)點(diǎn)清空緩沖區(qū)提供了時(shí)間。此外由于已經(jīng)發(fā)生了擁塞,證明網(wǎng)絡(luò)條件并不是很好,所以擁塞窗口要增長(zhǎng)的慢些,將慢啟動(dòng)門限降為一半便是這個(gè)目的
快速重傳算法
前面介紹到當(dāng)數(shù)據(jù)超時(shí)定時(shí)器溢出時(shí),發(fā)送端便得知有數(shù)據(jù)丟失,從而認(rèn)為網(wǎng)絡(luò)中發(fā)生了擁塞。有什么其他方法可以確定數(shù)據(jù)丟失呢
考慮這樣一種情況,發(fā)送端在發(fā)送若干報(bào)文段后連續(xù)發(fā)送了多個(gè)報(bào)文段[1001:2000],[2001:3000],[3001:4000]…,但是只有后幾個(gè)報(bào)文段成功到達(dá)對(duì)端,由于對(duì)端希望接收的序列號(hào)是1001,所以接收端發(fā)送給發(fā)送端的所有應(yīng)答報(bào)文段中攜帶的序列號(hào)仍然都是1001。
快速重傳算法的核心思想就是當(dāng)發(fā)送端接收到了三個(gè)相同的應(yīng)答報(bào)文(攜帶的希望下次接收的序列號(hào)相同)時(shí),就假設(shè)以該序列號(hào)結(jié)尾的那個(gè)報(bào)文段丟失,所以發(fā)送端不必等到定時(shí)器溢出就會(huì)重傳丟失的報(bào)文段
快速恢復(fù)算法
快速重傳算法僅僅是為了盡早發(fā)現(xiàn)丟失報(bào)文段并重傳,并不能確定網(wǎng)絡(luò)發(fā)生擁塞(如果發(fā)生嚴(yán)重的擁塞,就不會(huì)一連有好幾個(gè)報(bào)文段到達(dá)接收端,也就不會(huì)一連收到接收端發(fā)來(lái)的好幾個(gè)重復(fù)應(yīng)答報(bào)文段),所以不會(huì)執(zhí)行慢啟動(dòng)算法將擁塞窗口降為1
快速重傳法和快速恢復(fù)法的執(zhí)行過(guò)程如下
- 當(dāng)發(fā)送方連續(xù)收到三個(gè)重復(fù)應(yīng)答報(bào)文時(shí),就將慢啟動(dòng)門限ssthresh減半
- 將擁塞窗口降為減半后的ssthresh值+三個(gè)報(bào)文段
- 開(kāi)始執(zhí)行擁塞避免算法,緩慢增加擁塞窗口
加三個(gè)報(bào)文段的原因是發(fā)送端目前可以確定接收方已經(jīng)接收到三個(gè)報(bào)文段(通過(guò)接收到三個(gè)重復(fù)應(yīng)答報(bào)文得知),所以可以確定這三個(gè)報(bào)文段沒(méi)有滯留在傳輸路徑上,也就沒(méi)有加重網(wǎng)絡(luò)負(fù)擔(dān),所以可以加上三個(gè)報(bào)文段大小
在舊版的快速重傳算法中還是使用慢啟動(dòng),但是正如上面所述,網(wǎng)絡(luò)很可能沒(méi)有發(fā)生擁塞,所以在修正后的版本中使用快速恢復(fù)算法
重新分組
現(xiàn)考慮一種情況,發(fā)送端連續(xù)發(fā)送M1,M2,M3三個(gè)報(bào)文段,但只有M1順利到達(dá)而M2和M3都在傳輸過(guò)程中丟失。如果按正常的流程,發(fā)送端TCP會(huì)先后重傳M2和M3兩個(gè)報(bào)文段。
但是從節(jié)省報(bào)文段數(shù)量的角度思考,如果將M2和M3合并成一個(gè)新的報(bào)文段進(jìn)行重傳,就能夠減少傳輸過(guò)程中的報(bào)文段數(shù)量,在某種程度上也減輕了網(wǎng)絡(luò)負(fù)擔(dān)
由于TCP數(shù)據(jù)都是基于序列號(hào)的,每個(gè)數(shù)據(jù)都有唯一的序列號(hào),所以可以將兩段數(shù)據(jù)合成一段
再次使用<TCP/IP詳解>中的例子,示例中首先發(fā)送一個(gè)報(bào)文段確認(rèn)連接正常,然后斷開(kāi)以太網(wǎng)電纜并發(fā)送兩個(gè)報(bào)文段(由于網(wǎng)絡(luò)連接中斷,這兩個(gè)報(bào)文段必將重傳),最后插上以太網(wǎng)電纜
觀察tcpdump輸出結(jié)果
從圖中可以看到發(fā)送”line number 2”報(bào)文段時(shí)由于網(wǎng)絡(luò)原因進(jìn)行了兩次重傳,隨后鍵入”and 3”嘗試發(fā)送,發(fā)現(xiàn)TCP將這兩個(gè)報(bào)文段合并成一個(gè)進(jìn)行發(fā)送(從圖中數(shù)據(jù)個(gè)數(shù)為20得知)
總結(jié)
以上是生活随笔為你收集整理的TCP/IP学习笔记(四)TCP超时重传及拥塞控制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: TCP/IP学习笔记(三)TCP流量控制
- 下一篇: TCP/IP学习笔记(五)TCP的保活定