今天我們將 從穩(wěn)定性角度深挖 TCP 協(xié)議的運(yùn)作機(jī)制 。
如今,大半個(gè)互聯(lián)網(wǎng)都建立在 TCP 協(xié)議之上,我們使用的 HTTP 協(xié)議、消息隊(duì)列、存儲(chǔ)、緩存,都需要用到 TCP 協(xié)議—— 這是因?yàn)?TCP 協(xié)議提供了可靠性 。
簡(jiǎn)單來說,可靠性就是讓數(shù)據(jù)無損送達(dá)。但若是考慮到成本,就會(huì)變得非常復(fù)雜——因?yàn)檫€需要盡可能地提升吞吐量、降低延遲、減少丟包率。
TCP 協(xié)議具有很強(qiáng)的實(shí)用性,而可靠性又是 TCP 最核心的能力 。具體來說,從一個(gè)終端有序地發(fā)出多個(gè)數(shù)據(jù)包,經(jīng)過一個(gè)復(fù)雜的網(wǎng)絡(luò)環(huán)境,到達(dá)目的地的時(shí)候會(huì)變得無序,而可靠性要求數(shù)據(jù)恢復(fù)到原始的順序。這里先提出兩個(gè)問題:
- TCP 協(xié)議是如何恢復(fù)數(shù)據(jù)的順序的?
- 拆包和粘包的作用是什么?
那么帶著這兩個(gè)問題開始今天的學(xué)習(xí)。
TCP 的拆包和粘包
TCP數(shù)據(jù)發(fā)送
TCP 是一個(gè)傳輸層協(xié)議
TCP 發(fā)送數(shù)據(jù)的時(shí)候,往往不會(huì)將數(shù)據(jù)一次性發(fā)送
而是將數(shù)據(jù)拆分成很多個(gè)部分,然后再逐個(gè)發(fā)送。像下圖這樣:
同樣的,在目的地,TCP 協(xié)議又需要逐個(gè)接收數(shù)據(jù)。
請(qǐng) 思考,TCP 為什么不一次發(fā)送完所有的數(shù)據(jù)?比如我們要傳一個(gè)大小為 10M 的文件,對(duì)于應(yīng)用層而言,就是一次傳送完成的。而傳輸層的協(xié)議為什么不選擇將這個(gè)文件一次發(fā)送完呢?
這里有很多原因,
- 比如為了穩(wěn)定性,一次發(fā)送的數(shù)據(jù)越多,出錯(cuò)的概率越大。
- 再比如說為了效率,網(wǎng)絡(luò)中有時(shí)候存在著并行的路徑,拆分?jǐn)?shù)據(jù)包就能更好地利用這些并行的路徑。
- 再有,比如發(fā)送和接收數(shù)據(jù)的時(shí)候,都存在著緩沖區(qū)。如下圖所示:
緩沖區(qū)是在內(nèi)存中開辟的一塊區(qū)域,目的是緩沖。因?yàn)榇罅康膽?yīng)用頻繁地通過網(wǎng)卡收發(fā)數(shù)據(jù),這個(gè)時(shí)候,網(wǎng)卡只能一個(gè)一個(gè)處理應(yīng)用的請(qǐng)求。當(dāng)網(wǎng)卡忙不過來的時(shí)候,數(shù)據(jù)就需要排隊(duì),也就是將數(shù)據(jù)放入緩沖區(qū) 。如果每個(gè)應(yīng)用都隨意發(fā)送很大的數(shù)據(jù),可能導(dǎo)致其他應(yīng)用實(shí)時(shí)性遭到破壞。
還有一些原因 比如內(nèi)存的最小分配單位是頁表,如果數(shù)據(jù)的大小超過一個(gè)頁表,可能會(huì)存在頁面置換問題,造成性能的損失。
總之,方方面面的原因: 在傳輸層封包不能太大 。
這種限制,往往是以緩沖區(qū)大小為單位的。也就是 TCP 協(xié)議,會(huì)將數(shù)據(jù)拆分成不超過緩沖區(qū)大小的一個(gè)個(gè)部分 。每個(gè)部分有一個(gè)獨(dú)特的名詞,叫作 TCP 段(TCP Segment) 。
在接收數(shù)據(jù)的時(shí)候,一個(gè)個(gè) TCP 段又被重組成原來的數(shù)據(jù)。
像這樣, 數(shù)據(jù)經(jīng)過拆分,然后傳輸,然后在目的地重組,俗稱拆包 。所以拆包是將數(shù)據(jù)拆分成多個(gè) TCP 段傳輸。
那么粘包是什么呢?有時(shí)候, 如果發(fā)往一個(gè)目的地的多個(gè)數(shù)據(jù)太小了,為了防止多次發(fā)送占用資源,TCP 協(xié)議有可能將它們合并成一個(gè) TCP 段發(fā)送,在目的地再還原成多個(gè)數(shù)據(jù),這個(gè)過程俗稱粘包。所以粘包是將多個(gè)數(shù)據(jù)合并成一個(gè) TCP 段發(fā)送 。
TCP Segment
那么一個(gè) TCP 段長(zhǎng)什么樣子呢?下圖是一個(gè) TCP 段的格式:
我們可以看到,TCP 的很多配置選項(xiàng)和數(shù)據(jù)粘在了一起,作為一個(gè) TCP 段。
顯然, 把每一部分都記住似乎不太現(xiàn)實(shí),先把其中最主要的部分理解。
TCP 協(xié)議就是依靠每一個(gè) TCP 段工作的,所以你每認(rèn)識(shí)一個(gè) TCP 的能力,幾乎都會(huì)找到在 TCP Segment 中與之對(duì)應(yīng)的字段 。接下來 認(rèn)識(shí)它們。
- Source Port/Destination Port 描述的是發(fā)送端口號(hào)和目標(biāo)端口號(hào),代表發(fā)送數(shù)據(jù)的應(yīng)用程序和接收數(shù)據(jù)的應(yīng)用程序。比如 80 往往代表 HTTP 服務(wù),22 往往是 SSH 服務(wù)……
- Sequence Number 和 Achnowledgment Number 是保證可靠性的兩個(gè)關(guān)鍵
- Data Offset 是一個(gè)偏移量。這個(gè)量存在的原因是 TCP Header 部分的長(zhǎng)度是可變的,因此需要一個(gè)數(shù)值來描述數(shù)據(jù)從哪個(gè)字節(jié)開始。
- Reserved 是很多協(xié)議設(shè)計(jì)會(huì)保留的一個(gè)區(qū)域,用于日后擴(kuò)展能力。
- URG/ACK/PSH/RST/SYN/FIN 是幾個(gè)標(biāo)志位,用于描述 TCP 段的行為。也就是一個(gè) TCP 封包到底是做什么用的
1)URG 代表這是一個(gè)緊急數(shù)據(jù),比如遠(yuǎn)程操作的時(shí)候,用戶按下了 Ctrl+C,要求終止程序,這種請(qǐng)求需要緊急處理。
2)ACK 代表響應(yīng), 所有的消息都必須有 ACK,這是 TCP 協(xié)議確保穩(wěn)定性的一環(huán)。
3)PSH 代表數(shù)據(jù)推送,也就是在傳輸數(shù)據(jù)的意思。
4)SYN 同步請(qǐng)求,也就是申請(qǐng)握手。
5)FIN 終止請(qǐng)求,也就是揮手。
特別說明一下:以上這 5 個(gè)標(biāo)志位,每個(gè)占了一個(gè)比特,可以混合使用。比如 ACK 和 SYN 同時(shí)為 1,代表同步請(qǐng)求和響應(yīng)被合并了。這也是 TCP 協(xié)議,為什么是三次握手的原因之一 。
- Window 也是 TCP 保證穩(wěn)定性并進(jìn)行流量控制的工具,后續(xù)會(huì) TCP 的穩(wěn)定性:滑動(dòng)窗口和流速控制是中詳細(xì)介紹。
- Checksum 是校驗(yàn)和,用于校驗(yàn) TCP 段有沒有損壞。
- Urgent Pointer 指向最后一個(gè)緊急數(shù)據(jù)的序號(hào)(Sequence Number)。它存在的原因是:有時(shí)候緊急數(shù)據(jù)是連續(xù)的很多個(gè)段,所以需要提前告訴接收方進(jìn)行準(zhǔn)備。
- Options 中存儲(chǔ)了一些可選字段,比如接下來我們要討論的 MSS(Maximun Segment Size)。
- Padding 存在的意義是因?yàn)?Options 的長(zhǎng)度不固定,需要 Pading 進(jìn)行對(duì)齊。
其實(shí)這個(gè)問題的本質(zhì)就好像兩個(gè)人在說話一樣,我們要確保他們說出去的話,和回答之間的順序。因?yàn)?TCP 是一個(gè)雙工的協(xié)議,兩邊可能會(huì)同時(shí)說話。所以聰明的 科學(xué)家想到了確定一句話的順序,需要兩個(gè)值去描述——也就是發(fā)送的字節(jié)數(shù)和接收的字節(jié)數(shù) 。
我們重新定義一下 Seq(如上圖所示),對(duì)于任何一個(gè)接收方,如果知道了發(fā)送者發(fā)送某個(gè) TCP 段時(shí),已經(jīng)發(fā)送了多少字節(jié)的數(shù)據(jù),那么就可以確定發(fā)送者發(fā)送數(shù)據(jù)的順序。
但是這里有一個(gè)問題。如果接收方也向發(fā)送者發(fā)送了數(shù)據(jù)請(qǐng)求(或者說雙方在對(duì)話),接收方就不知道發(fā)送者發(fā)送的數(shù)據(jù)到底對(duì)應(yīng)哪一條自己發(fā)送的數(shù)據(jù)了。
舉個(gè)例子:下面 A 和 B 的對(duì)話中,我們可以確定他們彼此之間接收數(shù)據(jù)的順序。但是無法確定數(shù)據(jù)之間的關(guān)聯(lián)關(guān)系,所以只有 Sequence Number 是不夠的。
A:今天天氣好嗎?
A:今天你開心嗎?
B:開心
B:天氣不好
人類很容易理解這幾句話的順序,但是對(duì)于機(jī)器來說就需要特別的標(biāo)注。因此我們還需要另一個(gè)數(shù)據(jù),就是每個(gè) TCP 段發(fā)送時(shí),發(fā)送方已經(jīng)接收了多少數(shù)據(jù)。用 Acknowledgement Number 表示,下面簡(jiǎn)寫為 ACK。
下圖中,終端發(fā)送了三條數(shù)據(jù),并且接收到四條數(shù)據(jù),通過觀察,根據(jù)接收到的數(shù)據(jù)中的 Seq 和 ACK,將發(fā)送和接收的數(shù)據(jù)進(jìn)行排序。
例如上圖中, **發(fā)送方發(fā)送了 100 字節(jié)的數(shù)據(jù),而接收到的(Seq = 0 和 Seq =100)的兩個(gè)封包,都是針對(duì)發(fā)送方(Seq = 0)這個(gè)封包的。發(fā)送 100 個(gè)字節(jié),所以接收到的 ACK 剛好是 100。說明(Seq= 0 和 Seq= 100)這兩個(gè)封包是針對(duì)接收到第 100 個(gè)字節(jié)數(shù)據(jù)后,發(fā)送回來的。這樣就確定了整體的順序** 。
注意,無論 Seq 還是 ACK,都是針對(duì)“對(duì)方”而言的。是對(duì)方發(fā)送的數(shù)據(jù)和對(duì)方接收到的數(shù)據(jù) 。我們?cè)趯?shí)際的工作當(dāng)中,可以通過 Whireshark 調(diào)試工具觀察兩個(gè) TCP 連接的 Seq和 ACK。
MSS(Maximun Segment Size)
接下來,我們討論下 MSS,它也是面試經(jīng)常會(huì)問到的一個(gè) TCP Header 中的可選項(xiàng)(Options), 這個(gè)可選項(xiàng)控制了 TCP 段的大小,它是一個(gè)協(xié)商字段(Negotiate) 。協(xié)議是雙方都要遵循的標(biāo)準(zhǔn),因此配置往往不能由單方?jīng)Q定,需要雙方協(xié)商。
TCP 段的大小(MSS)涉及發(fā)送、接收緩沖區(qū)的大小設(shè)置,雙方實(shí)際發(fā)送接收封包的大小,對(duì)拆包和粘包的過程有指導(dǎo)作用,因此需要雙方去協(xié)商 。
如果這個(gè)字段設(shè)置得非常大,就會(huì)帶來一些影響。
- 首先對(duì)方可能會(huì)拒絕,作為服務(wù)的提供方,你可能不會(huì)愿意接收太大的 TCP 段。因?yàn)榇蟮?TCP 段,會(huì)降低性能,比如內(nèi)存使用的性能 。還有就是資源的占用。一個(gè)用戶占用服務(wù)器太多的資源,意味著其他的用戶就需要等待或者降低他們的服務(wù)質(zhì)量
- 其次,支持 TCP 協(xié)議工作的 IP 協(xié)議,工作效率會(huì)下降
TCP 協(xié)議不肯拆包,IP 協(xié)議就需要拆出大量的包。那么 IP 協(xié)議為什么需要拆包呢?這是因?yàn)樵诰W(wǎng)絡(luò)中,每次能夠傳輸?shù)臄?shù)據(jù)不可能太大,這受限于具體的網(wǎng)絡(luò)傳輸設(shè)備,也就是物理特性。但是 IP 協(xié)議,拆分太多的封包并沒有意義。因?yàn)榭赡軙?huì)導(dǎo)致屬于同個(gè) TCP 段的封包被不同的網(wǎng)絡(luò)路線傳輸,這會(huì)加大延遲。同時(shí),拆包,還需要消耗硬件和計(jì)算資源。
那是不是 MSS 越小越好呢? MSS 太小的情況下,會(huì)浪費(fèi)傳輸資源(降低吞吐量)。因?yàn)閿?shù)據(jù)被拆分之后,每一份數(shù)據(jù)都要增加一個(gè)頭部。如果 MSS 太小,那頭部的數(shù)據(jù)占比會(huì)上升,這讓吞吐量成為一個(gè)災(zāi)難。所以在使用的過程當(dāng)中,MSS 的配置,往往都是一個(gè)折中的方案 。
不要去猜想什么樣的方案是最合理的,而是要嘗試去用實(shí)驗(yàn)證明它,一切都要用實(shí)驗(yàn)依據(jù)說話。
Question : TCP 協(xié)議是如何恢復(fù)數(shù)據(jù)的順序的,TCP 拆包和粘包的作用是什么?
Answer:
TCP 拆包的作用是將任務(wù)拆分處理,降低整體任務(wù)出錯(cuò)的概率,以及減小底層網(wǎng)絡(luò)處理的壓力。拆包過程需要保證數(shù)據(jù)經(jīng)過網(wǎng)絡(luò)的傳輸,又能恢復(fù)到原始的順序。這中間,需要數(shù)學(xué)提供保證順序的理論依據(jù)。 TCP 利用(發(fā)送字節(jié)數(shù)、接收字節(jié)數(shù))的唯一性來確定封包之間的順序關(guān)系 。
粘包是為了防止數(shù)據(jù)量過小,導(dǎo)致大量的傳輸,而將多個(gè) TCP 段合并成一個(gè)發(fā)送。
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7139瀏覽量
89576 -
端口
+關(guān)注
關(guān)注
4文章
990瀏覽量
32208 -
應(yīng)用程序
+關(guān)注
關(guān)注
38文章
3292瀏覽量
57912 -
TCP協(xié)議
+關(guān)注
關(guān)注
1文章
101瀏覽量
12121
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
LwIP中TCP協(xié)議是如何實(shí)現(xiàn)的
TCP運(yùn)輸層協(xié)議的超時(shí)重傳原理實(shí)現(xiàn)
TCP/IP協(xié)議簡(jiǎn)介
![<b class='flag-5'>TCP</b>/IP<b class='flag-5'>協(xié)議</b>簡(jiǎn)介](https://file1.elecfans.com//web2/M00/A5/00/wKgZomUMNoKALGd3AABbAYwWMSM793.jpg)
TCP/IP協(xié)議,TCP/IP協(xié)議內(nèi)容和作用是什么?
NetBEUI和,IPX/SPX ,TCP/IP三大協(xié)議
tcp ip協(xié)議_什么是tcp ip協(xié)議
![<b class='flag-5'>tcp</b> ip<b class='flag-5'>協(xié)議</b>_什么是<b class='flag-5'>tcp</b> ip<b class='flag-5'>協(xié)議</b>](https://file.elecfans.com/web1/M00/EB/A0/pIYBAGB86e2AA8i5AADGujP1HUI639.jpg)
評(píng)論