九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
切,老掉牙的TCP知識

來源丨經(jīng)授權(quán)轉(zhuǎn)自 假裝懂編程(ID:suntalkrobot)

作者丨康師傅

hi,大家好,我是康師傅,今天和大家聊聊網(wǎng)絡(luò)協(xié)議那些常見的知識點,為什么要聊這個知識呢?主要是因為自己快忘完了,同時這不今年快要結(jié)束了,可能很多同學(xué)都在開始準(zhǔn)備明年的面試了,那么我想不管你是前端、后端還是客戶端,網(wǎng)絡(luò)協(xié)議這塊的復(fù)習(xí)應(yīng)該是少不了的。

網(wǎng)絡(luò)協(xié)議離不開我們常說的http、tcp這些,在網(wǎng)絡(luò)分層模型中 http 屬于應(yīng)用層協(xié)議,tcp屬于傳輸層協(xié)議,其實應(yīng)用層協(xié)議還有像smtp、ftp等協(xié)議,傳輸層還有udp協(xié)議,當(dāng)然我們今天重點說下http和tcp相關(guān)的知識,http離不開tcp,因此我們先說說tcp、ip相關(guān)的知識。

TCP、IP

某一天,你和你的同事正在用微信聊天,不知道你是否思考過,你們的電腦上裝了很多軟件,比如有網(wǎng)易云、QQ...等等,為什么你通過微信發(fā)的消息會正確的發(fā)送到對方的微信上,而不是發(fā)送到其他應(yīng)用軟件上?同時再說夸大一點,為什么你發(fā)送的消息會發(fā)送你同事的電腦上,而不是隔壁老王的電腦上,這么問題看起來有點傻,其實這些離不開我們今天要說的TCP、IP協(xié)議。首先IP大家肯定都能明白,每個電腦都有一個IP,這也是為什么我們的信息可以精準(zhǔn)的發(fā)給我們的同事而不是隔壁老王,因為我們知道同事電腦的IP,這就是IP層干的的事。

當(dāng)通過IP找到了你同事的電腦后,還要找到你同事正在運行的微信軟件,電腦上軟件這么多,而且大家的IP都是一樣的,這可怎么辦?答案是端口,這也就是TCP層干的事,在數(shù)據(jù)經(jīng)過TCP層的時候,會加上目標(biāo)端口也就是我們微信進程占用的端口,然后數(shù)據(jù)包到達你同事的電腦上時,在TCP層會拆包,拆包后會發(fā)現(xiàn)目標(biāo)端口號,然后把數(shù)據(jù)丟給我們的微信進程(電腦視角:端口號是10086,哦,這個數(shù)據(jù)丟給微信進程處理吧)。

其實TCP層不僅僅會加上目標(biāo)的端口號,還會加上發(fā)送者的端口號,IP層不僅僅會加上目標(biāo)IP,還會加上發(fā)送者的IP,發(fā)現(xiàn)沒,這就是我們常說的socket四元組:發(fā)送端IP+發(fā)送端端口+接收端IP+接收端端口。一個socket四元組就可以確定一個連接。

我們常說TCP協(xié)議是一種基于字節(jié)流面向連接的、可靠的傳輸層通信協(xié)議,這里我們需要思考定義中的三個抽象描述:

  1. 基于字節(jié)流是什么意思?
  2. 什么叫做面向連接的?
  3. 如何算可靠?

基于字節(jié)流的

我們先說第一個問題,TCP 協(xié)議是基于字節(jié)流傳輸?shù)模@是什么意思呢?舉個例子,其實當(dāng)我們往 socket 中寫入1000個字節(jié)的時候,會分很多情況的,這時1000個字節(jié)會被 copy 到內(nèi)核緩沖區(qū)的,但是1000個字節(jié)具體是怎么通過網(wǎng)卡發(fā)出去是不確定的,有可能一次性發(fā)出去,也可能分成2次,分別是300、700,也有可能是500、500,但是不管怎么分,每個字節(jié)都有自己的序號。

造成這么多情況的原因是因為受到路徑最大傳輸單元 MTU、發(fā)送窗口大小、擁塞窗口大小等因素的影響(這些概念后面會講,just follow me),在這里我們也說下可靠性,因為數(shù)據(jù)包已經(jīng)在 TCP 層分段了,等于一塊數(shù)據(jù)被打散了,這些打散的數(shù)據(jù)包被接收的順序可能不一樣,但是內(nèi)核在收到亂序的數(shù)據(jù)包后,并不會直接丟給上層應(yīng)用(http等),需要按照數(shù)據(jù)包的順序組裝好,這個組裝依賴的就是序列號,那基于字節(jié)流方式傳輸?shù)臄?shù)據(jù)包,如何確定這個數(shù)據(jù)包的序列號呢?其實這個序列號就是這個包的第一個字節(jié)的序號。

三次握手

再說第二個問題:面向連接。對沒錯,我們還是要說說老掉牙的問題:三次握手、四次揮手。三次握手、四次揮手其實也是一種可靠性的表現(xiàn)。因為需要可靠,所以在建立連接的時候需要先確認雙方是否都o(jì)k,也就是三次握手。我們先看看三次握手干了什么?同時我們看看為什么三次就行了,兩次或者十次行不行?

看到上圖中的一堆玩意比如syn、seq、ack、isn等等,先不要害怕,我們一一解釋下,然后你就會明白了,上面我們也說到了,因為需要可靠,不能一上來就直接發(fā)送數(shù)據(jù),萬一對方不在線,那數(shù)據(jù)豈不是丟失了,因此握手的目的就是先確認兩邊的狀態(tài)都o(jì)k,那如何區(qū)分這次通信是握手而不是正常的發(fā)送數(shù)據(jù)呢?這就是SYN包的作用,SYN相當(dāng)于一個雙方通信中附帶的一個標(biāo)志,當(dāng)數(shù)據(jù)包中有它的時候,說明這次通信的目的是握手。

三次握手發(fā)SYN包之后,還有一個重要的事情:交換彼此的初始序列號seq,這是因為基于字節(jié)流的TCP其實每個字節(jié)的數(shù)據(jù)都有序號,在握手確認彼此的初始序列號之后,接下來所有的字節(jié)數(shù)據(jù)都是基于初始序列號向后累加的,初始序列號的生成方法就是ISN函數(shù),它大概會隨機生成一個數(shù)字,需要注意的是它的值并不是從0開始的。當(dāng)一端發(fā)送了自己的初始序列號之后,并且收到了對端的ack就說明此次交互通暢,其中ack的值就是自己發(fā)過去的序列號加1。

ok,搞懂了幾個名詞的概念和意義之后我們再來看看三次握手的過程。

  1. 首先發(fā)送端c和接收端s一開始誰也沒聯(lián)系誰,大家沒啥交集,不存在交易,大門緊閉,也就是假想的close狀態(tài)。
  2. 第一次:發(fā)送端c發(fā)送SYN包過去,同時帶上初始序列號ISN(c),然后發(fā)送端c處于SYN-SENT狀態(tài),這時說明發(fā)送端c具有發(fā)包的能力。
  3. 第二次:接收端s收到發(fā)送端c發(fā)過來的SYN包之后,就知道了此次要進行的是握手認證,于是它也發(fā)送一個SYN包并且?guī)献约旱某跏夹蛄刑朓SN(s),同時回復(fù)發(fā)送端c一個ack,ack的值就是ISN(c)+1,其實這個ISN(c)+1的意思就是說“發(fā)送端老弟,你的初始序號我收到了,下次通信的話,數(shù)據(jù)包直接從ISN(c)+1開始”,此時接收端處于「SYN-RCVD」狀態(tài),并且第二次握手也說明了接收端具有收包和發(fā)包的能力。
  4. 第三次:發(fā)送端c收到ack之后,得回一下接收端s,這樣接收端s才知道發(fā)送端c也具有收包的能力,這時發(fā)送端會回一個ack=ISN(s)+1,這個的意思和上面的差不多:“接收端老哥,你的初始序列號我也收到了,下次通信的話,你的數(shù)據(jù)包序號就從ISN(s)+1開始吧”,至此三次握手完畢,雙方的狀態(tài)都是ESTABLISHED。

我們總結(jié)下,由于TCP是可靠的傳輸層通信協(xié)議,握手的目的主要是確認雙方都有收發(fā)包的能力,從上文的描述來看三次剛剛好,如果少了,首先某一端的收發(fā)包能力就無法得到確認,比如最后一次如果發(fā)動端不發(fā)送最后的ack,那么接收端就不知道它是不是收到了數(shù)據(jù)包。當(dāng)然超過3次肯定也是沒問題的,但是沒必要,因為3次已經(jīng)可以知道雙方的狀況了。

不知道你發(fā)現(xiàn)沒有,建立連接的過程雙方都消耗了一個序列號,這里可不可以不消耗一個序列號呢?答案不可以,必須要消耗一個,關(guān)于這一點你先記住:不占用序列號的段是不需要確認的,比如ack,凡是消耗序列號的 TCP 報文段,一定需要對端確認。如果這個段沒有收到確認,會一直重傳直到達到指定的次數(shù)為止,像SYN 包就是需要確認的報文段。

四次揮手

看完了三次握手,我們再來看看四次揮手的過程,四次揮手的過程雙方會處于某種狀態(tài),這是需要注意的,這也是面試考察點。依然一樣我們來看看為什么需要四次揮手,以及每次揮手的過程干了什么?

為了方便描述,這里定義下主動斷開方叫「A」,被動斷開方叫做「B」

  1. 第一次:A突然想要關(guān)閉連接,不想玩了,于是它會發(fā)送一個FIN包,這個FIN包和上面的SYN包是對立的,說明此刻A想要斷開連接,同時FIN包也是需要對端確認的,所以FIN包是需要消耗一個序列號的,發(fā)送完FIN包后,A處于FIN_WAIT1狀態(tài)。
  2. 第二次:B收到對端的FIN包之后,心想:“這小子是不想玩耍了呀,不想玩就算了”,于是B會對FIN包做出個回應(yīng)也就是ack,意思是:“對面的,我知道了”,同時自己處于CLOSE_WAIT狀態(tài),A收到對端的ack之后同時自己處于FIN_WAIT2狀態(tài)。
  3. 第三次:B在發(fā)送ack之后,如果還有未處理完的數(shù)據(jù),需要接著把未發(fā)送完的數(shù)據(jù)發(fā)給對端,當(dāng)數(shù)據(jù)發(fā)完之后,其實也就是和A沒啥關(guān)系了,于是B也會發(fā)個FIN包,意思是“對面的,數(shù)據(jù)都發(fā)完了,你就斷開吧”,此時B會處于LAST_ACK狀態(tài)。
  4. 第四次:還是一樣的,F(xiàn)IN包需要確認,因此A再收到FIN包后,會立馬回復(fù)一個ACK,那此時對端就會斷開連接處于CLOSED狀態(tài),同時A處于TIME_WAIT狀態(tài),也就是2MSL之后自動斷開。

能不能三次揮手?

看流程四次揮手絕對沒問題,那問題來了,三次行不行?其實某些情況下三次也是可以的,比如被動斷開方?jīng)]有要處理的數(shù)據(jù)也就不存在DATA那一部分,那其實ACK和FIN一起發(fā)過去問題也是沒問題的,如果存在DATA,非要把ACK+DATA+FIN合并在一起發(fā)過去會發(fā)生什么呢?首先處理DATA需要時間,那么為了等DATA處理完再發(fā)ACK,可能會導(dǎo)致主動斷開方因為遲遲沒收到ack,而重發(fā)FIN包。

為啥最后一步主動斷開方需要處于TIME_WAIT狀態(tài),這個狀態(tài)代表什么?

TIME_WAIT是主動關(guān)閉方最后進入的一種狀態(tài),TIME_WAIT是2MSL的,MSL是報文最大的生命周期,正常來說一個數(shù)據(jù)包如果在網(wǎng)絡(luò)中超過MSL之后還沒被對端收到就會被丟棄,那為什么主動斷開方需要2MSL呢?

  1. 一個MSL主要是保證最后一次 ACK 能到達對端,如果 1MSL 后,ACK 還沒到達對端會怎么辦?
  2. 如果主動斷開方的 ACK 沒到達對端,這時候會觸發(fā)被斷開方重傳 FIN,那么另一個 MSL 就是保證重傳的 FIN 包也能到達對端。

因此2MSL = 去向 ACK 消息最大存活時間(MSL) + 來向 FIN 消息的最大存活時間(MSL)。

為什么FIN包也需要消耗一個序列號?

上圖并沒有說到序列號的事,其實 FIN 包和 SYN 包一樣的,也是需要消耗序列號的,如果要問為什么?只是回答“因為 FIN 包需要對端確認,而需要確認的報文段都是消耗序列號的”難免有些牽強,我們來看個圖你就知道了。

  1. 假設(shè)現(xiàn)在發(fā)送端的序列號是100,而且發(fā)送了100字節(jié)的數(shù)據(jù),按道理接下來的ack應(yīng)該是200(199+1)。
  1. 此時突然要發(fā)送 FIN 包,因為之前已經(jīng)發(fā)送了100個字節(jié),因此這時的 FIN 包對應(yīng)的 seq 應(yīng)該是 200
  2. 如果 FIN 包不消耗一個序列號,那么對應(yīng)的 ACK 應(yīng)該也是200,而不是201,額,這就尷尬了,最后這個 ACK 到底是對 FIN 包的 ACK 還是對 100 字節(jié)數(shù)據(jù)的 ACK?這就傻傻分不清楚了。

因此無論是 SYN 包還是 FIN 包,為了和正常的數(shù)據(jù)區(qū)分,都需要消耗一個序列號。

可靠

我是大哥我來分段-MTU和MSS
通過上文我們知道在 TCP 中數(shù)據(jù)的傳輸是基于字節(jié)流的,數(shù)據(jù)塊會被拆分成一個個報文段然后發(fā)出去,決定報文段大小的因素很多,比如路徑MTU、發(fā)送窗口大小、接收窗口大小等因素的影響,這里我們一起來看看這些因素是什么?首先我們來看看這個路徑MTU,在網(wǎng)絡(luò)分層中,我們知道最終數(shù)據(jù)是要通過鏈路層發(fā)出去的,這個鏈路層的通道其實是有限制的,這個限制我們就叫做MTU,那這個MTU是多少呢?一般是1500,你可以通過netstat -i查看你本機網(wǎng)卡的MTU。

netstat -i
en0   1500  <Link#6>    08:f8:bc:6f:6a:03 34427890     0 37802460 26255     0

注意這只是本機的MTU,真實的網(wǎng)絡(luò)中,你的數(shù)據(jù)從電腦網(wǎng)卡出去之后,可能要經(jīng)過一系列的路由器、交換機等物理硬件,其中每個物理硬件都有自己的MTU,那在這漫長的網(wǎng)絡(luò)路徑中,起關(guān)鍵作用的MTU是哪個?答案是最小的那個,最小的那個就叫做路徑MTU,這就像木桶效應(yīng),桶的容量是由最短的那一塊板決定的,當(dāng)你的數(shù)據(jù)包大于MTU時,會被拆成一個一個合適的網(wǎng)絡(luò)包發(fā)出去。IP層發(fā)現(xiàn)鏈路層的數(shù)據(jù)包有大小限制,因此IP層就說:'既然鏈路層有大小限制,發(fā)再大的數(shù)據(jù)包過去也是會被拆解的,還不如我自己做,在把數(shù)據(jù)發(fā)給鏈路老弟之前,我直接按照它的要求把數(shù)據(jù)分好段,就不麻煩它了。' IP層干了數(shù)據(jù)分段的事情之后,TCP層不高興了,'弄啥嘞,弄啥嘞,我在他們的上層,數(shù)據(jù)竟然還要 IP 層小弟分段,我顏面何存!',于是 TCP 層為了避免數(shù)據(jù)被發(fā)送方分片,會主動把數(shù)據(jù)分割成小段再交給IP 層,TCP 能分的最大段我們稱之為 MSS (Max Segment Size),這個 MSS 的值是多少呢?其實它的值是這個:

MSS = MTU - IP 頭大小 - TCP 頭大小

其中 IP 頭和 TCP 頭各占 20 個字節(jié),以 MTU=1500來說,那么 MSS = 1500-20-20=1460。就這樣 TCP 層主動的把數(shù)據(jù)分好,從而得到了 IP 層和鏈路層的一致好評。IP 層:'大哥靠譜'。鏈路層:'大哥的大哥靠譜'。

我只能吃這么多-滑動窗口
在socket通信中,我們知道發(fā)送端有發(fā)送端的緩沖區(qū),接收端有接收端的緩沖區(qū),發(fā)送端把數(shù)據(jù)寫入到socket緩沖區(qū)中,待緩沖區(qū)滿了或者過了一段時間后,緩沖區(qū)的數(shù)據(jù)會被網(wǎng)卡一段一段的發(fā)出去,當(dāng)數(shù)據(jù)到到達對端后,并不是直接等著對方處理,這樣效率會很低,而是會先把數(shù)據(jù)放入到緩沖區(qū)中,也就是我們的接收緩沖區(qū),然后應(yīng)用程序不斷的從接收緩沖區(qū)中取數(shù)據(jù)。緩沖區(qū)起到一個緩沖的作用,很合理,然后如果發(fā)送端發(fā)送的太快,或者說接收端的應(yīng)用程序處理的太慢,導(dǎo)致接收端的緩沖區(qū)很快被填滿,這時候該怎么辦?直接發(fā)肯定不行,得告訴發(fā)送端先不要發(fā)了。這就要說到了 TCP 中的「滑動窗口」的概念。我們知道 TCP 是基于字節(jié)流來發(fā)送數(shù)據(jù)的,也就說每個字節(jié)其實都是有序號的,有了序號可以干什么呢?首先通過序號可以重組數(shù)據(jù),其次ack之前的序號表示都已經(jīng)收到,滑動窗口和ack的情況有關(guān),我們來站在 TCP 的角度看看數(shù)據(jù)包的狀態(tài)。

這是站在發(fā)送端的角度來看數(shù)據(jù)包的狀態(tài)的,其中的滑動窗口部分可以看作是發(fā)送端的滑動窗口,對于已發(fā)送已確認的部分,算是過去時了,它只會使滑動窗口向右移,真正影響滑動窗口大小的是「已發(fā)送未確認」「未發(fā)送可發(fā)送」部分,剩下的「不能發(fā)送」是因為接收端沒有足夠的空間了。我們再來站在接收端角度看看滑動窗口是什么樣的。

可以發(fā)現(xiàn)窗口的大小其實是一樣的,唯一的區(qū)別是對于接收端來說要么已接收,要么未接收,不能接收的話說明沒有足夠的空間了。那發(fā)送端怎么知道當(dāng)前接收端剩余空間的大?。科鋵嵔邮斩嗽贏CK的時候會帶上自己窗口的大小,這樣發(fā)送端就知道了接收端窗口的大小。以上圖為例,當(dāng)接收端拿到了32-35的數(shù)據(jù)后,就會ACK=36告訴發(fā)送端,同時接收端的滑動窗口會向后移動4位,發(fā)送端收到ACK=36后,就知道36之前的數(shù)據(jù)接收端都收到了,因此會把發(fā)送端的窗口也向后移動4位。

滑動窗口很棒,可以在能力范圍內(nèi)處理數(shù)據(jù),但是有個問題呀:如果發(fā)送端能力極強,發(fā)的很快,接收端能力極弱,處理的很慢,這會導(dǎo)致什么問題?某一刻滑動窗口為0了,這時候接收端就會告訴發(fā)送端:'你奶奶的,消停會吧,沒空間了'。發(fā)送端收到了通知之后:'原來是個弱雞,休息會吧,等它下次ack通知我吧',正常來說,接收端在處理完數(shù)據(jù)之后可以告訴發(fā)送端可以繼續(xù)發(fā)數(shù)據(jù)了,然而意外出現(xiàn)了,由于接收端所在的主機的主人正在聽網(wǎng)易云音樂、玩著2k,同時還尼瑪欣賞著b站舞蹈區(qū)up主娥羅多姿的舞蹈,導(dǎo)致網(wǎng)卡壓力很大,最后一個ack丟失了,這樣發(fā)送端就不知道接收端其實已經(jīng)處理了一部分?jǐn)?shù)據(jù),這可怎么辦,如果一直丟失,豈不是要一直傻等,得主動出擊呀,于是搞了個「零窗口探測定時器」,這個定時器的功能相信大家也知道了,就是當(dāng)接收方的接收窗口為0時,每隔一段時間,發(fā)送方會主動發(fā)送探測包,通過迫使對端響應(yīng)來得知其接收窗口的狀態(tài),不得不說零窗口探測夠穩(wěn)。

悠著點慢慢來-擁塞控制
上面我們說到滑動窗口可以合理的控制接收端能處理數(shù)據(jù)的量,注意這里說的只是量,如果網(wǎng)絡(luò)狀況很差,發(fā)送端一次性發(fā)了很多數(shù)據(jù),并且窗口未被填滿(此處的意思就是和窗口的大小沒關(guān)系),這時會發(fā)生什么?我想大概率是發(fā)送端瘋狂的重傳(因為網(wǎng)絡(luò)差,未收到ack),那么我們反過來想一想網(wǎng)絡(luò)狀態(tài)差,我們還有必要發(fā)送大量的數(shù)據(jù)過去嗎,大量的重試不是給發(fā)送端自己找麻煩,因此需要悠著點,這里的悠著點說的就是「擁塞窗口(cwnd)」,擁塞窗口指的是在收到對端 ACK 之前自己還能傳輸?shù)淖畲?MSS 段數(shù),那它和之前說的發(fā)送窗口有什么關(guān)系?其實真正的發(fā)送窗口大小是擁塞窗口和接收端那個窗口之間的最小值。MSS 我們知道在 MTU=1500 的情況下它的值是1460,擁塞窗口指的就是能發(fā)多少個1460,由于在連接建立之初,發(fā)送端并不知道網(wǎng)絡(luò)狀況,如果網(wǎng)絡(luò)狀態(tài)很差,一口氣傳過去很多數(shù)據(jù)是不明智的,緩慢啟動才是正確的選擇,緩慢啟動可以及時止損,同時緩慢啟動也不并是說一直緩慢,如果網(wǎng)絡(luò)ok,會隨著時間慢慢增長,這就是緩慢啟動的目的,那怎么個增長法呢?在通信之初,只要發(fā)送端收到一個 ACK 就會把 cwnd 翻倍,比如一開始是10,收到一個 ACK 后,下次就是20,再收到一個 ACK 后,就是40...,這個做法很聰明,我們只需忍受剛啟動的時的慢速,隨著時間的增長 cwnd 會以指數(shù)級的增長快速趕上來。喝茶聊天,萬事大吉。不對,這指數(shù)級的增長若不控制,一會便要超過了馬斯克的財富了,這可不得了,于是搞了個慢啟動閾值(ssthresh),當(dāng) cwnd 達到 ssthresh 時,這時說明 cwnd 不小了,在翻倍的漲下去可能會危險,這時可以選擇小漲,不翻倍,每次在cwnd的基礎(chǔ)上再加個1 MSS 就行了。

  • 當(dāng) cwnd <= ssthresh 時,擁塞窗口按指數(shù)級增長(慢啟動)
  • 當(dāng) cwnd > ssthresh 時,擁塞窗口按線性增長(擁塞避免)

即使是加1個 MSS,隨著時間的推移也可能無限大,但是為什么現(xiàn)實中沒出現(xiàn)問題?我想其中之一就是上面的說到的真正的發(fā)送窗口的大小是兩者中的最小的那個,畢竟接收窗口不可能無限大。其二就是隨著網(wǎng)絡(luò)包的越來越大,會發(fā)生網(wǎng)絡(luò)擁堵,這時候 ssthresh 會降級, 也就是 ssthresh = cwnd / 2,然后 cwnd 會被設(shè)置為1個報文段,重頭重新開始緩慢啟動和擁塞避免,關(guān)于第二點,我借鑒網(wǎng)上一個例子:'假設(shè) TCP 的 ssthresh 的初始值為 8。當(dāng)擁塞窗口上升到 12 時網(wǎng)絡(luò)發(fā)生了超時,于是TCP 開始使用慢開始和擁塞避免。試分別求出第 1 次到第 15 次傳輸?shù)母鲹砣翱诖笮 ?

一開始cwnd是1,然后不停的翻倍,直至到達 ssthresh,也就是8,這時開始每次加1個 MSS,當(dāng)?shù)?2的時候,發(fā)生超時,也就是 ssthresh 會變成6,然后 cwnd 重新從1開始,也是不停的翻倍,當(dāng)?shù)?,準(zhǔn)備翻倍到8的時候,發(fā)現(xiàn)sthresh=6,因此會變成6,然后開始每次加一個 MSS。因此第1次和第15次分別是1和9。

牛逼的算法讓我不由的手舞足蹈,ちょっと待って(等一下),怎么判斷網(wǎng)絡(luò)擁堵超時了?這個其實很好判斷,當(dāng)超過一定時間之后,發(fā)送端沒收到ack,可能就是網(wǎng)絡(luò)超時了,正常來說,這時候,發(fā)送端會使用退避策略來重新發(fā)送,每次重傳的間隔大概是幾百毫秒,這幾百毫秒毫秒對人類來說還挺快的,但是對計算機來說其實挺慢的,那有沒有什么更快的方法?我們先來看個例子:假設(shè)現(xiàn)在要發(fā)送4個數(shù)據(jù)包分別是[1,100],[101,200],[201,300],[301,400],正常來說發(fā)完第一個數(shù)據(jù)包之后,會回復(fù)ACK=101,沒毛病,但是在發(fā)第二個數(shù)據(jù)包的時候,網(wǎng)絡(luò)超時了,丟包了,當(dāng)發(fā)送端繼續(xù)發(fā)送第三個、第四包的時候,并不會回復(fù) ACK=301,401,而是會繼續(xù)回復(fù) ACK=101,這里請再記住 ACK 代表這個序列號之前的數(shù)據(jù)都已收到。正如上文說到的,正常來說,此時要等幾百毫秒才會意識到丟包,重發(fā),而如果想要更快點,比如收到三次重復(fù)的ACK說明就是丟包了,這樣是不是快很多,這就是「快速重傳(SACK)」,但是只是單純的告訴101之前的數(shù)據(jù)收到了(第一個數(shù)據(jù)包)有點低效,萬一第三個也丟了怎么辦,因此SACK做了進一步的優(yōu)化:在通知ACK的同時也告訴比如第三個包也丟了、第四個數(shù)據(jù)包我收到了,這樣發(fā)送端就知道了此刻除了第二個數(shù)據(jù)包丟失了,第三個包也丟失了,重傳第二個、第三個即可。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
TCP會話過程詳解
深入理解 TCP 協(xié)議:從原理到實戰(zhàn)【超詳細】-上
從TCP協(xié)議的原理來談?wù)剅st復(fù)位攻擊
一文秒懂 TCP/IP實際五層結(jié)構(gòu)(下篇)
TCP三次握手、四次揮手過程及原理
TCP三次握手過程
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服