日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
你真的理解粘包與半包嗎?三分鐘搞懂它

通俗的例子

比如,平時(shí)我們要寄快遞,如果東西太大的話,那么就需要拆成幾個(gè)包裹來(lái)郵寄。

十余年的平遙網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整平遙建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“平遙網(wǎng)站設(shè)計(jì)”,“平遙網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

收件人僅收到個(gè)別包裹的時(shí)候,東西是不完整的,對(duì)應(yīng)到網(wǎng)絡(luò)傳輸中,這種情況就叫半包。

只有等接收到全部包裹時(shí),這個(gè)東西(傳輸?shù)男畔?才完整,所以半包情況下無(wú)法解析出完整的數(shù)據(jù),需要等,等接收到全部包裹。

那么問(wèn)題來(lái)了,如何知曉已經(jīng)收到全部包裹了呢?下文我們?cè)僮鞣治觥?/p>

再比如,快過(guò)年了,我打算給家里的親戚送點(diǎn)禮物,給每位長(zhǎng)輩送個(gè)手表,我們都知道手表的體積不大,并且我家里人都住在一個(gè)村,所以把給各長(zhǎng)輩的禮物打包在一個(gè)包裹里郵寄,這樣能節(jié)省運(yùn)費(fèi)。

這種把本應(yīng)該分多個(gè)包傳輸?shù)臄?shù)據(jù)合成一個(gè)包發(fā)送的情況,對(duì)應(yīng)到網(wǎng)絡(luò)傳輸中,就叫粘包。

看完這個(gè)例子之后,應(yīng)該對(duì)粘包與半包有點(diǎn)感覺(jué)了,接下來(lái)我們看下網(wǎng)絡(luò)中實(shí)際的情況。

實(shí)際情況

粘包與半包只有在 TCP 傳輸?shù)臅r(shí)候才會(huì)有,像 UDP 是不會(huì)有這種情況的,原因是因?yàn)?TCP 是面向流的,數(shù)據(jù)之間沒(méi)有界限的,而 UDP 是有的界限的。

如果熟悉 TCP 和 UDP 報(bào)文格式的同學(xué)肯定知道,TCP 的包沒(méi)有報(bào)文長(zhǎng)度,而 UDP 的包有報(bào)文長(zhǎng)度,這也說(shuō)明了 TCP 為什么是流式。

所以我為什么說(shuō)上面的例子不太恰當(dāng),因?yàn)楝F(xiàn)實(shí)生活中快遞的包裹之間其實(shí)是有界限的,TCP 則像流水,沒(méi)有明確的界限。

然后 TCP 有發(fā)送緩沖區(qū)的概念,UDP 實(shí)際上是沒(méi)這個(gè)概念。

假設(shè) TCP 一次傳輸?shù)臄?shù)據(jù)大小超過(guò)發(fā)送緩沖區(qū)大小,那么一個(gè)完整的報(bào)文就需要被拆分成兩個(gè)或更多的小報(bào)文,這可能會(huì)產(chǎn)生半包的情況,當(dāng)接收端收到不完整的數(shù)據(jù),是無(wú)法解析成功的。

如果 TCP 一次傳輸?shù)臄?shù)據(jù)大小小于發(fā)送緩沖區(qū),那么可能會(huì)跟別的報(bào)文合并起來(lái)一塊發(fā)送,這就是粘包。

此時(shí)接收端也無(wú)法正常解析報(bào)文,需要將其拆成多個(gè)正確的報(bào)文,才能正常解析。

關(guān)于粘包與半包,我還看到有拿 MTU (最大傳輸單元)說(shuō)事的,如果發(fā)送的數(shù)據(jù)大于 MTU 那就會(huì)出現(xiàn)拆包,導(dǎo)致半包的情況。

我個(gè)人覺(jué)得這里有點(diǎn)不對(duì),簡(jiǎn)單理解下,UDP 也是要遵循 MTU 的呀,對(duì)吧?那它咋不會(huì)發(fā)生半包呢?

我們接著來(lái)看如何解決粘包與半包。

那如何解決粘包與半包問(wèn)題呢?

  • 粘包:這個(gè)思路其實(shí)很清晰,就是把它拆開(kāi)唄,具體就是看怎么拆了,比如我們可以固定長(zhǎng)度,我們規(guī)定每個(gè)包都是10個(gè)字節(jié),那么就10個(gè)字節(jié)切一刀,這樣拆開(kāi)解析就 ok 了。
  • 半包:半包其實(shí)就是信息還不完整,我們需要等接收到全部的信息之后再作處理,當(dāng)我們識(shí)別這是一個(gè)不完整的包時(shí)候,我們先 hold 住,不作處理,等待數(shù)據(jù)完整再處理。這里關(guān)鍵點(diǎn)在于,我們?nèi)绾尾拍苤来藭r(shí)完整了?上面說(shuō)的固定長(zhǎng)度其實(shí)也是一點(diǎn),當(dāng)然還有更多更好的解決方案,我們接著往下看。

實(shí)際常見(jiàn)解決粘包與半包問(wèn)題有三個(gè)方案:

  • 固定長(zhǎng)度
  • 分隔符
  • 固定長(zhǎng)度字段+內(nèi)容

為了說(shuō)明方便,以下沒(méi)有按二進(jìn)制的位等單位來(lái)描述。

固定長(zhǎng)度

這個(gè)其實(shí)很簡(jiǎn)單,比如現(xiàn)在要傳輸 ABC、EF 這兩個(gè)包,如果不做處理接收端很可能收到的是 AB、CEF 或者 ABCE、F 等等。

這時(shí)候我們固定長(zhǎng)度,我們規(guī)定每個(gè)報(bào)文長(zhǎng)度都是 3,如果一個(gè)報(bào)文實(shí)際數(shù)據(jù)不足 3,那么就用空字符填充一下 。

所以我們發(fā)送的報(bào)文是 :

接收到的情況可能是:

但我們是按照 3 位來(lái)處理的,所以一次只會(huì)按照 3 位來(lái)解析,所以第一次雖然收到的數(shù)據(jù)是 ABCE,但我們就解析 3 位,即解析出 ABC,留著了個(gè) E,等我們要繼續(xù)解析 3 位的時(shí)候,發(fā)現(xiàn)長(zhǎng)度不足 3,所以我們暫時(shí)先不管,先等等。

后面等到了 F“”,我們發(fā)現(xiàn)當(dāng)下數(shù)據(jù)又滿足 3 位了,所以我們接著解析 EF“” 。

這樣就解決了粘包與半包問(wèn)題。

對(duì)應(yīng)到 Netty 中的實(shí)現(xiàn)就是 FixedLengthFrameDecoder,這個(gè)類來(lái)實(shí)現(xiàn)固定長(zhǎng)度的解碼。

核心邏輯就是我上面說(shuō)的,我們來(lái)看下源碼,很簡(jiǎn)單:

固定長(zhǎng)度的優(yōu)點(diǎn):簡(jiǎn)單。

缺點(diǎn):固定長(zhǎng)度很僵硬,不易于擴(kuò)展,且如果設(shè)置過(guò)大來(lái)滿足業(yè)務(wù)場(chǎng)景的話,會(huì)導(dǎo)致空間浪費(fèi),因?yàn)椴蛔汩L(zhǎng)度的需要填充。

分隔符

這個(gè)應(yīng)該很好理解, 還是拿 ABC、EF 這兩個(gè)包舉例,我在寫完 ABC后,插入一個(gè)分號(hào),組成ABC;,EF 同理:

這樣以分隔符為界限來(lái)切分無(wú)界限的 TCP 流,來(lái)解決粘包與半包問(wèn)題,這個(gè)應(yīng)該很好理解,既然你 TCP 沒(méi)界限,我業(yè)務(wù)上給你搞個(gè)界限。

對(duì)應(yīng)到 Netty 中的實(shí)現(xiàn)就是 DelimiterBasedFrameDecoder,具體源碼就不貼了,有點(diǎn)長(zhǎng),不過(guò)道理還是簡(jiǎn)單的。

一直解析,等識(shí)別到分隔符之后,說(shuō)明前面的數(shù)據(jù)完整了,于是解析前面的數(shù)據(jù),然后繼續(xù)往后掃描解析。

分隔符的優(yōu)點(diǎn):簡(jiǎn)單,也不會(huì)浪費(fèi)空間。

缺點(diǎn):需要對(duì)內(nèi)容本身進(jìn)行處理,防止內(nèi)容內(nèi)出現(xiàn)分隔符,這樣就會(huì)導(dǎo)致錯(cuò)亂,所以需要掃描一遍傳輸?shù)臄?shù)據(jù)將其轉(zhuǎn)義,或者可以用 base64 編碼數(shù)據(jù),用 64 個(gè)之外的字符作為分隔符即可。

分隔符的處理方式在業(yè)界也是常用的,比如 Redis 就用換行符來(lái)分隔。

固定長(zhǎng)度字段+內(nèi)容

這個(gè)也很好理解,比如協(xié)議規(guī)定固定 4 位存放內(nèi)容的長(zhǎng)度,這樣內(nèi)容就可以伸縮:

還是拿 ABC、EF 這兩個(gè)包舉例:

解析流程是:先獲取 4 位,如果當(dāng)前收到的數(shù)據(jù)不夠 4 位,那就再等等,夠 4 位之后解析得到長(zhǎng)度是 3,所以我再往后取 3 位,同樣數(shù)據(jù)如果不夠 3 位就再等等,夠了的話就解析,這樣就獲取一個(gè)完整的包了。

然后接著往后獲取 4 位,解析得到 2,同理根據(jù) 2 往后再取 2 位,解析得到 EF。

這種方式就是先解析固定長(zhǎng)度的字段,獲得后面內(nèi)容的長(zhǎng)度,根據(jù)內(nèi)容長(zhǎng)度來(lái)獲取內(nèi)容,從而得到一個(gè)完整的報(bào)文。

對(duì)應(yīng)到 Netty 中的實(shí)現(xiàn)就是 LengthFieldBasedFrameDecoder,具體源碼就不貼了,有點(diǎn)長(zhǎng),

固定長(zhǎng)度字段+內(nèi)容的優(yōu)點(diǎn):可以根據(jù)固定字段精準(zhǔn)定位,也不用掃描轉(zhuǎn)義字符。

缺點(diǎn):固定長(zhǎng)度字段的設(shè)計(jì)比較困難,大了浪費(fèi)空間,畢竟每個(gè)報(bào)文都帶這個(gè)長(zhǎng)度,小了可能不夠用。

總結(jié)

好了,我們總結(jié)一下。

因?yàn)?TCP 是面向流的協(xié)議,且利用緩沖區(qū)來(lái)提高發(fā)送的效率,所以會(huì)導(dǎo)致粘包/半包情況的發(fā)生。

對(duì)于這種情況,我們可以在報(bào)文上動(dòng)手腳,可以約定固定長(zhǎng)度的報(bào)文,或埋入分隔符,或利用固定長(zhǎng)度字段+內(nèi)容等常見(jiàn)的三種方式來(lái)解決粘包、半包的問(wèn)題。

以上三種在 Netty 中都有現(xiàn)成實(shí)現(xiàn)類,可直接使用:

FixedLengthFrameDecoder,固定長(zhǎng)度

DelimiterBasedFrameDecoder,分隔符

LengthFieldBasedFrameDecoder,定長(zhǎng)度字段+內(nèi)容

建議實(shí)驗(yàn)一下,會(huì)有更清晰的認(rèn)識(shí)。


本文題目:你真的理解粘包與半包嗎?三分鐘搞懂它
分享地址:http://www.5511xx.com/article/dhejesc.html