自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一分鐘看懂TCP粘包拆包

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
TCP 是一個(gè)面向「流」的協(xié)議,所謂流就是沒有界限的一長串二進(jìn)制數(shù)據(jù)。在實(shí)際的傳輸過程中,TCP 會根據(jù)網(wǎng)絡(luò)情況將數(shù)據(jù)包進(jìn)行拆分或者拼裝,如果業(yè)務(wù)沒有定義一個(gè)明確的界限規(guī)則,在應(yīng)用層的業(yè)務(wù)上就會出現(xiàn)粘包拆包的現(xiàn)象。

平時(shí)大家在網(wǎng)絡(luò)編程過程中可能會遇到這樣一種現(xiàn)象:客戶端發(fā)送了一長串消息,服務(wù)端接受的消息揉在一起或者被拆分了,這樣就會造成消息難以被正確理解。

比如說有一天你特別想喝奶茶,看了一下外賣,「一點(diǎn)點(diǎn)」的奶茶看著不錯(cuò),(一點(diǎn)點(diǎn)趕緊給我打錢 doge),于是你在群里發(fā)了一條消息,想找?guī)讉€(gè)人拼奶茶:

一點(diǎn)點(diǎn)奶茶有人喝嗎?

結(jié)果群里同事回了一句:

現(xiàn)在不是已經(jīng)三點(diǎn)了嗎?

你覺得莫名其妙,看了一眼同事的手機(jī),他收到的消息是這樣的兩行:

一點(diǎn)

點(diǎn)奶茶有人喝嗎?

哈哈,講了一個(gè)冷笑話。用專業(yè)的術(shù)語來說這種現(xiàn)象就是「拆包」了,我們接著往下講。

TCP 粘包拆包的現(xiàn)象

粘包拆包問題一般是處于應(yīng)用層下的問題,在數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層以及傳輸層都有可能發(fā)生。我們?nèi)粘5木W(wǎng)絡(luò)應(yīng)用開發(fā)大多都在傳輸層進(jìn)行,因此本文著重講解傳輸層粘包拆包問題。

傳輸層有兩個(gè)協(xié)議我們都很熟悉:UDP 和 TCP,UDP有消息保護(hù)邊界,不會發(fā)生粘包拆包問題,因此粘包拆包問題只發(fā)生在TCP協(xié)議中。

下面用一個(gè)簡單的例子來講解什么是粘包和拆包。

假設(shè)客戶端向服務(wù)端連續(xù)發(fā)送了兩個(gè)數(shù)據(jù)包,用 packet1 和 packet2 來表示,那么服務(wù)端收到的數(shù)據(jù)可能有四種:

(1)第一種情況,服務(wù)端按順序正常收到兩個(gè)包,即未出現(xiàn)粘包和拆包的現(xiàn)象。

(2)第二種情況,服務(wù)端只收到一個(gè)數(shù)據(jù)包,由于 TCP 保證送達(dá)的特性,所以這一個(gè)數(shù)據(jù)包包含了客戶端發(fā)送的兩個(gè)數(shù)據(jù)包的信息,這種現(xiàn)象就是粘包。除非客戶端發(fā)送的數(shù)據(jù)包有明確的規(guī)則,否則服務(wù)端不知道兩個(gè)包的界限,難以處理數(shù)據(jù)。

(3)第三種情況,服務(wù)端收到了三個(gè)數(shù)據(jù)包,Package1數(shù)據(jù)包被拆分為兩個(gè)數(shù)據(jù)包:Package1.1和Package1.2,這種現(xiàn)象就是拆包,至于拆包的原因下面會講,服務(wù)端收到拆開的數(shù)據(jù)包也很難處理。

(4)第四種情況,一些大的數(shù)據(jù)包被拆分為小的數(shù)據(jù)包,小的數(shù)據(jù)包與其他數(shù)據(jù)包粘在一起,這種現(xiàn)象是將上面的粘包和拆包綜合在一塊。

TCP 粘包拆包的原因

TCP 是一個(gè)面向「流」的協(xié)議,所謂流就是沒有界限的一長串二進(jìn)制數(shù)據(jù)。TCP 作為傳輸層協(xié)議并不了解上層業(yè)務(wù)數(shù)據(jù)的具體含義,它會根據(jù)TCP緩沖區(qū)的實(shí)際情況進(jìn)行數(shù)據(jù)包的劃分,所以在業(yè)務(wù)上認(rèn)為是一個(gè)完整的包,可能會被 TCP 拆分成多個(gè)包進(jìn)行發(fā)送,也有可能把多個(gè)小的包封裝成一個(gè)大的數(shù)據(jù)包發(fā)送,這就會出現(xiàn)粘包拆包的問題。

例如,TCP緩沖區(qū)是1024個(gè)字節(jié)大小,如果應(yīng)用一次請求發(fā)送的數(shù)據(jù)量比較小,沒達(dá)到緩沖區(qū)大小,TCP則會將多個(gè)請求合并為同一個(gè)請求進(jìn)行發(fā)送,站在業(yè)務(wù)上來看這就是「粘包」;

如果應(yīng)用一次請求發(fā)送的數(shù)據(jù)量比較大,超過了緩沖區(qū)大小,TCP就會將其拆分為多次發(fā)送,這就是「拆包」,也就是將一個(gè)大的包拆分為多個(gè)小包進(jìn)行發(fā)送。

TCP 粘包拆包的解決方法

TCP 是面向流的,會發(fā)生粘包和拆包,那作為應(yīng)用程序,如何從這源源不斷涌來的數(shù)據(jù)流中拆分出或者合并出有意義的信息呢?通常會有以下一些常用的方法:

(1)發(fā)送端給每個(gè)數(shù)據(jù)包添加包首部,首部中應(yīng)該至少包含數(shù)據(jù)包的長度,這樣接收端在接收到數(shù)據(jù)后,通過讀取包首部的長度字段,便知道每一個(gè)數(shù)據(jù)包的實(shí)際長度了。

如下圖,在每個(gè)包前面加上包的實(shí)際長度。

(2)發(fā)送端將每個(gè)數(shù)據(jù)包封裝為固定長度(不夠的可以通過補(bǔ)0填充),這樣接收端每次從接收緩沖區(qū)中讀取固定長度的數(shù)據(jù)就自然而然的把每個(gè)數(shù)據(jù)包拆分開來。

下圖每個(gè)包的固定長度為 4,接收端很容易進(jìn)行區(qū)分。

(3)可以在數(shù)據(jù)包之間設(shè)置邊界,如添加特殊符號,這樣,接收端通過這個(gè)邊界就可以將不同的數(shù)據(jù)包拆分開。

如下圖,在每個(gè)包的后面加上特殊字符:/

Netty 框架如何解決粘包拆包問題

Netty 作為一款高性能的 Java 網(wǎng)絡(luò)編程框架,不僅是基于 Java NIO 進(jìn)行了深度封裝,還在客戶端與服務(wù)端之間的數(shù)據(jù)傳輸上做了有效處理。

前面講過 TCP 傳輸會出現(xiàn)粘包和拆包的現(xiàn)象,Netty 針對這一點(diǎn)內(nèi)置了多款數(shù)據(jù)流編解碼器,客戶端服務(wù)端按照約定好的規(guī)則進(jìn)行數(shù)據(jù)傳輸即可解決這個(gè)問題。

Netty 提供了多款開箱即用的編解碼器:

(1)FixedLengthFrameDecoder 固定長度解碼器

(2)DelimiterBasedFrameDecoder 指定分隔符解碼器

(3)LengthFieldBasedFrameDecoder 基于數(shù)據(jù)包長度解碼器

(4)等等……這里不再列舉

小結(jié)

TCP 是一個(gè)面向「流」的協(xié)議,所謂流就是沒有界限的一長串二進(jìn)制數(shù)據(jù)。在實(shí)際的傳輸過程中,TCP 會根據(jù)網(wǎng)絡(luò)情況將數(shù)據(jù)包進(jìn)行拆分或者拼裝,如果業(yè)務(wù)沒有定義一個(gè)明確的界限規(guī)則,在應(yīng)用層的業(yè)務(wù)上就會出現(xiàn)粘包拆包的現(xiàn)象。

針對 TCP 粘包拆包的現(xiàn)象,常見的解決思路如下:

(1)發(fā)送端給每個(gè)數(shù)據(jù)包添加包首部。

(2)發(fā)送端將每個(gè)數(shù)據(jù)包封裝為固定長度。

(3)可以在數(shù)據(jù)包之間設(shè)置邊界。

為了解決粘包拆包,Netty 框架也提供了很多開箱即用的編解碼器,極大簡化網(wǎng)絡(luò)編程解決此類問題的難度。

責(zé)任編輯:武曉燕 來源: 愛笑的架構(gòu)師
相關(guān)推薦

2020-05-21 19:46:19

區(qū)塊鏈數(shù)字貨幣比特幣

2020-06-11 08:04:12

WDMDWDMMWDM

2021-08-06 08:50:45

加密貨幣比特幣區(qū)塊鏈

2020-10-13 14:55:31

云計(jì)算云安全技術(shù)

2023-06-12 07:18:26

CPU主頻高頻率

2024-12-19 11:00:00

TCP網(wǎng)絡(luò)通信粘包

2017-03-30 19:28:26

HBase分布式數(shù)據(jù)

2018-06-26 05:23:19

線程安全函數(shù)代碼

2017-07-06 08:12:02

索引查詢SQL

2022-07-18 06:16:07

單點(diǎn)登錄系統(tǒng)

2018-07-31 16:10:51

Redo Undo數(shù)據(jù)庫數(shù)據(jù)

2017-02-21 13:00:27

LoadAverage負(fù)載Load

2019-10-17 11:06:32

TCP粘包通信協(xié)議

2011-02-21 17:48:35

vsFTPd

2016-09-12 17:28:45

云存儲應(yīng)用軟件存儲設(shè)備

2018-12-12 22:51:24

Java包裝語言

2020-07-09 07:37:06

數(shù)據(jù)庫Redis工具

2020-07-17 07:44:25

云計(jì)算邊緣計(jì)算IT

2020-11-10 09:01:52

DPDK網(wǎng)絡(luò)監(jiān)控

2021-07-15 10:35:16

NettyTCPJava
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號