一、總述
TCP,Transmission Control Protocol,是一個(gè)面向連接、基于流式傳輸的可靠傳輸協(xié)議,考慮到的內(nèi)容很多,比如數(shù)據(jù)包的丟失、損壞、分片和亂序等,TCP協(xié)議通過多種不同的機(jī)制來實(shí)現(xiàn)可靠傳輸。今天,重點(diǎn)分析重傳機(jī)制、滑動窗口,以及擁塞控制。
二、重傳機(jī)制
在三握四揮的過程中,服務(wù)器和客戶端之間就通過帶有不同標(biāo)志位的TCP報(bào)文來通知或判斷對端或本地是否成功建立、斷開連接。
接收主機(jī)在接收到數(shù)據(jù)之后往往都會返回一個(gè)應(yīng)答消息,網(wǎng)絡(luò)錯(cuò)綜復(fù)雜,面對隨時(shí)可能發(fā)生的數(shù)據(jù)丟失問題,TCP使用重傳機(jī)制解決。常見的重傳機(jī)制有以下四種:
- 超時(shí)重傳
- 快速重傳
- SACK
- D_SACK
(一) 超時(shí)重傳
超時(shí)重傳,顧名思義,在發(fā)送數(shù)據(jù)時(shí),會設(shè)定一個(gè)定時(shí)器,當(dāng)超過指定的時(shí)間過后,沒有收到對端的ACK確認(rèn)應(yīng)答報(bào)文,就會重寫發(fā)送該數(shù)據(jù)。而這又可以分為兩種情況:
- 數(shù)據(jù)包丟失
- ACK確認(rèn)應(yīng)答丟失
在了解如何設(shè)置超時(shí)時(shí)間之前,先來看看什么是RTT(Round-Trip Time)往返時(shí)延。
RTT,往返時(shí)延,數(shù)據(jù)從一端到另一端。其中,往返這個(gè)詞是表明了什么范圍是所需的時(shí)間。
知道了RTT,在來看點(diǎn)相關(guān)的:RTO,Retransmission Timeout,直譯“超時(shí)重傳時(shí)間”。這個(gè)時(shí)間的設(shè)置毫無疑問關(guān)系到我們重傳機(jī)制的效率高低,看以下兩種情況:
- RTO>>RTT,重發(fā)慢,沒有效率;
- RTO<<RTT,包可能還沒到就開始重發(fā),重發(fā)出去的包數(shù)量多了,網(wǎng)絡(luò)無疑會擁塞,超時(shí)的包越來越多,惡性循環(huán)。
那么結(jié)論顯而易見——RTO的值,應(yīng)該略大于RTT。
很容易想到的是,報(bào)文往返的RTT值會是經(jīng)常變化的,所以RTO也應(yīng)該是一個(gè)動態(tài)變化的值。(在Linux中,通常會采樣RTT的值然后加權(quán)算平均,不詳細(xì)談了)
而在超時(shí)時(shí),TCP的策略是超時(shí)間隔加倍。
(二) 快速重傳
Fast Retransmit,快速重傳,不以時(shí)間為驅(qū)動,而以數(shù)據(jù)驅(qū)動重傳。
在上圖中,Seq2一直沒有成功被接收方收到,當(dāng)發(fā)送端收到三個(gè)Ack=2的確認(rèn),就會在定時(shí)器過期之前,重傳丟失的Seq2。
不過,發(fā)送方并不知道Ack=2是誰傳回來的,那么是重傳Seq2還是把之前的所有包都重傳呢?根據(jù)TCP實(shí)現(xiàn)的不同,上述兩種情況都是可能的。
(三) SACK
SACK是指Selective Acknowledgment,選擇性確認(rèn),這種方式通過在TCP頭部"選項(xiàng)"字段添加一個(gè)SACK,把緩存的地圖發(fā)送給發(fā)送方,這樣發(fā)送方就知道哪些數(shù)據(jù)需要重傳了。
如果要支持SACK,雙方都要支持,在Linux下,通過net.ipv4.tcp_sack這個(gè)參數(shù)打開(Linux2.4后默認(rèn)打開)。
(四) Duplicate SACK
D_SACK,主要使用SACK來通知發(fā)送方有哪些數(shù)據(jù)被重復(fù)接收了,下面通過兩個(gè)例子來說明,這個(gè)Duplicate到底有什么妙用。
- ACK丟包
發(fā)送端通過ACK和SACK就可以明確,是發(fā)出去的包丟了還是接收方返回的ACK確認(rèn)報(bào)文丟了。
- 網(wǎng)絡(luò)延時(shí)
在判定網(wǎng)絡(luò)延遲時(shí),Duplicate的含義才更加明顯地體現(xiàn)了出來,即復(fù)制的、完全一樣的。
如上圖中提及,在經(jīng)歷了網(wǎng)絡(luò)延遲和三次相同ACK觸發(fā)快速重傳后,網(wǎng)絡(luò)延遲的包終于送達(dá),此時(shí)返回ACK=3000,SACK=1000~1500(注意之前的SACK范圍總是大于ACK),就知道了這個(gè)SACK是D_SACK,是重復(fù)的包。
三、滑動窗口(流量控制)
(一) 滑動窗口
滑動窗口,Sliding Window,是一種流量控制機(jī)制,同時(shí)也是一種保持通信效率的技術(shù)。已知的是,每當(dāng)有一個(gè)數(shù)據(jù)包發(fā)出,發(fā)送端總盼望得到一個(gè)ACK確認(rèn);那么要是在得到ACK之前不做任何動作,效率的高低明顯可見。
為此,TCP引入了窗口的概念,通過指定窗口大?。〝?shù)據(jù)最大值),來進(jìn)行無需等待確認(rèn)應(yīng)答的通信。
在實(shí)際實(shí)現(xiàn)時(shí),是由操作系統(tǒng)開辟一個(gè)緩存空間。在發(fā)送方得到確認(rèn)應(yīng)答前,已發(fā)送的數(shù)據(jù)都會保存在緩沖區(qū),如果按期收到確認(rèn)應(yīng)答,此時(shí)數(shù)據(jù)就可以從緩沖區(qū)清除。
如此一來,有了累計(jì)確認(rèn)(或累計(jì)應(yīng)答)模式:
- 那么引申出一個(gè)問題——窗口的大小由哪一方?jīng)Q定?
TCP報(bào)頭中有一個(gè)16位的字段:窗口尺寸Window,這個(gè)字段是由接收方通知發(fā)送方自己還有多少緩沖區(qū)可以用來接收數(shù)據(jù)。以免接收方無法正常接收到數(shù)據(jù)。
- 發(fā)送方,滑動窗口分為4個(gè)部分
它的工作方式很容易想到:ACK確認(rèn)一部分,可用窗口就擴(kuò)大一部分;當(dāng)發(fā)送窗口滿了,在接收ACK之前就不再發(fā)送數(shù)據(jù)。
- 接收方,滑動窗口分為3個(gè)部分
值得注意的是,兩個(gè)窗口的大小是約等于的關(guān)系,而不是一模一樣。因?yàn)榛瑒哟翱诓皇且怀刹蛔兊摹H绻邮辗降淖x取速度有了很大提升,會通過TCP報(bào)文通知發(fā)送方新的窗口大小。
(二) 窗口關(guān)閉問題
TCP中,通過接收方指定窗口尺寸來進(jìn)行流量控制。在通信中,當(dāng)接收方窗口被填滿,會向發(fā)送方說明窗口尺寸位0;等處理好數(shù)據(jù)后,才會又通告一個(gè)窗口非0的ACK報(bào)文。不過,要是這個(gè)非0報(bào)文丟失,就會陷入死鎖的狀態(tài)(雙方同時(shí)等待)。
- 窗口探測報(bào)文
為了解決這個(gè)問題,TCP為每個(gè)連接設(shè)置了一個(gè)持續(xù)計(jì)時(shí)器,只要收到0窗口通告,就啟動計(jì)時(shí)器。當(dāng)計(jì)時(shí)器超時(shí),就會發(fā)送窗口探測報(bào)文,這個(gè)報(bào)文的用意顯而易見。(窗口探測的次數(shù)一般是3次)。
(三) 糊涂窗口問題
糊涂窗口是指接收方在處理數(shù)據(jù)時(shí)的速度過慢,導(dǎo)致窗口的尺寸不斷變小的現(xiàn)象。實(shí)際上就是兩個(gè)動作讓這個(gè)現(xiàn)象出現(xiàn):
- 接收方通告小窗口
- 發(fā)送方發(fā)送小數(shù)據(jù)
想要避免這種現(xiàn)象,解決上述兩個(gè)問題就好了。
- 在接收方,當(dāng)窗口小于min(MSS, 緩存空間/2),就會告知對方0窗口,到后面合適的時(shí)機(jī)再通知非0窗口。
- 在發(fā)送方,使用Nagle算法進(jìn)行延時(shí)處理,要等到發(fā)送窗口大小>=MSS,或者接收到ACK確認(rèn)報(bào)文,才會停止囤積數(shù)據(jù)。這個(gè)算法是默認(rèn)打開的,在使用telnet和ssh等交互性比較強(qiáng)的程序時(shí),通過TCP_NODELAY來關(guān)閉。
四、擁塞控制
(一) 什么是擁塞
上文的流量控制是避免發(fā)送方的數(shù)據(jù)填滿接收方的緩存,而擁塞控制,則是為了避免在整個(gè)網(wǎng)絡(luò)環(huán)境處于擁堵時(shí),還繼續(xù)發(fā)送大量數(shù)據(jù)包的手段(可能導(dǎo)致數(shù)據(jù)包時(shí)延、丟失等,重傳也會加重?fù)砣?/p>
那么很明顯,擁塞控制是在發(fā)送端實(shí)現(xiàn)的。為了調(diào)節(jié)發(fā)送數(shù)據(jù)的量,定義了“擁塞窗口”的概念。
(二) 什么是擁塞窗口
擁塞窗口,是一個(gè)由發(fā)送方維護(hù)的狀態(tài)變量,根據(jù)網(wǎng)絡(luò)的擁塞程度動態(tài)變化。前面的發(fā)送窗口和接收窗口在有了擁塞窗口的加入以后,是這樣的關(guān)系:
- 發(fā)送=min(擁塞,接收)
擁塞窗口的動態(tài)變化也很簡答:有擁塞,就變小;沒擁塞,就變大。
(三) 如何判斷擁塞
只要發(fā)送方?jīng)]在規(guī)定的時(shí)間內(nèi)接收到ACK確認(rèn)報(bào)文(發(fā)生超時(shí)重傳),就會認(rèn)為網(wǎng)絡(luò)出現(xiàn)了擁塞。
(四) 擁塞控制算法——慢啟動
TCP在剛建立完連接后,會經(jīng)歷慢啟動,逐步提高發(fā)送數(shù)據(jù)包的數(shù)量。規(guī)則是:
- 發(fā)送方每收一個(gè)ACK,擁塞窗口cwnd的大小就增加1。
所以,這個(gè)增長是指數(shù)性的。
那什么時(shí)候是個(gè)頭呢?——當(dāng)達(dá)到慢啟動門限(slow start threshold)后,就會使用擁塞避免算法。
(五) 擁塞避免算法
慢啟動門限ssthresh一般的大小為65535字節(jié),在進(jìn)入擁塞避免算法后,窗口增長的規(guī)則是:
- 每當(dāng)收到一個(gè)ACK,cwnd增加1/cwnd。
如此一來,線性增長。
在此后一直增長,網(wǎng)絡(luò)就會進(jìn)入擁塞的狀態(tài),出現(xiàn)丟包和丟包重傳,觸發(fā)了重傳,也就進(jìn)入了擁塞發(fā)生算法。
(六) 擁塞發(fā)生
在上文提到過,重傳的機(jī)制也有兩種:1. 超時(shí)重傳,2. 快速重傳。接下來進(jìn)行分述:
- 超時(shí)重傳的擁塞發(fā)生算法
ssthresh設(shè)置為cwnd/2,cwnd重置為1,然后重新開始慢啟動。不過這種方式會突然減少數(shù)據(jù)流,可能網(wǎng)絡(luò)卡頓(就像是急剎車)。
- 快速重傳的擁塞發(fā)生算法
在快速重傳時(shí),接收方發(fā)送三次前一個(gè)包的ACK通知發(fā)送端重傳(大部分沒丟,只丟了小部分)。
cwnd=cwnd/2,ssthresh=cwnd,然后進(jìn)入快速恢復(fù)算法。
(七) 快速恢復(fù)
快速重傳一般和快速恢復(fù)算法同時(shí)使用,這種情況會判斷網(wǎng)絡(luò)情況并不是特別嚴(yán)峻,反映也不會像RTO那樣強(qiáng)烈。
快速恢復(fù)算法:
- cwnd=ssthresh+3
- 重傳丟失的數(shù)據(jù)包
- 如果再收到重復(fù)的ACK,cwnd+1
- 如果收到新ACK(說明D_SACK時(shí)的數(shù)據(jù)全部收到,恢復(fù)過程結(jié)束),cwnd=ssthresh,恢復(fù)到之前二點(diǎn)擁塞避免狀態(tài)。
本文作為筆記,圖片來源:文章來源:http://www.zghlxwxcb.cn/news/detail-846648.html
30 張圖解: 面試必問的 TCP 重傳、滑動窗口、流量控制、擁塞控制_面試回答 tcp流量控制-CSDN博客https://blog.csdn.net/qq_34827674/article/details/105606205文章來源地址http://www.zghlxwxcb.cn/news/detail-846648.html
到了這里,關(guān)于TCP重傳機(jī)制、滑動窗口、擁塞控制的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!