版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
程序員TCP基礎(chǔ)知識(shí)
這是一篇詳細(xì)介紹TCP各種特點(diǎn)的文章,內(nèi)容主要包括TCP三次握手和
四次揮手細(xì)節(jié)問(wèn)題、TCP狀態(tài)之間的轉(zhuǎn)換、TCP超時(shí)和重傳、關(guān)于TCP包
失序和重復(fù)問(wèn)題、TCP的數(shù)據(jù)流與窗口管理、TCP的擁塞控制,思維導(dǎo)圖
如下。
TCP狀態(tài)轉(zhuǎn)換TIME_WAIT狀態(tài)
包失序
TCP是一種面向連接的單播協(xié)議,在TCP中,并不存在多播、廣播的這
種行為,因?yàn)門CP報(bào)文段中能明確發(fā)送方和接受方的IP地址。
在發(fā)送數(shù)據(jù)前,相互通信的雙方(即發(fā)送方和接受方)需要建立一條連接,
在發(fā)送數(shù)據(jù)后,通信雙方需要斷開(kāi)連接,這就是TCP連接的建立和終止。
TCP連接的建立和終止
如果你看過(guò)我之前寫的關(guān)于網(wǎng)絡(luò)層的一篇文章,你應(yīng)該知道TCP的基本元
素有四個(gè):即發(fā)送方的IP地址、發(fā)送方的端口號(hào)、接收方的IP地址、
接收方的端口號(hào)。而每一方的IP+端口號(hào)都可以看作是一個(gè)套接字,套接
字能夠被唯一標(biāo)示。套接字就相當(dāng)于是門,出了這個(gè)門,就要進(jìn)行數(shù)據(jù)傳
輸了。
TCP的連接建立->終止總共分為三個(gè)階段
下面我們所討論的重點(diǎn)也是集中在這三個(gè)層面。
下圖是一個(gè)非常典型的TCP連接的建立和關(guān)閉過(guò)程,其中不包括數(shù)據(jù)傳輸
的部分。
hrcp建立連接-三次握手
客戶端主機(jī)服務(wù)器主機(jī)
i.
服務(wù)端進(jìn)程準(zhǔn)備好接收來(lái)自外部的TCP連接,一般情況下是調(diào)用bind、
listen、socket三個(gè)函數(shù)完成。這種打開(kāi)方式被認(rèn)為是被動(dòng)打開(kāi)(passive
open)o然后服務(wù)端進(jìn)程處于LISTEN狀態(tài),等待客戶端連接請(qǐng)求。
客戶端通過(guò)connect發(fā)起主動(dòng)打開(kāi)(activeopen),向服務(wù)器發(fā)出連接請(qǐng)求,
請(qǐng)求中首部同步位SYN=1,同時(shí)選擇一個(gè)初始序號(hào)sequence,簡(jiǎn)寫seq
=xoSYN報(bào)文段不允許攜帶數(shù)據(jù),只消耗一個(gè)序號(hào)。此時(shí),客戶端進(jìn)
入SYN-SEND狀態(tài)。
3.
服務(wù)器收到客戶端連接后,,需要確認(rèn)客戶端的報(bào)文段。在確認(rèn)報(bào)文段中,
把SYN和ACK位都置為1。確認(rèn)號(hào)是ack=x+1,同時(shí)也為自己選擇
一個(gè)初始序號(hào)seq=y。這個(gè)報(bào)文段也不能攜帶數(shù)據(jù),但同樣要消耗掉一個(gè)
序號(hào)。此時(shí),TCP服務(wù)器進(jìn)入SYN-RECEIVED(同步收到)狀態(tài)。
客戶端在收到服務(wù)器發(fā)出的響應(yīng)后,還需要給出確認(rèn)連接。確認(rèn)連接中的
ACK置為1,序號(hào)為seq=x+1,確認(rèn)號(hào)為ack=y+1。TCP規(guī)定,
這個(gè)報(bào)文段可以攜帶數(shù)據(jù)也可以不攜帶數(shù)據(jù),如果不攜帶數(shù)據(jù),那么下一
個(gè)數(shù)據(jù)報(bào)文段的序號(hào)仍是seq=x+1o這時(shí),客戶端進(jìn)入ESTABLISHED
(已連接)狀態(tài)
服務(wù)器收到客戶的確認(rèn)后,也進(jìn)入ESTABLISHED狀態(tài)。
這是一個(gè)典型的三次握手過(guò)程,通過(guò)上面3個(gè)報(bào)文段就能夠完成一個(gè)
TCP連接的建立。三次握手的的目的不僅僅在于讓通信雙方知曉正在建立
一個(gè)連接,也在于利用數(shù)據(jù)包中的選項(xiàng)字段來(lái)交換一些特殊信息,交換初
始序列號(hào)。
一般首個(gè)發(fā)送SYN報(bào)文的一方被認(rèn)為是主動(dòng)打開(kāi)一個(gè)連接,而這一方通常也被稱為客戶
端。而SYN的接收方通常被稱為服務(wù)端,它用于接收這個(gè)SYN,并發(fā)送下面的SYN,
因此這種打開(kāi)方式是被動(dòng)打開(kāi)。
TCP建立一個(gè)連接需要三個(gè)報(bào)文段,釋放一個(gè)連接卻需要四個(gè)報(bào)文段。
rep斷開(kāi)連接-四次揮手
數(shù)據(jù)傳輸結(jié)束后,通信的雙方可以釋放連接。數(shù)據(jù)傳輸結(jié)束后的客戶端主
機(jī)和服務(wù)端主機(jī)都處于ESTABLISHED狀態(tài),然后進(jìn)入釋放連接的過(guò)程。
客戶端主機(jī)服務(wù)器主機(jī)
主動(dòng)關(guān)閉被動(dòng)關(guān)閉
數(shù)據(jù)傳輸
等待
2MSL
CLOSED
TCP斷開(kāi)連接需要?dú)v經(jīng)的過(guò)程如下
客戶端應(yīng)用程序發(fā)出釋放連接的報(bào)文段,并停止發(fā)送數(shù)據(jù),主動(dòng)關(guān)閉TCP
連接。客戶端主機(jī)發(fā)送釋放連接的報(bào)文段,報(bào)文段中首部FIN位置為1,
不包含數(shù)據(jù),序列號(hào)位seq=u,此時(shí)客戶端主機(jī)進(jìn)入FIN-WAIT-1(終止等
待1)階段。
服務(wù)器主機(jī)接受到客戶端發(fā)出的報(bào)文段后,即發(fā)出確認(rèn)應(yīng)答報(bào)文,確認(rèn)應(yīng)
答報(bào)文中ACK=1,生成自己的序號(hào)位seq=v,ack=u+1,然后服務(wù)器
主機(jī)就進(jìn)入CLOSE-WAIT(關(guān)閉等待)狀態(tài)。
3.
客戶端主機(jī)收到服務(wù)端主機(jī)的確認(rèn)應(yīng)答后,即進(jìn)入FIN-WAIT-2(終止等待
2)的狀態(tài)。等待客戶端發(fā)出連接釋放的報(bào)文段。
這時(shí)服務(wù)端主機(jī)會(huì)發(fā)出斷開(kāi)連接的報(bào)文段,報(bào)文段中ACK=1,序歹U號(hào)seq
=v,ack=u+1,在發(fā)送完斷開(kāi)請(qǐng)求的報(bào)文后,服務(wù)端主機(jī)就進(jìn)入
TLAST-ACK(最后確認(rèn))的階段。
客戶端收到服務(wù)端的斷開(kāi)連接請(qǐng)求后,客戶端需要作出響應(yīng),客戶端發(fā)出
斷開(kāi)連接的報(bào)文段,在報(bào)文段中,ACK=1,序列號(hào)seq=u+1,因?yàn)榭?/p>
戶端從連接開(kāi)始斷開(kāi)后就沒(méi)有再發(fā)送數(shù)據(jù),ack=v+1,然后進(jìn)入
到TIME-WAIT(時(shí)間等待)狀態(tài),請(qǐng)注意,這個(gè)時(shí)候TCP連接還沒(méi)有釋放。
必須經(jīng)過(guò)時(shí)間等待的設(shè)置,也就是2MSL后,客戶端才會(huì)進(jìn)入CLOSED狀
態(tài),時(shí)間MSL叫做最長(zhǎng)報(bào)文段壽命(MaximumSegmentLifetime)。
服務(wù)端主要收到了客戶端的斷開(kāi)連接確認(rèn)后,就會(huì)進(jìn)入CLOSED狀態(tài)。
因?yàn)榉?wù)端結(jié)束TCP連接時(shí)間要比客戶端早,而整個(gè)連接斷開(kāi)過(guò)程需要發(fā)
送四個(gè)報(bào)文段,因此釋放連接的過(guò)程也被稱為四次揮手。
TCP連接的任意一方都可以發(fā)起關(guān)閉操作,只不過(guò)通常情況下發(fā)起關(guān)閉連
接操作一般都是客戶端。然而,一些服務(wù)器比如Web服務(wù)器在對(duì)請(qǐng)求作
出相應(yīng)后也會(huì)發(fā)起關(guān)閉連接的操作。TCP協(xié)議規(guī)定通過(guò)發(fā)送一個(gè)FIN報(bào)
文來(lái)發(fā)起關(guān)閉操作。
所以綜上所述,建立一個(gè)TCP連接需要三個(gè)報(bào)文段,而關(guān)閉一個(gè)TCP連
接需要四個(gè)報(bào)文段。TCP協(xié)議還支持一種半開(kāi)啟(half-open)狀態(tài),雖然這
種情況并不多見(jiàn)。
CP半開(kāi)啟
TCP連接處于半開(kāi)啟的這種狀態(tài)是因?yàn)檫B接的一方關(guān)閉或者終止了這個(gè)
TCP連接卻沒(méi)有通知另一方,也就是說(shuō)兩個(gè)人正在微信聊天,cxuan你下
線了你不告訴我,我還在跟你侃八卦呢。此時(shí)就認(rèn)為這條連接處于半開(kāi)啟
狀態(tài)。這種情況發(fā)生在通信中的一方處于主機(jī)崩潰的情況下,你XXX的,
我電腦死機(jī)了我咋告訴你?只要處于半連接狀態(tài)的一方不傳輸數(shù)據(jù)的話,
那么是無(wú)法檢測(cè)出來(lái)對(duì)方主機(jī)已經(jīng)下線的。
另外一種處于半開(kāi)啟狀態(tài)的原因是通信的一方關(guān)閉了主機(jī)電源而不是正常
關(guān)機(jī)。這種情況下會(huì)導(dǎo)致服務(wù)器上有很多半開(kāi)啟的TCP連接。
rep半關(guān)閉
既然TCP支持半開(kāi)啟操作,那么我們可以設(shè)想TCP也支持半關(guān)閉操作。
同樣的,TCP半關(guān)閉也并不常見(jiàn)。TCP的半關(guān)閉操作是指僅僅關(guān)閉數(shù)據(jù)流
的一個(gè)傳輸方向。兩個(gè)半關(guān)閉操作合在一起就能夠關(guān)閉整個(gè)連接。在一般
情況下,通信雙方會(huì)通過(guò)應(yīng)用程序互相發(fā)送FIN報(bào)文段來(lái)結(jié)束連接,但是
在TCP半關(guān)閉的情況下,應(yīng)用程序會(huì)表明自己的想注:"我己經(jīng)完成了數(shù)
據(jù)的發(fā)送發(fā)送,并發(fā)送了一個(gè)FIN報(bào)文段給對(duì)方,但是我依然希望接收來(lái)
自對(duì)方的數(shù)據(jù)直到它發(fā)送一個(gè)FIN報(bào)文段給我"。下面是一個(gè)TCP半關(guān)閉
的示意圖。
客戶端主機(jī)服務(wù)器主機(jī)
解釋一下這個(gè)過(guò)程:
首先客戶端主機(jī)和服務(wù)器主機(jī)一直在進(jìn)行數(shù)據(jù)傳輸,一段時(shí)間后,客戶端
發(fā)起了FIN報(bào)文,要求主動(dòng)斷開(kāi)連接,服務(wù)器收到FIN后,回應(yīng)ACK,
由于此時(shí)發(fā)起半關(guān)閉的一方也就是客戶端仍然希望服務(wù)器發(fā)送數(shù)據(jù),所以
服務(wù)器會(huì)繼續(xù)發(fā)送數(shù)據(jù),一段時(shí)間后服務(wù)器發(fā)送另外一條FIN報(bào)文,在客
戶端收到FIN報(bào)文回應(yīng)ACK給服務(wù)器后,斷開(kāi)連接。
TCP的半關(guān)閉操作中,連接的一個(gè)方向被關(guān)閉,而另一個(gè)方向仍在傳輸數(shù)據(jù)直到它被關(guān)閉
為止。只不過(guò)很少有應(yīng)用程序使用這一特性。
同時(shí)打開(kāi)和同時(shí)關(guān)閉
還有一種比較非常規(guī)的操作,這就是兩個(gè)應(yīng)用程序同時(shí)主動(dòng)打開(kāi)連接。雖
然這種情況看起來(lái)不太可能,但是在特定的安排下卻是有可能發(fā)生的。我
們主要講述這個(gè)過(guò)程。
通信雙方在接收到來(lái)自對(duì)方的SYN之前會(huì)首先發(fā)送一個(gè)SYN,這個(gè)場(chǎng)景
還要求通信雙方都知道對(duì)方的IP地址+端口號(hào)。
下面是同時(shí)打開(kāi)的例子
通信一方通信另一方
數(shù)據(jù)傳輸
如上圖所示,通信雙方都在收到對(duì)方報(bào)文前主動(dòng)發(fā)送了SYN報(bào)文,都在
收到彼此的報(bào)文后回復(fù)了一個(gè)ACK報(bào)文。
一個(gè)同時(shí)打開(kāi)過(guò)程需要交換四個(gè)報(bào)文段,比普通的三次握手增加了一個(gè),
由于同時(shí)打開(kāi)沒(méi)有客戶端和服務(wù)器一說(shuō),所以這里我用了通信雙方來(lái)稱呼。
像同時(shí)打開(kāi)一樣,同時(shí)關(guān)閉也是通信雙方同時(shí)提出主動(dòng)關(guān)閉請(qǐng)求,發(fā)送FIN
報(bào)文,下圖顯示了一個(gè)同時(shí)關(guān)閉的過(guò)程。
通信一方通信另一方
主動(dòng)關(guān)閉主動(dòng)關(guān)閉
同時(shí)關(guān)閉過(guò)程中需要交換和正常關(guān)閉相同數(shù)量的報(bào)文段,只不過(guò)同時(shí)關(guān)閉
不像四次揮手那樣順序進(jìn)行,而是交叉進(jìn)行的。
聊一聊初始序列號(hào)
也許是我上面圖示或者文字描述的不專業(yè),初始序列號(hào)它是有專業(yè)術(shù)語(yǔ)表
示的,初始序歹ij號(hào)的英文名稱是Initialsequencenumbers(ISN),所以我
們上面表示的seq=v,其實(shí)就表示的ISNo
在發(fā)送SYN之前,通信雙方會(huì)選擇一個(gè)初始序列號(hào)。初始序列號(hào)是隨機(jī)
生成的,每一個(gè)TCP連接都會(huì)有一個(gè)不同的初始序列號(hào)。RFC文檔指出
初始序列號(hào)是一個(gè)32位的計(jì)數(shù)器,每4us(微秒)+1。因?yàn)槊總€(gè)TCP
連接都是一個(gè)不同的實(shí)例,這么安排的目的就是為了防止出現(xiàn)序列號(hào)重疊
的情況。
當(dāng)一個(gè)TCP連接建立的過(guò)程中,只有正確的TCP四元組和正確的序列號(hào)
才會(huì)被對(duì)方接收。這也反應(yīng)了TCP報(bào)文段容易被偽造的脆弱性,因?yàn)橹?/p>
要我偽造了一個(gè)相同的四元組和初始序列號(hào)就能夠偽造TCP連接,從而打
斷TCP的正常連接,所以抵御這種攻擊的一種方式就是使用初始序列號(hào),
另外一種方法就是加密序列號(hào)。
TCP狀態(tài)轉(zhuǎn)換
我們上面聊到了三次握手和四次揮手,提到了一些關(guān)于TCP連接之間的狀
態(tài)轉(zhuǎn)換,那么下面我就從頭開(kāi)始和你好好梳理一下這些狀態(tài)之間的轉(zhuǎn)換。
首先第一步,剛開(kāi)始時(shí)服務(wù)器和客戶端都處于CLOSED狀態(tài),這時(shí)需要
判斷是主動(dòng)打開(kāi)還是被動(dòng)打開(kāi),如果是主動(dòng)打開(kāi),那么客戶端向服務(wù)器發(fā)
送SYN報(bào)文,此時(shí)客戶端處于SYN-SEND狀態(tài),SYN-SEND表示發(fā)送連
接請(qǐng)求后等待匹配的連接請(qǐng)求,服務(wù)器被動(dòng)打開(kāi)會(huì)處于USTEN狀態(tài),用
于監(jiān)聽(tīng)SYN報(bào)文。如果客戶端調(diào)用了close方法或者經(jīng)過(guò)一段時(shí)間沒(méi)有
操作,就會(huì)重新變?yōu)镃LOSED狀態(tài),這一步轉(zhuǎn)換圖如下
'、、、開(kāi)始
這里有個(gè)疑問(wèn),為什么處于LISTEN狀態(tài)下的客戶端還會(huì)發(fā)送SYN變?yōu)镾YN_SENT
狀態(tài)呢?
知乎看到了車小胖大佬的回答,這種情況可能出現(xiàn)在FTP中,LISTEN,
SYN_SENT是因?yàn)檫@個(gè)連接可能是由于服務(wù)器端的應(yīng)用有數(shù)據(jù)發(fā)送給客
戶端而觸發(fā)的,客戶端被動(dòng)接受連接,連接建立后,開(kāi)始傳輸文件。也就
是說(shuō),處于LISTEN狀態(tài)的服務(wù)器也是有可能發(fā)送SYN報(bào)文的,只不過(guò)
這種情況非常少見(jiàn)。
處于SYN_SEND狀態(tài)的服務(wù)器會(huì)接收SYN并發(fā)送SYN和ACK轉(zhuǎn)換
成為SYN_RCVD狀態(tài),同樣的,處于LISTEN狀態(tài)的客戶端也會(huì)接收
SYN并發(fā)起SYN和ACK轉(zhuǎn)換為SYN_RCVD狀態(tài)。如果處于
SYN_RCVD狀態(tài)的客戶端收到RST就會(huì)變?yōu)長(zhǎng)ISTEN狀態(tài)。
這兩張圖一起看會(huì)比較好一些。
這里需要解釋下什么是RST
這里有一種情況是當(dāng)主機(jī)收到TCP報(bào)文段后,其IP和端口號(hào)不匹配的情
況。假設(shè)客戶端主機(jī)發(fā)送一個(gè)請(qǐng)求,而服務(wù)器主機(jī)經(jīng)過(guò)IP和端口號(hào)的判斷
后發(fā)現(xiàn)不是給這個(gè)服務(wù)器的,那么服務(wù)器就會(huì)發(fā)出一個(gè)RST特殊報(bào)文段給
客戶端。
客戶端主機(jī)服務(wù)器主機(jī)
因此,當(dāng)服務(wù)端發(fā)送一個(gè)RST特殊報(bào)文段給客戶端的時(shí)候,它就會(huì)告訴客
戶端沒(méi)有匹配的套接字連接,請(qǐng)不要再繼續(xù)發(fā)送了。
RST:(Resettheconnection)用于復(fù)位因某種原因引起出現(xiàn)的錯(cuò)誤連接,
也用來(lái)拒絕非法數(shù)據(jù)和請(qǐng)求。如果接收到RST位時(shí)候,通常發(fā)生了某些
錯(cuò)誤。
上面沒(méi)有識(shí)別正確的IP端口是一種導(dǎo)致RST出現(xiàn)的情況,除此之外,
RST還可能由于請(qǐng)求超時(shí)、取消一個(gè)已存在的連接等出現(xiàn)。
位于SYN_RCVD的服務(wù)器會(huì)接收ACK報(bào)文,SYN_SEND的客戶端會(huì)
接收SYN和ACK報(bào)文,并發(fā)送ACK報(bào)文,由此,宣戶端和服務(wù)器之間
的連接就建立了。
客戶靖主機(jī)艇務(wù)a主機(jī)
被動(dòng)打開(kāi)
這里還要注意一點(diǎn),同時(shí)打開(kāi)的狀態(tài)我在上面沒(méi)有刻意表示出來(lái),實(shí)際上,
在同時(shí)打開(kāi)的情況下,它的狀態(tài)變化是這樣的。
一端主機(jī)另一端主機(jī)
主動(dòng)打開(kāi)
為什么會(huì)是這樣呢?因?yàn)槟阆?,在同時(shí)打開(kāi)的情況下,兩端主機(jī)都發(fā)起
SYN報(bào)文,而主動(dòng)發(fā)起SYN的主機(jī)會(huì)處于SYN-SEND狀態(tài),發(fā)送完成
后,會(huì)等待接收SYN和ACK,在雙方主機(jī)都發(fā)送了SYN+ACK后,
雙方都處于SYN-RECEIVED(SYN-RCVD)狀態(tài),然后等待SYN+ACK
的報(bào)文到達(dá)后,雙方就會(huì)處于ESTABLISHED狀態(tài),開(kāi)始傳輸數(shù)據(jù)。
好了,到現(xiàn)在為止,我給你敘述了一下TCP連接建立過(guò)程中的狀態(tài)轉(zhuǎn)換,
現(xiàn)在你可以泡一壺茶喝點(diǎn)水,等著數(shù)據(jù)傳輸了。
好了,現(xiàn)在水喝夠了,這時(shí)候數(shù)據(jù)也傳輸完成了,數(shù)據(jù)傳輸完成后,這條TCP
連接就可以斷開(kāi)了。
現(xiàn)在我們把時(shí)鐘往前撥一下,調(diào)整到服務(wù)端處于SYN_RCVD狀態(tài)的時(shí)亥(),
因?yàn)閯偸盏搅薙YN包并發(fā)送了SYN+ACK包,此帚服務(wù)端很開(kāi)心,但
是這時(shí),服務(wù)端應(yīng)用進(jìn)程關(guān)閉了,然后應(yīng)用進(jìn)程發(fā)了一個(gè)FIN包,就會(huì)讓
服務(wù)器從SYNRCVD->FINWAIT1狀態(tài)。
、開(kāi)始客戶端主機(jī)服務(wù)器主機(jī)
?動(dòng)關(guān)冊(cè)
然后把時(shí)鐘調(diào)到現(xiàn)在,客戶端和服務(wù)器現(xiàn)在已經(jīng)傳輸完數(shù)據(jù)了,此時(shí)客戶
端發(fā)送了一條FIN報(bào)文希望斷開(kāi)連接,此時(shí)客戶端也會(huì)變
為FIN_WAIT_1狀態(tài),對(duì)于服務(wù)器來(lái)說(shuō),它接收到了FIN報(bào)文段并回復(fù)了
ACK才營(yíng)文,露會(huì)從ESTABLISHED->CLOSE_WAIT狀態(tài)。
服務(wù)主機(jī)
、、開(kāi)始客戶Ml主機(jī)H
主動(dòng)關(guān)用?動(dòng)關(guān)冊(cè)
發(fā)送數(shù)據(jù)
USTENSYN_SENT
發(fā)送S?N
接收SYN
接收SYN
接收RST發(fā)送SYN
發(fā)送SYN和ACK
ACK■
同時(shí)打開(kāi)
fcYN_RCV(l
收SYN和ACK
發(fā)送ACK
接唉APK
Close
送:FIN
發(fā)送FIN
mLOSE_WAITLAST.ACK
Close接收:FIN
發(fā)送:FIN發(fā)送:ACK
接收ACK
FIN_WA!T_2
接收Fl4
發(fā)送ACKCLOSING
位于CLOSE_WAIT狀態(tài)的服務(wù)端會(huì)發(fā)送FIN報(bào)文,然后把自己置于
LAST_ACK或態(tài)。處于FIN_WAIT_1的客戶端接收ACK消息就會(huì)變?yōu)?/p>
FIN_WAIT_2狀態(tài)。
這里需要先解釋一下CLOSING這個(gè)狀態(tài),F(xiàn)IN_WAIT1->CLOSING的轉(zhuǎn)換比較特殊
CLOSING這種狀態(tài)比較特殊,實(shí)際情況中應(yīng)該是很少見(jiàn),屬于一種比較罕
見(jiàn)的例外狀態(tài)。正常情況下,當(dāng)你發(fā)送FIN報(bào)文后,按理來(lái)說(shuō)是應(yīng)該先收
到(或同時(shí)收到)對(duì)方的ACK報(bào)文,再收到對(duì)方的FIN報(bào)文。但是
CLOSING狀態(tài)表示你發(fā)送FIN報(bào)文后,并沒(méi)有收到對(duì)方的ACK報(bào)文,
反而卻也收到了對(duì)方的FIN報(bào)文。
什么情況下會(huì)出現(xiàn)此種情況呢?其實(shí)細(xì)想一下,也不難得出結(jié)論:那就是
如果雙方在同時(shí)關(guān)閉一個(gè)鏈接的話,那么就出現(xiàn)了同時(shí)發(fā)送FIN報(bào)文的情
況,也即會(huì)出現(xiàn)CLOSING狀態(tài),表示雙方都正在關(guān)閉連接。
FIN_WAIT_2狀態(tài)的客戶端接收服務(wù)端主機(jī)發(fā)送的FIN+ACK消息,并
發(fā)癟ACK響應(yīng)后,會(huì)變?yōu)門IME_WAIT狀態(tài)。處于CLOSE_WAIT的客
戶端發(fā)送FIN會(huì)處于LAST_ACK狀態(tài)。
這里不少圖和博客雖然在圖上畫的是FIN+ACK報(bào)文后才會(huì)處于LAST_ACK狀態(tài),但
是描述的時(shí)候,一般通常只對(duì)于FIN進(jìn)行描述.也就是說(shuō)CLOSE_WAIT發(fā)送FIN才會(huì)
處于LASTACK狀態(tài)。
'、、開(kāi)始
M
所以這里FIN_WAIT_1->TIME_WAIT的狀態(tài)也就是接收FIN和ACK
并發(fā)送ACK之后,客戶端處于防狀態(tài)。
然后位于CLOSINIG狀態(tài)的客戶端這時(shí)候還有ACK接收的話,會(huì)繼續(xù)處
于TIME_WAIT狀態(tài),可以看到,TIME_WAIT狀態(tài)相當(dāng)于是客戶端在關(guān)
閉前的最詰一個(gè)狀態(tài),它是一種主動(dòng)關(guān)閉的狀態(tài);而LAST_ACK是服務(wù)
端在關(guān)閉前的最后一個(gè)狀態(tài),它是一種被動(dòng)打開(kāi)的狀態(tài)。
上面有幾個(gè)狀態(tài)比較特殊,這里我們?cè)敿?xì)解釋下。
IME_WAIT狀態(tài)
通信雙方建立TCP連接后,主動(dòng)關(guān)閉連接的一方就會(huì)進(jìn)入TIME_WAIT
狀態(tài)。TIME_WAIT狀態(tài)也稱為2MSL的等待狀態(tài)。在這個(gè)狀態(tài)下,TCP將
會(huì)等待最大段生存期(MaximumSegmentLifetime,MSL)時(shí)間的兩倍。
這里需要解釋下MSL
MSL是TCP段期望的最大生存時(shí)間,也就是在網(wǎng)絡(luò)中存在的最長(zhǎng)時(shí)間。
這個(gè)時(shí)間是有限制的,因?yàn)槲覀冎繲CP是依靠IP數(shù)據(jù)段來(lái)進(jìn)行傳輸
的,IP數(shù)據(jù)報(bào)中有TTL和跳數(shù)的字段,這兩個(gè)字段決定了IP的生存時(shí)
間,一般情況下,TCP的最大生存時(shí)間是2分鐘,不過(guò)這個(gè)數(shù)值是可以
修改的,根據(jù)不同操作系統(tǒng)可以修改此值。
基于此,我們來(lái)探討TIME_WAIT的狀態(tài)。
當(dāng)TCP執(zhí)行一個(gè)主動(dòng)關(guān)閉并發(fā)送最終的ACK時(shí),TIME_WAIT應(yīng)該以2
*最大生存時(shí)間存在,這樣就能夠讓TCP重新發(fā)送最終前ACK以避免出
現(xiàn)丟失的情況。重新發(fā)送最終的ACK并不是因?yàn)門CP重傳了ACK,而
是因?yàn)橥ㄐ帕硪环街貍髁薋IN,客戶端經(jīng)常會(huì)發(fā)送FIN,因?yàn)樗枰狝CK
的響應(yīng)才能夠關(guān)閉連接,如果生存時(shí)間超過(guò)了2MSL的話,客戶端就會(huì)發(fā)
送RST,使服務(wù)端出錯(cuò)。
TCP超時(shí)和重傳
沒(méi)有永遠(yuǎn)不出錯(cuò)誤的通信,這句話表明著不管外部條件多么完備,永遠(yuǎn)都
會(huì)有出錯(cuò)的可能。所以,在TCP的正常通信過(guò)程中,也會(huì)出現(xiàn)錯(cuò)誤,這種
錯(cuò)誤可能是由于數(shù)據(jù)包丟失引起的,也可能是由于數(shù)據(jù)包重復(fù)引起的,甚
至可能是由于數(shù)據(jù)包失序引起的。
TCP的通信過(guò)程中,會(huì)由TCP的接收端返回一系列的確認(rèn)信息來(lái)判斷是
否出現(xiàn)錯(cuò)誤,一旦出現(xiàn)丟包等情況,TCP就會(huì)啟動(dòng)重傳操作,重傳尚未確
認(rèn)的數(shù)據(jù)。
TCP的重傳有兩種方式,一種是基于時(shí)間,一種是基于確認(rèn)信息、,一般通
過(guò)確認(rèn)信息要比通過(guò)時(shí)間更加高效。
所以從這點(diǎn)就可以看出,TCP的確認(rèn)和重傳,都是基于數(shù)據(jù)包是否被確認(rèn)為前提的。
TCP在發(fā)送數(shù)據(jù)時(shí)會(huì)設(shè)置一個(gè)定時(shí)器,如果在定時(shí)器指定的時(shí)間內(nèi)未收到
確認(rèn)信息,那么就會(huì)觸發(fā)相應(yīng)的超時(shí)或者基于計(jì)時(shí)器的重傳操作,計(jì)時(shí)器
超時(shí)通常被稱為重傳超時(shí)(RTO)。
但是有另外一種不會(huì)引起延遲的方式,這就是快速重傳。
TCP在每次重傳一次報(bào)文后,其重傳時(shí)間都會(huì)加倍,這種"間隔時(shí)間加倍"
被稱為二進(jìn)制指數(shù)補(bǔ)償(binaryexponentialbackoff)。等到間隔時(shí)間加倍
到15.5min后,客戶端會(huì)顯示
[Connectionclosedbyforeignhost.
TCP擁有兩個(gè)閾值來(lái)決定如何重傳一個(gè)報(bào)文段,這兩個(gè)閾值被定義在
RFC[RCF1122]中,第一個(gè)閾值是R1,它表示愿意嘗試重傳的次數(shù),閾
值R2表示TCP應(yīng)該放棄連接的時(shí)間。R1和R2應(yīng)至少設(shè)為三次重傳和
100秒放棄TCP連接。
這里需要注意下,對(duì)連接建立報(bào)文SYN來(lái)說(shuō),它的R2至少應(yīng)該設(shè)置為3分鐘,但是
在不同的系統(tǒng)中,R1和R2值的設(shè)置方式也不同。
在Linux系統(tǒng)中,R1和R2的值可以通過(guò)應(yīng)用程序來(lái)設(shè)置,或者是修
改net.ipv4.tcp_retries1和net.ipv4.tcp_retries2的值來(lái)設(shè)置。變量值
就是重傳次數(shù)。
tcp_retries2的默認(rèn)值是15,這個(gè)充實(shí)次數(shù)的耗時(shí)大約是13-30分鐘,
這只是一個(gè)大概值,最終耗時(shí)時(shí)間還要取決于RTO,也就是重傳超時(shí)時(shí)
間。tcp_retries1的默認(rèn)值是3。
對(duì)于SYN段來(lái)說(shuō),net.ipv4.tcp_syn_retries和
net.ipv4.tcp_synack_retries這兩個(gè)值限制了SYN的重傳次數(shù),默認(rèn)是
5,大約是180秒。
Windows操作系統(tǒng)下也有R1和R2變量,它們的值被定義在下方的注冊(cè)
表中
HKLM\System\CurrentControlSet\Services\Tcpip\Parameters?
HKLM\System\CurrentControlSet\Services\Tcpip6\Parameters|
其中有一個(gè)非常重要的變量就是TcpMaxDataRetransmissions,這個(gè)
TcpMaxDataRetransmissions對(duì)應(yīng)Linux中的tcp_retries2變量,默認(rèn)
值是5o這個(gè)值的意思表示的是TCP在現(xiàn)有連接上未確認(rèn)數(shù)據(jù)段的次數(shù)。
快速重傳
我們上面提到了快速重傳,實(shí)際上快速重傳機(jī)制是基于接收端的反饋信息
來(lái)觸發(fā)的,它并不受重傳計(jì)時(shí)器的影響。所以與超時(shí)重傳相比,快速重傳
能夠有效的修復(fù)丟包情況。當(dāng)TCP連接的過(guò)程中接收端出現(xiàn)亂序的報(bào)文
(比如2-4-3)到達(dá)時(shí),TCP需要立刻生成確認(rèn)消息,這種確認(rèn)消息也
被稱為重復(fù)ACKo
當(dāng)失序報(bào)文到達(dá)時(shí),重復(fù)ACK要做到立刻返回,不允許延遲發(fā)送,此舉
的目的是要告訴發(fā)送方某段報(bào)文失序到達(dá)了,希望發(fā)送方指出失序報(bào)文段
的序列號(hào)。
還有一種情況也會(huì)導(dǎo)致重復(fù)ACK發(fā)給發(fā)送方,那就是當(dāng)前報(bào)文段的后續(xù)
報(bào)文發(fā)送至接收端,由此可以判斷當(dāng)前發(fā)送方的報(bào)文段丟失或者延遲到達(dá)。
因?yàn)檫@兩種情況導(dǎo)致的后果都是接收方?jīng)]有收到報(bào)文,但是我們卻無(wú)法判
斷到底是報(bào)文段丟失還是報(bào)文段沒(méi)有送達(dá)。因此TCP發(fā)送端會(huì)等待一定數(shù)
目的重復(fù)ACK被接受來(lái)決定數(shù)據(jù)是否丟失并觸發(fā)快速重傳。一般這個(gè)判
斷的數(shù)量是3,這段文字表述可能無(wú)法清晰理解,我們舉個(gè)例子。
1
ACK2
2
3
ACK2
4
ACK2
5
ACK2
ACK6
如上圖所示,報(bào)文段1成功接收并被確認(rèn)為ACK2,接收端的期待序號(hào)為
2,當(dāng)報(bào)文段2丟失后,報(bào)文段3。失序到達(dá),但是與接收端的期望不匹
配,所以接收端會(huì)重復(fù)發(fā)送冗余ACK2o
這樣,在超時(shí)重傳定時(shí)器到期之前,接收收到連續(xù)三個(gè)相同的ACK后,
發(fā)送端就知道哪個(gè)報(bào)文段丟失了,于是發(fā)送方會(huì)重發(fā)這個(gè)丟失的報(bào)文段,
這樣就不用等待重傳定時(shí)器的到期,大大提高了效率。
SACK
在標(biāo)準(zhǔn)的TCP確認(rèn)機(jī)制中,如果發(fā)送方發(fā)送了0-10000序號(hào)之間的數(shù)
據(jù),但是接收方只接收到了0-1000,3000-10000之間的數(shù)據(jù),而1000
-3000之間的數(shù)據(jù)沒(méi)有到達(dá)接收端,此時(shí)發(fā)送方會(huì)重傳1000-10000之
間的數(shù)據(jù),實(shí)際上這是沒(méi)有必要的,因?yàn)?000后面的數(shù)據(jù)已經(jīng)被接收了。
但是發(fā)送方無(wú)法感知這種情況的存在。
如何避免或者說(shuō)解決這種問(wèn)題呢?
為了優(yōu)化這種情況,我們有必要讓客戶端知道更多的消息,在TCP報(bào)文段
中,有一個(gè)SACK選項(xiàng)字段,這個(gè)字段是一種選擇性確認(rèn)(selective
acknowledgment)機(jī)制,這個(gè)機(jī)制能告訴TCP客戶端,用我們的俗語(yǔ)來(lái)
解釋就是:“我這里最多允許接收1000之后的報(bào)文段,但是我卻收到了
3000-10000的報(bào)文段,請(qǐng)給我1000-3000之間的報(bào)文段”。
但是,這個(gè)選擇性確認(rèn)機(jī)制的是否開(kāi)啟還受一個(gè)字段的影響,這個(gè)字段就
是SACK允許選項(xiàng)字段,通信雙方在SYN段或者SYN+ACK段中添加
SACK允許選項(xiàng)字段來(lái)通知對(duì)端主機(jī)是否支持SACK,如果雙方都支持的
話,后續(xù)在SYN段中就可以使用SACK選項(xiàng)了。
這里需要注意下:SACK選項(xiàng)字段只能出現(xiàn)在SYN段中.
偽超時(shí)和重傳
在某些情況下,即使沒(méi)有出現(xiàn)報(bào)文段的丟失也可能會(huì)引發(fā)報(bào)文重傳。這種
重傳行為被稱為偽重傳(spuriousretransmission),這種重傳是沒(méi)有必要
的,造成這種情況的因素而能是由于偽超時(shí)(spurioustimeout),偽超時(shí)的
意思就是過(guò)早的判定超時(shí)發(fā)生。造成偽超時(shí)的因素有很多,比如報(bào)文段失
序到達(dá),報(bào)文段重復(fù),ACK丟失等情況。
檢測(cè)和處理偽超時(shí)的方法有很多,這些方法統(tǒng)稱為檢測(cè)算法和響應(yīng)算法。
檢測(cè)算法用于判斷是否出現(xiàn)了超時(shí)現(xiàn)象或出現(xiàn)了計(jì)時(shí)器的重傳現(xiàn)象。一旦
出現(xiàn)了超時(shí)或者重傳的情況,就會(huì)執(zhí)行響應(yīng)算法撤銷或者減輕超時(shí)帶來(lái)的
影響,下面是幾種算法,此篇文章暫不深入這些實(shí)現(xiàn)細(xì)節(jié)
重復(fù)SACK擴(kuò)展-DSACK
Eifel檢測(cè)算法
前移RTO恢復(fù)-F-RTO
Eifel響應(yīng)算法
包失序和包重復(fù)
上面我們討論的都是TCP如何處理丟包的問(wèn)題,我們下面來(lái)討論一下包失
序和包重復(fù)的問(wèn)題。
包失序
數(shù)據(jù)包的失序到達(dá)是互聯(lián)網(wǎng)中極其容易出現(xiàn)的一種情況,由于IP層并不能
保證數(shù)據(jù)包的有序性,每個(gè)數(shù)據(jù)包的發(fā)送都可能會(huì)選擇當(dāng)前情況傳輸速度
最快的鏈路,所以很有可能出現(xiàn)發(fā)送了A->B->C的三個(gè)數(shù)據(jù)包,到達(dá)
接收端的數(shù)據(jù)包順序是C->A->B或者B->C->A等等。這就是包失
序的一種現(xiàn)象。
在包傳輸中,主要分為兩種鏈路:正向鏈路(SYN)和反向鏈路(ACK)
如果失序發(fā)生在正向鏈路,TCP是無(wú)法正確判斷數(shù)據(jù)包是否丟失的,數(shù)據(jù)
的丟失和失序都會(huì)導(dǎo)致接收端收到無(wú)序的數(shù)據(jù)包,造成數(shù)據(jù)之間的空缺。
如果這種空缺不夠大的話,這種情況影響不大;但是如果空缺比較大的話,
可能會(huì)導(dǎo)致偽重傳。
如果失序發(fā)生在反向鏈路,就會(huì)使TCP的窗口前移,然后收到重復(fù)而應(yīng)該
被丟棄的ACK,導(dǎo)致發(fā)送端出現(xiàn)不必要的流量突發(fā),影響可用網(wǎng)絡(luò)帶寬。
回到我們上面討論的快速重傳,由于快速重傳是根據(jù)重復(fù)ACK推斷出現(xiàn)
丟包而啟動(dòng)的,它不用等到重傳計(jì)時(shí)器超時(shí)。由于TCP接收端會(huì)對(duì)接收到
的失序報(bào)文立刻返回ACK,所以網(wǎng)絡(luò)中任何一個(gè)失序到達(dá)的報(bào)文都可能會(huì)
造成重復(fù)ACK。假設(shè)一旦收到ACK,就會(huì)啟動(dòng)快速重傳機(jī)制,當(dāng)ACK數(shù)
量激增,就會(huì)導(dǎo)致大量不必要的重傳發(fā)生,所以快速重傳應(yīng)該達(dá)到重復(fù)閾
值(dupthresh)再觸發(fā)。但是在互聯(lián)網(wǎng)中,嚴(yán)重的失序并不常見(jiàn),因此
dupthresh的值可以設(shè)置的盡量小,一般來(lái)說(shuō)3就能處理絕大部分情況。
包重復(fù)
包重復(fù)也是互聯(lián)網(wǎng)中出現(xiàn)很少的一種情況,它指的是在網(wǎng)絡(luò)傳輸過(guò)程中,
包可能會(huì)出現(xiàn)傳輸多次的情況,當(dāng)重傳生成時(shí),TCP可能會(huì)出現(xiàn)混淆。
包的重復(fù)可以使接收端生成一系列的重復(fù)ACK,這種情況可以使用SACK
協(xié)商來(lái)解決。
TCP數(shù)據(jù)流和窗口管理
我們?cè)?0張圖帶你搞懂TCP和UDP這篇文章中知道了可以使用滑動(dòng)
窗口來(lái)實(shí)現(xiàn)流量控制,也就是說(shuō),客戶端和服務(wù)器可以相互提供數(shù)據(jù)流信
息的交換,數(shù)據(jù)流的相關(guān)信息主要包括報(bào)文段序列號(hào)、ACK號(hào)和窗口大小。
圖中的兩個(gè)箭頭表示數(shù)據(jù)流方向,數(shù)據(jù)流方向也就是TCP報(bào)文段的傳輸方
向。可以看到,每個(gè)TCP報(bào)文段中都包括了序列號(hào)、ACK和窗口信息,
可能還會(huì)有用戶數(shù)據(jù)。TCP報(bào)文段中的窗口大小表示接收端還能夠接收的
緩存空間的大小,以字節(jié)為單位。這個(gè)窗口大小是一種動(dòng)態(tài)的,因?yàn)闊o(wú)時(shí)
無(wú)刻都會(huì)有報(bào)文段的接收和消失,這種動(dòng)態(tài)調(diào)整的窗口大小我們稱之為滑
動(dòng)窗口,下面我們就來(lái)具體認(rèn)識(shí)一下滑動(dòng)窗口。
滑動(dòng)窗口
TCP連接的每一端都可以發(fā)送數(shù)據(jù),但是數(shù)據(jù)的發(fā)送不是沒(méi)有限制的,實(shí)
際上,TCP連接的兩端都各自維護(hù)了一個(gè)發(fā)送窗口結(jié)構(gòu)(sendwindow
structure)和接收窗口結(jié)構(gòu)(receivewindowstructure),這兩個(gè)窗口結(jié)
構(gòu)就是數(shù)據(jù)發(fā)送的限制。
發(fā)送方窗口
下圖是一個(gè)發(fā)送方窗口的示例。
發(fā)送窗口結(jié)構(gòu)
窗口移動(dòng)方向
在這幅圖中,涉及滑動(dòng)窗口的四種概念:
已經(jīng)發(fā)送并確認(rèn)的報(bào)文段:發(fā)送給接收方后,接收方回回復(fù)ACK來(lái)對(duì)報(bào)
文段進(jìn)行響應(yīng),圖中標(biāo)注綠色的報(bào)文段就是已經(jīng)經(jīng)過(guò)接收方確認(rèn)的報(bào)文段。
已經(jīng)發(fā)送但是還沒(méi)確認(rèn)的報(bào)文段:圖中綠色區(qū)域是經(jīng)過(guò)接收方確認(rèn)的報(bào)文
段,而淺藍(lán)色這段區(qū)域指的是已經(jīng)發(fā)送但是還未經(jīng)過(guò)接收方確認(rèn)的報(bào)文段。
等待發(fā)送的報(bào)文段:圖中深藍(lán)色區(qū)域是等待發(fā)送的報(bào)文段,它屬于發(fā)送窗
口結(jié)構(gòu)的一部分,也就是說(shuō),發(fā)送窗口結(jié)構(gòu)其實(shí)是由已發(fā)送未確認(rèn)+等待
發(fā)送的報(bào)文段構(gòu)成。
窗口滑動(dòng)時(shí)才能發(fā)送的報(bào)文段:如果圖中的[4,9]這個(gè)集合內(nèi)的報(bào)文段發(fā)送
完畢后,整個(gè)滑動(dòng)窗口會(huì)向右移動(dòng),圖中橙色區(qū)域就是窗口右移時(shí)才能發(fā)
送的報(bào)文段。
滑動(dòng)窗口也是有邊界的,這個(gè)邊界是Leftedge和Rightedge,Leftedge是
窗口的左邊界,Rightedge是窗口的右邊界。
當(dāng)Leftedge向右移動(dòng)而Rightedge不變時(shí),這個(gè)窗口可能處于close關(guān)
閉狀態(tài)。隨著已發(fā)送的數(shù)據(jù)逐漸被確認(rèn)從而導(dǎo)致窗口變小時(shí),就會(huì)發(fā)生這
種情況。
發(fā)送窗口結(jié)構(gòu)
窗口移動(dòng)方向
-2
234567891011
此時(shí)沒(méi)有左右邊界
窗口close
當(dāng)Rightedge向右移動(dòng)時(shí),窗口會(huì)處于open打開(kāi)狀態(tài),允許發(fā)送更多的
數(shù)據(jù)。當(dāng)接收端進(jìn)程讀取緩沖區(qū)數(shù)據(jù),從而使緩沖區(qū)接收更多數(shù)據(jù)時(shí),就
會(huì)處于這種狀態(tài)。
2345678910
此時(shí)沒(méi)有左右邊界
窗口close發(fā)送窗口結(jié)構(gòu)
:已經(jīng)發(fā)送但是:等待發(fā)送
發(fā)送并確認(rèn)的
:還沒(méi)確認(rèn):的報(bào)文段
報(bào)文段
:的報(bào)文段:
|窗口移動(dòng)方向
LeftedgeRightedge
右邊界向右移動(dòng)
窗口open
還可能會(huì)發(fā)生Rightedge向左移動(dòng)的情況,會(huì)導(dǎo)致發(fā)送并確認(rèn)的報(bào)文段變
小,這種情況被稱為糊涂窗口綜合癥,這種情況是我們不愿意看到的。出
現(xiàn)糊涂窗口綜合癥時(shí),通信雙方用于交換的數(shù)據(jù)段大小會(huì)變小,而網(wǎng)絡(luò)固
定的開(kāi)銷卻沒(méi)有變化,每個(gè)報(bào)文段中有用數(shù)據(jù)相對(duì)于頭部信息的比例較小,
導(dǎo)致傳輸效率非常低。
這就相當(dāng)于之前你明明有能力花一天時(shí)間寫完一個(gè)復(fù)雜的頁(yè)面,現(xiàn)在你花
了一天的時(shí)間卻改了一個(gè)標(biāo)題的bug,大材小用。
每個(gè)TCP報(bào)文段都包含ACK號(hào)和窗口通告信息,所以每當(dāng)收到響應(yīng)時(shí),
TCP接收方都會(huì)根據(jù)這兩個(gè)參數(shù)調(diào)整窗口結(jié)構(gòu)。
TCP滑動(dòng)窗口的Leftedge永遠(yuǎn)不可能向左移動(dòng),因?yàn)榘l(fā)送并確認(rèn)的報(bào)文
段永遠(yuǎn)不可能被取消,就像這世界上沒(méi)有后悔藥一樣。這條邊緣是由另一
段發(fā)送的ACK號(hào)控制的。當(dāng)ACK標(biāo)號(hào)使窗口向右移動(dòng)但是窗口大小沒(méi)
有改變時(shí),則稱該窗口向前滑動(dòng)。
如果ACK的編號(hào)增加但是窗口通告信息隨著其他ACK的到達(dá)卻變小
了,止匕時(shí)Leftedge會(huì)接近Rightedge?當(dāng)Leftedge和Rightedge重
合時(shí),此時(shí)發(fā)送方不會(huì)再傳輸任何數(shù)據(jù),這種情況被稱為零窗口。此時(shí)TCP
發(fā)送方會(huì)發(fā)起窗口探測(cè),等待合適的時(shí)機(jī)再發(fā)送數(shù)據(jù)。
接收方窗口
接收方也維護(hù)了一個(gè)窗口結(jié)構(gòu),這個(gè)窗口要比發(fā)送方的簡(jiǎn)單很多。這個(gè)窗
口記錄了己經(jīng)接收并確認(rèn)的數(shù)據(jù),以及它能夠接收的最大序列號(hào)。接收方
的窗口結(jié)構(gòu)不會(huì)存儲(chǔ)重復(fù)的報(bào)文段和ACK,同時(shí)接收方的窗口也不會(huì)記錄
不應(yīng)該收到的報(bào)文段和ACKo下面是TCP接收方的窗口結(jié)構(gòu)。
接收方窗口結(jié)構(gòu)
已經(jīng)接收不能接收的
接收后會(huì)進(jìn)行保存的報(bào)文段
并確認(rèn)的報(bào)文段
報(bào)文段
LeftedgeRightedge
與發(fā)送端的窗口一樣,接收方窗口結(jié)構(gòu)也維護(hù)了一個(gè)Leftedge和Right
edge。位于Leftedge左邊的被稱為已經(jīng)接收并確認(rèn)的報(bào)文段,位于Right
edge右邊的被稱為不能接收的報(bào)文段。
對(duì)于接收端來(lái)說(shuō),到達(dá)序列號(hào)小于Leftefge的被認(rèn)為是已經(jīng)重復(fù)的數(shù)據(jù),
需要丟棄。超過(guò)Rightedge的被認(rèn)為超出處理范圍。只有當(dāng)?shù)竭_(dá)的報(bào)文段
等于Leftedge時(shí),數(shù)據(jù)才不會(huì)被丟棄,窗口才能夠向前滑動(dòng)。
接收方窗口結(jié)構(gòu)也會(huì)存在零窗口的情況,如果某個(gè)應(yīng)用進(jìn)程消耗數(shù)據(jù)很慢,
而TCP發(fā)送方卻發(fā)送了大量的數(shù)據(jù)給接收方,會(huì)造成TCP緩沖區(qū)溢出,
通告發(fā)送方不要再發(fā)送數(shù)據(jù)了,但是應(yīng)用進(jìn)程卻以非常慢的速度消耗緩沖
區(qū)的數(shù)據(jù)(比如1字節(jié)),就會(huì)告訴接收端只能發(fā)送一個(gè)字節(jié)的數(shù)據(jù),這
個(gè)過(guò)程慢慢持續(xù),造成網(wǎng)絡(luò)開(kāi)銷大,效率很低。
我們上面提到了窗口存在Leftedge=Rightedge的情況,此時(shí)被稱為零窗口,下面我們
就來(lái)具體研究一下零窗口。
零窗口
TCP是通過(guò)接收端的窗口通告信息來(lái)實(shí)現(xiàn)流量控制的。通告窗口告訴了
TCP,接收端能夠接收的數(shù)據(jù)量。當(dāng)接收方的窗口變?yōu)?時(shí),可以有效
的阻止發(fā)送端繼續(xù)發(fā)送數(shù)據(jù)。當(dāng)接收端重新獲得可用空間時(shí),它會(huì)給發(fā)送
端傳輸一個(gè)窗口更新告知自己能夠接收數(shù)據(jù)了。窗口更新一般是純
ACK,即不帶任何數(shù)據(jù)。但是純ACK不能保證一定會(huì)到達(dá)發(fā)送端,于是
需要有相關(guān)的措施能夠處理這種丟包。
如果純ACK丟失的話,通信雙方就會(huì)一直處于等待狀態(tài),發(fā)送方心想拉
垮的接收端怎么還讓我發(fā)送數(shù)據(jù)!接收端心想天殺的發(fā)送方怎么還不發(fā)數(shù)
據(jù)!為了防止這種情況,發(fā)送方會(huì)采用一個(gè)持續(xù)計(jì)時(shí)器來(lái)間歇性的查詢接
收方,看看其窗口是否已經(jīng)增長(zhǎng)。持續(xù)計(jì)時(shí)器會(huì)觸發(fā)窗口探測(cè),強(qiáng)制要求
接收方返回帶有更新窗口的ACKo
窗口探測(cè)包含一個(gè)字節(jié)的數(shù)據(jù),采用的是TCP丟失重傳的方式。當(dāng)TCP
持續(xù)計(jì)時(shí)器超時(shí)后,就會(huì)觸發(fā)窗口探測(cè)的發(fā)送。一個(gè)字節(jié)的數(shù)據(jù)能否被接
收端接收,還要取決于其緩沖區(qū)的大小。
擁塞控制
有了TCP的窗口控制后,使計(jì)算機(jī)網(wǎng)絡(luò)中兩個(gè)主機(jī)之間不再是以單個(gè)數(shù)據(jù)
段的形式發(fā)送了,而是能夠連續(xù)發(fā)送大量的數(shù)據(jù)包。然而,大量數(shù)據(jù)包同
時(shí)也伴隨著其他問(wèn)題,比如網(wǎng)絡(luò)負(fù)載、網(wǎng)絡(luò)擁堵等問(wèn)題。TCP為了防止這
類問(wèn)題的出現(xiàn),使用了擁塞控制機(jī)制,擁塞控制機(jī)制會(huì)在面臨網(wǎng)絡(luò)擁塞時(shí)
遏制發(fā)送方的數(shù)據(jù)發(fā)送。
擁塞控制主要有兩種方法
端到端的擁塞控制:因?yàn)榫W(wǎng)絡(luò)層沒(méi)有為運(yùn)輸層擁塞控制提供顯示支持。所以
即使網(wǎng)絡(luò)中存在擁塞情況,端系統(tǒng)也要通過(guò)對(duì)網(wǎng)絡(luò)行為的觀察來(lái)推斷。TCP
就是使用了端到端的擁塞控制方式。IP層不會(huì)向端系統(tǒng)提供有關(guān)網(wǎng)絡(luò)擁塞
的反饋信息。那么TCP如何推斷網(wǎng)絡(luò)擁塞呢?如果超時(shí)或者三次冗余確
認(rèn)就被認(rèn)為是網(wǎng)絡(luò)擁塞,TCP會(huì)減小窗口的大小,或者增加往返時(shí)延來(lái)避
免。
網(wǎng)絡(luò)輔助的擁塞控制:在網(wǎng)絡(luò)輔助的擁塞控制中,路由器會(huì)向發(fā)送方提供關(guān)
于網(wǎng)絡(luò)中擁塞狀態(tài)的反饋。這種反饋信息就是一個(gè)比特信息,它指示鏈路
中的擁塞情況。
下圖描述了這兩種擁塞控制方式
TCP擁塞控制
如果你看到這里,那我就暫定認(rèn)為你了解了TCP實(shí)現(xiàn)可靠性的基礎(chǔ)了,那
就是使用序號(hào)和確認(rèn)號(hào)。除此之外,另外一個(gè)實(shí)現(xiàn)TCP可靠性基礎(chǔ)的就是
TCP的擁塞控制。如果說(shuō)
TCP所采用的方法是讓每一個(gè)發(fā)送方根據(jù)所感知到的網(wǎng)絡(luò)的擁塞程度來(lái)限
制發(fā)出報(bào)文段的速率,如果TCP發(fā)送方感知到?jīng)]有什么擁塞,則TCP發(fā)
送方會(huì)增加發(fā)送速率;如果發(fā)送方感知沿著路徑有阻塞,那么發(fā)送方就會(huì)
降低發(fā)送速率。
但是這種方法有三個(gè)問(wèn)題
1.
TCP發(fā)送方如何限制它向其他連接發(fā)送報(bào)文段的速率呢?
2.
3.
一個(gè)TCP發(fā)送方是如何感知到網(wǎng)絡(luò)擁塞的呢?
4.
5.
當(dāng)發(fā)送方感知到端到端的擁塞時(shí),采用何種算法來(lái)改變其發(fā)送速率呢?
6.
我們先來(lái)探討一下第一個(gè)問(wèn)題,TCP發(fā)送方如何限制它向其他連接發(fā)送報(bào)
文段的速率呢?
我們知道TCP是由接收緩存、發(fā)送緩存和變量(LastByteRead,rwnd,等)
組成。發(fā)送方的TCP擁塞控制機(jī)制會(huì)跟蹤一個(gè)變量,即擁塞窗口
(congestionwindow)的變量,擁塞窗口表示為cwnd,用于限制TCP在
接收到ACK之前可以發(fā)送到網(wǎng)絡(luò)的數(shù)據(jù)量。而接收窗口(rwnd)是一個(gè)用
于告訴接收方能夠接受的數(shù)據(jù)量。
一般來(lái)說(shuō),發(fā)送方未確認(rèn)的數(shù)據(jù)量不得超過(guò)cwnd和rwnd的最小值,也
就是
LastByteSent-LastByteAcked<=min(cwnd,rwnd)
由于每個(gè)數(shù)據(jù)包的往返時(shí)間是RTT,
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年度山西省高校教師資格證之高等教育法規(guī)考試題庫(kù)
- 國(guó)家自然基金簡(jiǎn)介(1)-資助研究項(xiàng)目屬性(2)-資助研培訓(xùn)課件
- 2024年泥水工項(xiàng)目協(xié)議模板下載
- 2024年除雪作業(yè)協(xié)議細(xì)則
- 2024汽車購(gòu)貸擔(dān)保協(xié)議樣本全文參閱
- 2024年辦公室裝修施工協(xié)議樣本
- 2024年斗毆雙方和解賠償協(xié)議樣式
- 中小學(xué)教師數(shù)據(jù)素養(yǎng)-江蘇師范大學(xué)中國(guó)大學(xué)mooc課后章節(jié)答案期末考試題庫(kù)2023年
- 崗位保密條款:2024勞動(dòng)協(xié)議增補(bǔ)篇
- 2024年全職收銀員勞動(dòng)協(xié)議范本
- 二年級(jí)珍惜時(shí)間發(fā)奮學(xué)習(xí)主題班會(huì)課件
- 平行與垂直(公開(kāi)課)課件
- 城市軌道交通牽引供電及電力技術(shù)分析
- 建筑行業(yè)會(huì)計(jì)基本處理課件
- 三年級(jí)上冊(cè)美術(shù)課件-第4課 連環(huán)畫 ▏人美版 (共15張PPT)
- 光州事件與韓國(guó)的民主化課件
- 新人教統(tǒng)編版四年級(jí)上冊(cè)道德與法治 第9課 正確認(rèn)識(shí)廣告 第2課時(shí) 教學(xué)課件
- 收取執(zhí)行款銀行賬戶確認(rèn)書
- 初中藝術(shù)鄂教七年級(jí)上冊(cè)(2022年新編) 漫步藝術(shù)長(zhǎng)廊舞劇欣賞《永不消逝的電波》教學(xué)設(shè)計(jì)
- 水電廠檢修標(biāo)準(zhǔn)化作業(yè)流程圖
- GB 18384-2020 電動(dòng)汽車安全要求
評(píng)論
0/150
提交評(píng)論