1塞茅、背景介紹
TCP使用可靠的傳輸協(xié)議亩码,即意味著必須按序、無差錯(cuò)的傳送數(shù)據(jù)到目的端野瘦,那么如果在傳輸過程中發(fā)送的包丟失了該怎么辦描沟?TCP的重傳機(jī)制就是:如果發(fā)送方認(rèn)為發(fā)生了丟包現(xiàn)象就重發(fā)這些數(shù)據(jù)包。顯然鞭光,我們需要一個(gè)方法去猜測是否發(fā)生了丟包吏廉。最簡單的想法就是,接收方每接收到一個(gè)包就向發(fā)送者返回一個(gè)ACK惰许,表示自己已經(jīng)收到了這段數(shù)據(jù)席覆,反過來,如果發(fā)送方一段時(shí)間內(nèi)沒有收到ACK汹买,就知道很可能是數(shù)據(jù)包丟失了佩伤,緊接著就重發(fā)該數(shù)據(jù)包聊倔,直到收到ACK為止。
為什么是猜測呢生巡? 因?yàn)榧词故浅瑫r(shí)了耙蔑,這個(gè)數(shù)據(jù)包也可能并沒有丟,它只是繞了段遠(yuǎn)程孤荣,來的很晚而已甸陌。畢竟TCP協(xié)議是位于傳輸層的協(xié)議,不可能明確知道數(shù)據(jù)鏈路層和物理層發(fā)生了什么垃环。但是這并不妨礙我們的超時(shí)重傳機(jī)制邀层,因?yàn)榻邮辗綍?huì)自動(dòng)忽略收到的重復(fù)的包。
下面我們具體講一講TCP的重傳機(jī)制:
2遂庄、重傳--TCP的重要事件
(1)基于計(jì)時(shí)器的重傳---超時(shí)重傳
這種機(jī)制下寥院,每個(gè)數(shù)據(jù)包都有相應(yīng)的計(jì)時(shí)器,當(dāng)超過指定的時(shí)間后涛目,沒有收到對方的 ACK 確認(rèn)應(yīng)答報(bào)文就會(huì)重發(fā)該數(shù)據(jù)包秸谢。
超時(shí)時(shí)間應(yīng)該設(shè)置為多少
我們先來了解一下 RTT (Round-Trip Time 往返時(shí)延)
而超時(shí)時(shí)間是以 RTO(Retransmission Timeout 超時(shí)重傳時(shí)間)表示。
超時(shí)時(shí)間不宜設(shè)置的過長或過短霹肝,否則:
綜上可知估蹄,RTO設(shè)置的值應(yīng)該略大于RTT的值。
RTO值的計(jì)算:
https://blog.csdn.net/JXH_123/article/details/27345151
值得注意的是:每觸發(fā)一次超時(shí)重傳沫换,都會(huì)將下一次超時(shí)時(shí)間間隔設(shè)為先前值的兩倍臭蚁。遇到超時(shí)說明網(wǎng)絡(luò)環(huán)境差,不宜頻繁發(fā)送讯赏。
Wireshark 抓包顯示:
超時(shí)重傳存在的問題是:
?當(dāng)一個(gè)報(bào)文段丟失時(shí)垮兑,會(huì)等待一定的超時(shí)時(shí)間后才重傳,增加了端到端的時(shí)延漱挎;
?當(dāng)一個(gè)報(bào)文段丟失時(shí)系枪,在其等待超時(shí)的過程中,可能會(huì)出現(xiàn)這種情況: 其后的報(bào)文段已經(jīng)被接收端接收但卻遲遲得不到確認(rèn)磕谅,發(fā)送端就也以為丟失了私爷,從而引起不必要的重傳,既浪費(fèi)時(shí)間也浪費(fèi)資源膊夹。(例如: 數(shù)據(jù)包5丟失衬浑,數(shù)據(jù)包6、7放刨、8嚎卫、9都已到達(dá)接收方,這個(gè)時(shí)候客戶端只能等服務(wù)端發(fā)送ACK,因此對于客戶端來說拓诸,它完全不知道丟了幾個(gè)包,可能就悲觀的認(rèn)為:5后面的數(shù)據(jù)包都丟了麻昼,就重傳這5個(gè)數(shù)據(jù)包奠支,這就比較浪費(fèi)了)。
(2)基于接收方的反饋信息的重傳---快速重傳
剛剛提到過抚芦,基于計(jì)時(shí)器的重傳往往要等待很長時(shí)間倍谜,而快速重傳使用了很巧妙的方法來解決這個(gè)問題。
快速重傳(Fast Retransmit)機(jī)制不以時(shí)間為驅(qū)動(dòng)叉抡,而是以數(shù)據(jù)為驅(qū)動(dòng)重傳尔崔。
由于TCP采用的是累計(jì)確認(rèn)機(jī)制,當(dāng)接收端收到比期望序號大的報(bào)文段時(shí)褥民,便會(huì)重復(fù)發(fā)送最近一次確認(rèn)的報(bào)文段的確認(rèn)號季春,即 冗余 ACK (Duplicate ACK)。
這樣消返,如果在超時(shí)重傳定時(shí)器溢出之前载弄,接收到連續(xù)的三個(gè)重復(fù)冗余 ACK (第一個(gè)ACK是正常的,后三個(gè)是冗余的)撵颊,發(fā)送端便知曉哪個(gè)報(bào)文段在傳輸過程中丟失了宇攻,于是重發(fā)該報(bào)文段,而不需要等待超時(shí)重傳定時(shí)器溢出倡勇,大大提高了效率逞刷。
Wireshark 抓包顯示:
但是,快速重傳仍然沒有解決第二個(gè)問題:到底該重傳多少個(gè)包妻熊?
(3)帶選擇確認(rèn)的重傳---SACK
改進(jìn)的方法就是 SACK (Selective Acknowledgment)夸浅,簡單來說就是在快速重傳的基礎(chǔ)上,返回最近收到的報(bào)文段的序列號范圍固耘,這樣客戶端就知道题篷,哪些數(shù)據(jù)包已經(jīng)到達(dá)服務(wù)器了。
看下例子:
存在 SACK 選項(xiàng)時(shí)
當(dāng)500-599報(bào)文到達(dá)厅目,接收方發(fā)送? ACK 200? 番枚,SACK [500,600)
當(dāng)600-699報(bào)文到達(dá),接收方發(fā)送? ACK 200? 损敷,SACK [500,700)
當(dāng)700-799報(bào)文到達(dá)
當(dāng)800-899報(bào)文到達(dá)
當(dāng)900-999報(bào)文到達(dá)葫笼,接收方累積確認(rèn)發(fā)送? ACK 200? ,SACK [500,1000)
連續(xù)收到3個(gè)重復(fù)ACK拗馒,發(fā)送方經(jīng)檢查發(fā)現(xiàn)200-499的數(shù)據(jù)丟失了路星,執(zhí)行快速重傳,待接收方接收到200-499的數(shù)據(jù),并返回 ACK 1000時(shí)洋丐,發(fā)送方的所有數(shù)據(jù)均已確認(rèn)完畢呈昔,移動(dòng)滑動(dòng)窗口到1000位置處。
使用 SACK可以告知發(fā)送方 收到了哪些數(shù)據(jù)友绝,發(fā)送方收到這些消息后就會(huì)知道哪些數(shù)據(jù)丟失堤尾,然后立即重傳丟失的部分。
需要注意的是:只有收到失序的分組時(shí)才可能會(huì)發(fā)送SACK迁客。
SACK 包括了兩個(gè)TCP選項(xiàng)郭宝,一個(gè)選項(xiàng)用于標(biāo)識是否支持 SACK(SACK_Permitted),在TCP建立連接時(shí)發(fā)送掷漱;另一種選項(xiàng)則包含了具體的 SACK信息粘室。
(1)SACK_Permitted 選項(xiàng)
該選項(xiàng)只允許在TCP連接建立時(shí),有 SYN標(biāo)志的包中設(shè)置卜范,在連接建立階段衔统,主動(dòng)發(fā)起連接的一方在它的SYN中指定選項(xiàng)。只有在它從另一方的SYN中收到了這個(gè)選項(xiàng)之后先朦,SACK機(jī)制才會(huì)被使能缰冤。
(2)SACK 信息選項(xiàng)
SACK 選項(xiàng)參數(shù)告訴對方已經(jīng)接收到并緩存的不連續(xù)的數(shù)據(jù)塊,發(fā)送方可據(jù)此信息檢查究竟是哪個(gè)塊丟失喳魏,從而發(fā)送相應(yīng)的數(shù)據(jù)塊棉浸。
?Left Edge:本區(qū)塊的第一個(gè)序號。 Right Edge:本區(qū)塊的最后序號的下一個(gè)序號刺彩。
[Left Edge, Right Edge)區(qū)間的ACK 序號表示本次確認(rèn)收到的序號迷郑。
問題1:SACK選項(xiàng)最多能包含多少個(gè)需重傳的塊?
?????? 由于TCP首部的最大長度為 60 byte创倔,而固定首部占用了 20 byte嗡害,對于SACK選項(xiàng)本身占用了2 byte,所以剩下 60-20-2=38 byte畦攘。而每個(gè)塊(包括開始和結(jié)束)占用 8 byte霸妹,所以最多可標(biāo)識的塊數(shù)為 38/8 = 4塊,所以 SACK 最多可以包括4個(gè)需重傳的塊知押。同時(shí)由于SACK有些時(shí)候會(huì)和時(shí)間戳(占10字節(jié))一起用叹螟,因此,此種情況下最多只有3個(gè)SACK台盯。
問題2:SACK選項(xiàng)的使用規(guī)則是怎么樣的罢绽?
SACK 的發(fā)送方,即 報(bào)文的接收端
第一個(gè)塊需要指出是哪一個(gè)到達(dá)的報(bào)文觸發(fā)的 SACK
盡可能多的把所有的塊填滿
SACK 要報(bào)告最近接收的不連續(xù)的數(shù)據(jù)塊
SACK 的接收端静盅,即 報(bào)文的發(fā)送端:
數(shù)據(jù)沒有被確認(rèn)前良价,都會(huì)保持在滑動(dòng)窗口內(nèi)
每個(gè)數(shù)據(jù)包都有一個(gè) SACKed 的標(biāo)志,對于已經(jīng)標(biāo)示的報(bào)文,再次接收到時(shí)會(huì)忽略
?如果SACK丟失明垢,超時(shí)重傳之后蚣常,重置所有數(shù)據(jù)包SACKed 標(biāo)志
(4)帶重復(fù)選擇確認(rèn)的重傳---DSACK
DSACK是在SACK的基礎(chǔ)上做了一些擴(kuò)展,主要用于對收到的重復(fù)報(bào)文進(jìn)行了處理袖外。
它的主要作用是:告訴發(fā)送方有哪些數(shù)據(jù)被重復(fù)接收了史隆。
DSACK同樣使用了與SACK一樣的報(bào)文格式,唯一區(qū)別在于:第一個(gè)連續(xù)的block指定的是觸發(fā)DSACK的重復(fù)報(bào)文的序號空間曼验。如果第一個(gè)段的范圍被ACK范圍所覆蓋,那么就是DSACK粘姜△拚眨或者,第一個(gè)段的范圍被SACK的第二個(gè)段覆蓋孤紧,那么就是DSACK豺裆。
引入DSACK的好處有:
1)可以讓發(fā)送方知道,是發(fā)出去的包丟了号显,還是回來的ACK包丟了臭猜;
2)是不是自己的 timeout 設(shè)置太小了,導(dǎo)致重傳押蚤;
3)網(wǎng)絡(luò)上出現(xiàn)了先發(fā)的包后到的情況(又稱數(shù)據(jù)包失序)蔑歌;
4)網(wǎng)絡(luò)上是不是把我的數(shù)據(jù)包給復(fù)制了;
總之揽碘,DSACK的目的是幫助發(fā)送方判斷次屠,是否發(fā)生了包失序、ACK丟失雳刺、包重復(fù)或偽重傳劫灶,讓TCP可以更好的做網(wǎng)絡(luò)流量控制。
3掖桦、總結(jié)
超時(shí)重傳機(jī)制能解決數(shù)據(jù)包丟失的問題本昏,但是超時(shí)重傳機(jī)制存在等待時(shí)間太長,浪費(fèi)時(shí)間在等待上枪汪,降低了傳輸效率和無法知道需要重傳哪些數(shù)據(jù)包的問題涌穆。 快速重傳能解決超時(shí)重傳的等待時(shí)間太長的問題,但是對于究竟該重傳哪些包的問題仍然不能有效解決料饥。SACK能需要重傳哪些數(shù)據(jù)包的問題蒲犬,它可以知道哪些包是被確認(rèn)接收的,客戶端能據(jù)此判斷需要重傳的包岸啡。DSACK則是作為SACK的一個(gè)輔助措施原叮,可以用來判斷網(wǎng)絡(luò)究竟是出現(xiàn)了什么情況,據(jù)此做好網(wǎng)絡(luò)流量控制。