程序員TCP 基礎(chǔ)知識(shí)匯編_第1頁(yè)
程序員TCP 基礎(chǔ)知識(shí)匯編_第2頁(yè)
程序員TCP 基礎(chǔ)知識(shí)匯編_第3頁(yè)
程序員TCP 基礎(chǔ)知識(shí)匯編_第4頁(yè)
程序員TCP 基礎(chǔ)知識(shí)匯編_第5頁(yè)
已閱讀5頁(yè),還剩29頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論