本文是參考【圖解TCP/IP】
TCP(Transmission Control Protocol)是傳輸控制協議,其作用于傳輸層,是一種提供了面向連接通信服務的協議
看TCP的英文全稱就知道,其主要作用就是傳輸 、控制,傳輸的是資料,控制的是在傳輸程序中丟包后的重發 、分包亂序后的有序重組 、控制資料傳輸的速率防止網路擁塞等
這也是我們口中一直說的TCP是一種可靠的傳輸協議的原因,本文就將對TCP的作用程序以及一些機制進行講解
- 公眾號:前端印象
- 不定時有送書活動,記得關注~
- 關注后回復對應文字領取:【面試題】、【前端必看電子書】、【資料結構與演算法完整代碼】、【前端技術交流群】
TCP的通信機制
- 一、TCP連接管理
- 二、分段資料發送
- 三、重發控制
- 四、滑動視窗控制
- 五、滑動視窗的重發控制
- 六、流控制
- 七、擁塞控制
- 八、結束語
一、TCP連接管理
TCP是面向連接進行通信服務的協議,所謂連接,其實就是在兩臺需要資料互動的主機之間建立一條虛擬的線路,所有的資料互動都是通過這條線路進行的,而TCP就負責這整個線路的創建、銷毀、維護管理等作業
在建立連接之前,需要做一些準備,為了確保通信兩端是否可以進行正常通信,發送端會通過TCP的首部發送一個SYN包作為建立連接的請求并等待接收端確認應答,如果接收端確認應答并回傳一個ACK包,則表示接收端同意與發送端進行通信,然后發送端再次發送一個ACK包給接收端,表示已收到你的同意通信的訊息了,此后兩端就可以正常通信了;若接收端沒有回傳給發送端一個確認應答的ACK包,則表示不同意與發送端進行通信,那么兩端自然無法進行后續的通信了
兩端若在通信完成以后肯定需要斷開通信,同樣也需要兩端互發包來確認是否要斷開通信,比如,發送端先發送一個FIN包給接收端,告知想要斷開連接,然后接收端可以回傳給發送端一個ACK包表示同意你斷開連接的請求,緊接著接收端也向發送端發送了一個FIN包,表示其也想斷開連接的意愿,發送端在接收到該包后隨即回傳給接收端一個ACK包表示我也同意你斷開連接,這樣,兩端就斷開連接了
總結一下,一次完整的TCP連接的建立與斷開至少需要來回發送7個包,其中建立連接需要發3個包,斷開連接需要發4個包
我們來看一下完整的通信程序簡圖

這就是大家常說的三次握手,四次揮手的程序
如果不好理解上面的建立、斷開連接程序,這里我再給大家舉一個小小的例子
發送端與接收端通信,就好比我們日常生活中兩個人打電話,例如現在A給B打電話
- A問B:喂?你是B嗎?
- B回答A:我是B呀,你是A嗎?
- A回答B:對的,我是A
就這樣一個簡單的三次對話就確認了雙方是想要互相通信的物件,因此連接就此建立了
那么當A和B聊完天,準備掛電話了
- A對B說:我的事說完了,那么沒啥事我就掛電話了哈
- B回答A:好的
- B又對A補充了一句:我也沒啥事了,那我也掛了哈
- A回答B:好的
這三段對話就使通信雙方確認了會話結束,因此連接就此斷開了
二、分段資料發送
TCP不是拿到一整個包就直接原封不動地傳給接收端的,因為若這樣做,即使是發生了資料丟失,也不知道到底丟失了哪部分的資料,因此其采用的就是將資料分段發送的方式
這里先說明一點,不光建立和斷開連接時接收端需要向發送端發送請求應答,在資料互動時也是需要的
例如有一個資料包,我們可以將其按順序給每一個位元組都標上一個序號,然后我們假設每次發送1000個序號區間的資料給接收端,所以第一次發送的是 序號 1 ~ 1000 的資料,接收端接收到了以后會回傳給發送端一個請求應答,告知發送端下一次請發送 序號 1001 ~ 2000 的資料過來,程序如圖所示

上面我們假設的是每次發送1000個序列號區間的單位,而實際程序中,卻不一定是這個值,
在前面的學習中,我們得知資料在資料鏈路層中傳輸會收到MTU(最大傳輸單元)的影響,若資料大于該值,IP則會被分片處理,因此我們盡可能地不讓這種事情發生,那么就要讓傳輸的每段資料大小小于該通信線路上最小的MTU,該值稱為MSS(最大訊息長度)
該值是會在建立連接的三次握手時被計算獲得的,比如發送端在請求接收端的時候,在發送的包上附帶上其線路上的MTU大小為4000,然后接收端在發送確認應答給發送端時,也會在包上附帶上其線路上的MTU大小為1460,此時發送端接收到確認應答后比較兩個MTU的大小,取其中小的那個值作為之后資料傳輸每段的資料大小
如圖:

三、重發控制
我們都知道,在資料傳輸程序中可能會因為各種原因出現丟包現象,而當出現丟包現象時,即發送端在發完資料以后等待一段時間,并未收到接收端的確認應答,則視為丟包,于是就會進行重發
其中丟包現象又分為兩種:
- 發送端向接收端發送資料的程序中,發生了丟包現象,接收端并未接收到資料,因此不會給發送端發送確認應答
- 接收端收到了發送端傳過來的資料,并且也向發送端回傳了確認應答,但確認應答的包卻在發送的途中出現了丟包,所以發送端接收不到確認應答
以上兩種情況如下圖所示:
第一種情況:

第二種情況:

那么,發送端發送完資料后多久沒收到確認應答才判定資料丟包了呢?這個都是隨著網路環境的變化而變化的,TCP會在每次發包時計算往返時間以及偏差來決定等待的時間
若重發后又出現了丟包,則下一次等待的時間會以2倍、4倍的指數函式延長
但其又不會無限進行重發,當重發次數達到一定程度后,會判定為網路例外,兩端通信就會被強制關閉
四、滑動視窗控制
上面介紹了TCP將資料分段發送,雖然提高了傳輸的可靠性,但是存在著一個致命的缺點,那就是效率非常低,因為每送一段都要等待接收端的確認應答,若整個資料的分段較多,那么通信的性能可能就會很低了,因此TCP引入了視窗這個概念
所謂視窗,表示的是無需等待確認應答而可以連續發送的連續多段資料的區域,如圖

我們假設每段資料長度為1000,這里的視窗大小為4段,因此發送端可以將這四段資料都分別發送出去并且不需要發送一段資料以后等待一個確認應答,如圖

此時的視窗包含4個段,即視窗內包含4000個位元組的資料,我們稱之為視窗大小
接收端在回傳相應的確認應答給發送端時,發送端會根據收到的確認應答,繼續發送比該確認應答中序列號大4000的資料,如圖所示

五、滑動視窗的重發控制
若使用了滑動視窗控制這一技術后,即使某段資料出現了丟包現象,也不會造成太大的影響,因為接收端會一邊接收發送端傳過來的資料,一邊用某種方式告知發送端剛才丟失了哪段資料
接下來我們來介紹一下其作用程序,如圖所示

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

七、擁塞控制
因為出現了視窗控制,資料不再是一段一段發送,而是連續發送多段資料包,因此有時如果遇到網路擁堵的情況,而我們又同時發送了大量的資料包,可能會導致網路癱瘓
TCP運用了一種叫做慢啟動技巧緩解了上述情況,何為慢啟動呢?就是不要在一開始就瞬間發送大量資料包,而是先發送一部分,然后根據收發情況再發送更多的資料包
具體程序我們來看一下

如圖中,發送端的視窗大小為1000,因此只發送了一段長度為1000位元組的資料包,此時接收端收到資料并回傳一個確認應答,因此發送端將視窗大小加一,即視窗大小為2000 ;發送端又發送了兩段長度為1000的資料包,接收端收到資料并回傳兩個確認應答,因此發送端將視窗大小加二,即視窗大小為4000 ;以此類推
總結: 發送端每次發送的資料包會以1,2,4的指數型增長
但視窗大小也不會無限指數型增大,而是會在達到某個值時進行一些調整,該值稱為慢啟動閾值
八、結束語
歡迎關注公眾號:前端印象 , 不定時更新前端面試題,與我一起學習前端,早日斬獲大廠Offer
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/204146.html
標籤:python
