本文是參考【圖解TCP/IP】
TCP(Transmission Control Protocol)是傳輸控制協(xié)議,其作用于傳輸層,是一種提供了面向連接通信服務(wù)的協(xié)議
看TCP的英文全稱就知道,其主要作用就是傳輸 、控制,傳輸?shù)氖菙?shù)據(jù),控制的是在傳輸過程中丟包后的重發(fā) 、分包亂序后的有序重組 、控制數(shù)據(jù)傳輸?shù)乃俾史乐咕W(wǎng)絡(luò)擁塞等
這也是我們口中一直說的TCP是一種可靠的傳輸協(xié)議的原因。本文就將對TCP的作用過程以及一些機(jī)制進(jìn)行講解
TCP的通信機(jī)制
- 一、TCP連接管理
- 二、分段數(shù)據(jù)發(fā)送
- 三、重發(fā)控制
- 四、滑動窗口控制
- 五、滑動窗口的重發(fā)控制
- 六、流控制
- 七、擁塞控制
- 八、結(jié)束語
一、TCP連接管理
TCP是面向連接進(jìn)行通信服務(wù)的協(xié)議,所謂連接,其實(shí)就是在兩臺需要數(shù)據(jù)交互的主機(jī)之間建立一條虛擬的線路,所有的數(shù)據(jù)交互都是通過這條線路進(jìn)行的,而TCP就負(fù)責(zé)這整個線路的創(chuàng)建、銷毀、維護(hù)管理等工作
在建立連接之前,需要做一些準(zhǔn)備,為了確保通信兩端是否可以進(jìn)行正常通信,發(fā)送端會通過TCP的首部發(fā)送一個SYN包作為建立連接的請求并等待接收端確認(rèn)應(yīng)答。如果接收端確認(rèn)應(yīng)答并返回一個ACK包,則表示接收端同意與發(fā)送端進(jìn)行通信,然后發(fā)送端再次發(fā)送一個ACK包給接收端,表示已收到你的同意通信的消息了,此后兩端就可以正常通信了;若接收端沒有返回給發(fā)送端一個確認(rèn)應(yīng)答的ACK包,則表示不同意與發(fā)送端進(jìn)行通信,那么兩端自然無法進(jìn)行后續(xù)的通信了
兩端若在通信完成以后肯定需要斷開通信,同樣也需要兩端互發(fā)包來確認(rèn)是否要斷開通信。比如,發(fā)送端先發(fā)送一個FIN包給接收端,告知想要斷開連接,然后接收端可以返回給發(fā)送端一個ACK包表示同意你斷開連接的請求,緊接著接收端也向發(fā)送端發(fā)送了一個FIN包,表示其也想斷開連接的意愿,發(fā)送端在接收到該包后隨即返回給接收端一個ACK包表示我也同意你斷開連接,這樣,兩端就斷開連接了
總結(jié)一下,一次完整的TCP連接的建立與斷開至少需要來回發(fā)送7個包,其中建立連接需要發(fā)3個包,斷開連接需要發(fā)4個包
我們來看一下完整的通信過程簡圖

這就是大家常說的三次握手,四次揮手的過程
如果不好理解上面的建立、斷開連接過程,這里我再給大家舉一個小小的例子
發(fā)送端與接收端通信,就好比我們?nèi)粘I钪袃蓚€人打電話,例如現(xiàn)在A給B打電話
- A問B:喂?你是B嗎?
- B回答A:我是B呀,你是A嗎?
- A回答B(yǎng):對的,我是A
就這樣一個簡單的三次對話就確認(rèn)了雙方是想要互相通信的對象,因此連接就此建立了
那么當(dāng)A和B聊完天,準(zhǔn)備掛電話了
- A對B說:我的事說完了,那么沒啥事我就掛電話了哈
- B回答A:好的
- B又對A補(bǔ)充了一句:我也沒啥事了,那我也掛了哈
- A回答B(yǎng):好的
這三段對話就使通信雙方確認(rèn)了會話結(jié)束,因此連接就此斷開了
二、分段數(shù)據(jù)發(fā)送
TCP不是拿到一整個包就直接原封不動地傳給接收端的,因?yàn)槿暨@樣做,即使是發(fā)生了數(shù)據(jù)丟失,也不知道到底丟失了哪部分的數(shù)據(jù),因此其采用的就是將數(shù)據(jù)分段發(fā)送的方式
這里先說明一點(diǎn),不光建立和斷開連接時接收端需要向發(fā)送端發(fā)送請求應(yīng)答,在數(shù)據(jù)交互時也是需要的
例如有一個數(shù)據(jù)包,我們可以將其按順序給每一個字節(jié)都標(biāo)上一個序號,然后我們假設(shè)每次發(fā)送1000個序號區(qū)間的數(shù)據(jù)給接收端,所以第一次發(fā)送的是 序號 1 ~ 1000 的數(shù)據(jù),接收端接收到了以后會返回給發(fā)送端一個請求應(yīng)答,告知發(fā)送端下一次請發(fā)送 序號 1001 ~ 2000 的數(shù)據(jù)過來,過程如圖所示

上面我們假設(shè)的是每次發(fā)送1000個***區(qū)間的單位,而實(shí)際過程中,卻不一定是這個值。
在前面的學(xué)習(xí)中,我們得知數(shù)據(jù)在數(shù)據(jù)鏈路層中傳輸會收到MTU(最大傳輸單元)的影響,若數(shù)據(jù)大于該值,IP則會被分片處理,因此我們盡可能地不讓這種事情發(fā)生,那么就要讓傳輸?shù)拿慷螖?shù)據(jù)大小小于該通信線路上最小的MTU,該值稱為MSS(最大消息長度)
該值是會在建立連接的三次握手時被計算獲得的,比如發(fā)送端在請求接收端的時候,在發(fā)送的包上附帶上其線路上的MTU大小為4000,然后接收端在發(fā)送確認(rèn)應(yīng)答給發(fā)送端時,也會在包上附帶上其線路上的MTU大小為1460,此時發(fā)送端接收到確認(rèn)應(yīng)答后比較兩個MTU的大小,取其中小的那個值作為之后數(shù)據(jù)傳輸每段的數(shù)據(jù)大小
如圖:

三、重發(fā)控制
我們都知道,在數(shù)據(jù)傳輸過程中可能會因?yàn)楦鞣N原因出現(xiàn)丟包現(xiàn)象,而當(dāng)出現(xiàn)丟包現(xiàn)象時,即發(fā)送端在發(fā)完數(shù)據(jù)以后等待一段時間,并未收到接收端的確認(rèn)應(yīng)答,則視為丟包,于是就會進(jìn)行重發(fā)
其中丟包現(xiàn)象又分為兩種:
- 發(fā)送端向接收端發(fā)送數(shù)據(jù)的過程中,發(fā)生了丟包現(xiàn)象,接收端并未接收到數(shù)據(jù),因此不會給發(fā)送端發(fā)送確認(rèn)應(yīng)答
- 接收端收到了發(fā)送端傳過來的數(shù)據(jù),并且也向發(fā)送端返回了確認(rèn)應(yīng)答,但確認(rèn)應(yīng)答的包卻在發(fā)送的途中出現(xiàn)了丟包,所以發(fā)送端接收不到確認(rèn)應(yīng)答
以上兩種情況如下圖所示:
第一種情況:

第二種情況:

那么,發(fā)送端發(fā)送完數(shù)據(jù)后多久沒收到確認(rèn)應(yīng)答才判定數(shù)據(jù)丟包了呢?這個都是隨著網(wǎng)絡(luò)環(huán)境的變化而變化的,TCP會在每次發(fā)包時計算往返時間以及偏差來決定等待的時間
若重發(fā)后又出現(xiàn)了丟包,則下一次等待的時間會以2倍、4倍的指數(shù)函數(shù)延長
但其又不會無限進(jìn)行重發(fā),當(dāng)重發(fā)次數(shù)達(dá)到一定程度后,會判定為網(wǎng)絡(luò)異常,兩端通信就會被強(qiáng)制關(guān)閉
四、滑動窗口控制
上面介紹了TCP將數(shù)據(jù)分段發(fā)送,雖然提高了傳輸?shù)目煽啃?,但是存在著一個致命的缺點(diǎn),那就是效率非常低,因?yàn)槊克鸵欢味家却邮斩说拇_認(rèn)應(yīng)答,若整個數(shù)據(jù)的分段較多,那么通信的性能可能就會很低了,因此TCP引入了窗口這個概念
所謂窗口,表示的是無需等待確認(rèn)應(yīng)答而可以連續(xù)發(fā)送的連續(xù)多段數(shù)據(jù)的區(qū)域,如圖

我們假設(shè)每段數(shù)據(jù)長度為1000,這里的窗口大小為4段,因此發(fā)送端可以將這四段數(shù)據(jù)都分別發(fā)送出去并且不需要發(fā)送一段數(shù)據(jù)以后等待一個確認(rèn)應(yīng)答,如圖

此時的窗口包含4個段,即窗口內(nèi)包含4000個字節(jié)的數(shù)據(jù),我們稱之為窗口大小
接收端在返回相應(yīng)的確認(rèn)應(yīng)答給發(fā)送端時,發(fā)送端會根據(jù)收到的確認(rèn)應(yīng)答,繼續(xù)發(fā)送比該確認(rèn)應(yīng)答中***大4000的數(shù)據(jù),如圖所示

五、滑動窗口的重發(fā)控制
若使用了滑動窗口控制這一技術(shù)后,即使某段數(shù)據(jù)出現(xiàn)了丟包現(xiàn)象,也不會造成太大的影響,因?yàn)榻邮斩藭贿吔邮瞻l(fā)送端傳過來的數(shù)據(jù),一邊用某種方式告知發(fā)送端剛才丟失了哪段數(shù)據(jù)
接下來我們來介紹一下其作用過程,如圖所示

圖中,在發(fā)送第二段數(shù)據(jù)(1001 ~ 2000)時發(fā)生了丟包,因此接收端沒有接收到對應(yīng)的包,所以當(dāng)發(fā)送端傳過來第三段數(shù)據(jù)的時候,接收端返回的仍是第二段的確認(rèn)應(yīng)答,緊接著發(fā)送端分別發(fā)送了第四段、第五段數(shù)據(jù),可接收端都返回的是第二段的確認(rèn)應(yīng)答
就這樣連著三次發(fā)送了同一個確認(rèn)應(yīng)答給發(fā)送端,所以發(fā)送端得知剛才傳輸數(shù)據(jù)的過程中第二段數(shù)據(jù)發(fā)生了丟包,因此此時會將丟失的數(shù)據(jù)重發(fā)一份
然后接收端在接收到之前丟掉的那段數(shù)據(jù)以后,因?yàn)橹暗臄?shù)據(jù)都成功接收了,所以下一次就開始請求 5001 ~ 6000 這段數(shù)據(jù)了
六、流控制
有時,發(fā)送端發(fā)送給接收端的數(shù)據(jù)超過了接收端的最大承載能力,因此會造成數(shù)據(jù)無法接收的情況,從而導(dǎo)致之后會進(jìn)行數(shù)據(jù)重發(fā),這非常得浪費(fèi)性能。
為了防止上述情況得發(fā)生,TCP提供了一種機(jī)制可以使發(fā)送端每次發(fā)送的數(shù)據(jù)盡可能得在接收端得承載能力之內(nèi),而其實(shí)現(xiàn)得方式就是接收端向發(fā)送端告知自己能夠接收的數(shù)據(jù)大小,因此發(fā)送端每次發(fā)送的數(shù)據(jù)就都不會超過該值,我們稱該值為窗口大小
一旦接收端暫時無法接收任何數(shù)據(jù),它會告知發(fā)送端,因此發(fā)送端會暫停數(shù)據(jù)的發(fā)送,但為了后續(xù)數(shù)據(jù)的正常發(fā)送,發(fā)送端會不時地向接收端發(fā)送一個窗口探測,試探性地看一下接收端是否能繼續(xù)接收數(shù)據(jù)了
具體的過程如下圖所示

七、擁塞控制
因?yàn)槌霈F(xiàn)了窗口控制,數(shù)據(jù)不再是一段一段發(fā)送,而是連續(xù)發(fā)送多段數(shù)據(jù)包,因此有時如果遇到網(wǎng)絡(luò)擁堵的情況,而我們又同時發(fā)送了大量的數(shù)據(jù)包,可能會導(dǎo)致網(wǎng)絡(luò)癱瘓
TCP運(yùn)用了一種叫做慢啟動技巧緩解了上述情況,何為慢啟動呢?就是不要在一開始就瞬間發(fā)送大量數(shù)據(jù)包,而是先發(fā)送一部分,然后根據(jù)收發(fā)情況再發(fā)送更多的數(shù)據(jù)包
具體過程我們來看一下

如圖中,發(fā)送端的窗口大小為1000,因此只發(fā)送了一段長度為1000字節(jié)的數(shù)據(jù)包,此時接收端收到數(shù)據(jù)并返回一個確認(rèn)應(yīng)答,因此發(fā)送端將窗口大小加一,即窗口大小為2000 ;發(fā)送端又發(fā)送了兩段長度為1000的數(shù)據(jù)包,接收端收到數(shù)據(jù)并返回兩個確認(rèn)應(yīng)答,因此發(fā)送端將窗口大小加二,即窗口大小為4000 ;以此類推
總結(jié): 發(fā)送端每次發(fā)送的數(shù)據(jù)包會以1,2,4的指數(shù)型增長
但窗口大小也不會無限指數(shù)型增大,而是會在達(dá)到某個值時進(jìn)行一些調(diào)整,該值稱為慢啟動閾值