Netty——TCP粘包尸执、拆包

一新翎、TCP 粘包和拆包基本介紹

TCP是面向連接的,面向流的该默,提供高可靠性服務(wù)瞳氓。收發(fā)兩端(客戶端和服務(wù)器端)都要有一一成對(duì)的socket,因此权均,發(fā)送端為了將多個(gè)發(fā)給接收端的包顿膨,更有效的發(fā)給對(duì)方,使用了優(yōu)化方法(Nagle算法)叽赊,將多次間隔較小且數(shù)據(jù)量小的數(shù)據(jù)恋沃,合并成一個(gè)大的數(shù)據(jù)塊,然后進(jìn)行封包必指。這樣做雖然提高了效率囊咏,但是接收端就難于分辨出完整的數(shù)據(jù)包了,因?yàn)槊嫦蛄鞯耐ㄐ攀菬o(wú)消息保護(hù)邊界的塔橡。

由于TCP無(wú)消息保護(hù)邊界, 需要在接收端處理消息邊界問(wèn)題梅割,也就是我們所說(shuō)的粘包、拆包問(wèn)題葛家。

TCP粘包户辞、拆包圖解


假設(shè)客戶端分別發(fā)送了兩個(gè)數(shù)據(jù)包D1和D2給服務(wù)端,由于服務(wù)端一次讀取到字節(jié)數(shù)是不確定的癞谒,故可能存在以下四種情況:

  • 1底燎、服務(wù)端分兩次讀取到了兩個(gè)獨(dú)立的數(shù)據(jù)包刃榨,分別是D1和D2,沒(méi)有粘包和拆包双仍。
  • 2枢希、服務(wù)端一次接受到了兩個(gè)數(shù)據(jù)包,D1和D2粘合在一起朱沃,稱之為T(mén)CP粘包苞轿。
  • 3、服務(wù)端分兩次讀取到了數(shù)據(jù)包逗物,第一次讀取到了完整的D1包和D2包的部分內(nèi)容搬卒,第二次讀取到了D2包的剩余內(nèi)容,這稱之為T(mén)CP拆包敬察。
  • 4秀睛、服務(wù)端分兩次讀取到了數(shù)據(jù)包,第一次讀取到了D1包的部分內(nèi)容D1_1莲祸,第二次讀取到了D1包的剩余部分內(nèi)容D1_2和完整的D2包蹂安。

特別要注意的是,如果TCP的接受滑窗非常小锐帜,而數(shù)據(jù)包D1和D2比較大田盈,很有可能會(huì)發(fā)生第五種情況,即服務(wù)端分多次才能將D1和D2包完全接受缴阎,期間發(fā)生多次拆包允瞧。

二、 粘包蛮拔、拆包發(fā)生原因

產(chǎn)生原因主要有這3種:滑動(dòng)窗口述暂、MSS/MTU限制、Nagle算法

1建炫、滑動(dòng)窗口

TCP流量控制主要使用滑動(dòng)窗口協(xié)議畦韭,滑動(dòng)窗口是接受數(shù)據(jù)端使用的窗口大小,用來(lái)告訴發(fā)送端接收端的緩存大小肛跌,以此可以控制發(fā)送端發(fā)送數(shù)據(jù)的大小艺配,從而達(dá)到流量控制的目的。這個(gè)窗口大小就是我們一次傳輸幾個(gè)數(shù)據(jù)衍慎。對(duì)所有數(shù)據(jù)幀按順序賦予編號(hào)转唉,發(fā)送方在發(fā)送過(guò)程中始終保持著一個(gè)發(fā)送窗口,只有落在發(fā)送窗口內(nèi)的幀才允許被發(fā)送稳捆;同時(shí)接收方也維持著一個(gè)接收窗口赠法,只有落在接收窗口內(nèi)的幀才允許接收。這樣通過(guò)調(diào)整發(fā)送方窗口和接收方窗口的大小可以實(shí)現(xiàn)流量控制乔夯。

現(xiàn)在來(lái)看一下滑動(dòng)窗口是如何造成粘包砖织、拆包的原朝?

  • 粘包:假設(shè)發(fā)送方的每256 bytes表示一個(gè)完整的報(bào)文,接收方由于數(shù)據(jù)處理不及時(shí)镶苞,這256個(gè)字節(jié)的數(shù)據(jù)都會(huì)被緩存到SO_RCVBUF(接收緩存區(qū))中。如果接收方的SO_RCVBUF中緩存了多個(gè)報(bào)文鞠评,那么對(duì)于接收方而言茂蚓,這就是粘包。

  • 拆包:考慮另外一種情況剃幌,假設(shè)接收方的窗口只剩了128聋涨,意味著發(fā)送方最多還可以發(fā)送128字節(jié),而由于發(fā)送方的數(shù)據(jù)大小是256字節(jié)负乡,因此只能發(fā)送前128字節(jié)牍白,等到接收方ack后,才能發(fā)送剩余字節(jié)抖棘。這就造成了拆包茂腥。

2、MSS和MTU分片

MSS:是Maximum Segement Size縮寫(xiě)切省,表示TCP報(bào)文中data部分的最大長(zhǎng)度最岗,是TCP協(xié)議在OSI五層網(wǎng)絡(luò)模型中傳輸層對(duì)一次可以發(fā)送的最大數(shù)據(jù)的限制。

MTU:最大傳輸單元是Maxitum Transmission Unit的簡(jiǎn)寫(xiě)朝捆,是OSI五層網(wǎng)絡(luò)模型中鏈路層(datalink layer)對(duì)一次可以發(fā)送的最大數(shù)據(jù)的限制般渡。

當(dāng)需要傳輸?shù)臄?shù)據(jù)大于MSS或者M(jìn)TU時(shí),數(shù)據(jù)會(huì)被拆分成多個(gè)包進(jìn)行傳輸芙盘。由于MSS是根據(jù)MTU計(jì)算出來(lái)的驯用,因此當(dāng)發(fā)送的數(shù)據(jù)滿足MSS時(shí),必然滿足MTU儒老。

為了更好的理解蝴乔,我們先介紹一下在5層網(wǎng)絡(luò)模型中應(yīng)用通過(guò)TCP發(fā)送數(shù)據(jù)的流程:


  • 對(duì)于應(yīng)用層來(lái)說(shuō),只關(guān)心發(fā)送的數(shù)據(jù)DATA贷盲,將數(shù)據(jù)寫(xiě)入socket在內(nèi)核中的發(fā)送緩沖區(qū)SO_SNDBUF即返回淘这,操作系統(tǒng)會(huì)將SO_SNDBUF中的數(shù)據(jù)取出來(lái)進(jìn)行發(fā)送。

  • 傳輸層會(huì)在DATA前面加上TCP Header巩剖,構(gòu)成一個(gè)完整的TCP報(bào)文铝穷。

  • 當(dāng)數(shù)據(jù)到達(dá)網(wǎng)絡(luò)層(network layer)時(shí),網(wǎng)絡(luò)層會(huì)在TCP報(bào)文的基礎(chǔ)上再添加一個(gè)IP Header佳魔,也就是將自己的網(wǎng)絡(luò)地址加入到報(bào)文中曙聂。

  • 到數(shù)據(jù)鏈路層時(shí),還會(huì)加上Datalink Header和CRC鞠鲜。

  • 當(dāng)?shù)竭_(dá)物理層時(shí)宁脊,會(huì)將SMAC(Source Machine断国,數(shù)據(jù)發(fā)送方的MAC地址),DMAC(Destination Machine榆苞,數(shù)據(jù)接受方的MAC地址 )和Type域加入稳衬。

可以發(fā)現(xiàn)數(shù)據(jù)在發(fā)送前,每一層都會(huì)在上一層的基礎(chǔ)上增加一些內(nèi)容坐漏,下圖演示了MSS薄疚、MTU在這個(gè)過(guò)程中的作用。


MTU是以太網(wǎng)傳輸數(shù)據(jù)方面的限制赊琳,每個(gè)以太網(wǎng)幀都有最小的大小64bytes最大不能超過(guò)1518bytes街夭。刨去以太網(wǎng)幀的幀頭 (DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和幀尾 CRC校驗(yàn)部分4Bytes(這個(gè)部分有時(shí)候大家也把它叫做FCS),那么剩下承載上層協(xié)議的地方也就是Data域最大就只能有1500Bytes這個(gè)值 我們就把它稱之為MTU躏筏。

由于MTU限制了一次最多可以發(fā)送1500個(gè)字節(jié)板丽,而TCP協(xié)議在發(fā)送DATA時(shí),還會(huì)加上額外的TCP Header和Ip Header趁尼,因此刨去這兩個(gè)部分埃碱,就是TCP協(xié)議一次可以發(fā)送的實(shí)際應(yīng)用數(shù)據(jù)的最大大小,也就是MSS弱卡。

MSS長(zhǎng)度=MTU長(zhǎng)度-IP Header-TCP Header

TCP Header的長(zhǎng)度是20字節(jié)乃正,IPv4中IP Header長(zhǎng)度是20字節(jié),IPV6中IP Header長(zhǎng)度是40字節(jié)婶博,因此:在IPV4中瓮具,以太網(wǎng)MSS可以達(dá)到1460byte;在IPV6中凡人,以太網(wǎng)MSS可以達(dá)到1440byte名党。

需要注意的是MSS表示的一次可以發(fā)送的DATA的最大長(zhǎng)度,而不是DATA的真實(shí)長(zhǎng)度挠轴。發(fā)送方發(fā)送數(shù)據(jù)時(shí)传睹,當(dāng)SO_SNDBUF中的數(shù)據(jù)量大于MSS時(shí),操作系統(tǒng)會(huì)將數(shù)據(jù)進(jìn)行拆分岸晦,使得每一部分都小于MSS欧啤,這就是拆包,然后每一部分都加上TCP Header启上,構(gòu)成多個(gè)完整的TCP報(bào)文進(jìn)行發(fā)送邢隧,當(dāng)然經(jīng)過(guò)網(wǎng)絡(luò)層和數(shù)據(jù)鏈路層的時(shí)候,還會(huì)分別加上相應(yīng)的內(nèi)容冈在。

需要注意: 默認(rèn)情況下倒慧,與外部通信的網(wǎng)卡的MTU大小是1500個(gè)字節(jié)。而本地回環(huán)地址的MTU大小為65535,這是因?yàn)楸镜販y(cè)試時(shí)數(shù)據(jù)不需要走網(wǎng)卡纫谅,所以不受到1500的限制炫贤。

3、Nagle算法

TCP/IP協(xié)議中付秕,無(wú)論發(fā)送多少數(shù)據(jù)兰珍,總是要在數(shù)據(jù)(DATA)前面加上協(xié)議頭(TCP Header+IP Header),同時(shí)询吴,對(duì)方接收到數(shù)據(jù)俩垃,也需要發(fā)送ACK表示確認(rèn)。

即使從鍵盤(pán)輸入的一個(gè)字符汰寓,占用一個(gè)字節(jié),可能在傳輸上造成41字節(jié)的包苹粟,其中包括1字節(jié)的有用信息和40字節(jié)的首部數(shù)據(jù)有滑。這種情況轉(zhuǎn)變成了4000%的消耗,這樣的情況對(duì)于重負(fù)載的網(wǎng)絡(luò)來(lái)是無(wú)法接受的嵌削。

為了盡可能的利用網(wǎng)絡(luò)帶寬毛好,TCP總是希望盡可能的發(fā)送足夠大的數(shù)據(jù)。(一個(gè)連接會(huì)設(shè)置MSS參數(shù)苛秕,因此肌访,TCP/IP希望每次都能夠以MSS尺寸的數(shù)據(jù)塊來(lái)發(fā)送數(shù)據(jù))。

Nagle算法就是為了盡可能發(fā)送大塊數(shù)據(jù)艇劫,避免網(wǎng)絡(luò)中充斥著許多小數(shù)據(jù)塊吼驶。

Nagle算法的基本定義是任意時(shí)刻,最多只能有一個(gè)未被確認(rèn)的小段店煞。 所謂“小段”蟹演,指的是小于MSS尺寸的數(shù)據(jù)塊,所謂“未被確認(rèn)”顷蟀,是指一個(gè)數(shù)據(jù)塊發(fā)送出去后酒请,沒(méi)有收到對(duì)方發(fā)送的ACK確認(rèn)該數(shù)據(jù)已收到。

Nagle算法的規(guī)則:

  • 1鸣个、如果SO_SNDBUF(發(fā)送緩沖區(qū))中的數(shù)據(jù)長(zhǎng)度達(dá)到MSS羞反,則允許發(fā)送;
  • 2囤萤、如果該SO_SNDBUF中含有FIN昼窗,表示請(qǐng)求關(guān)閉連接,則先將SO_SNDBUF中的剩余數(shù)據(jù)發(fā)送阁将,再關(guān)閉膏秫;
  • 3、設(shè)置了TCP_NODELAY=true選項(xiàng),則允許發(fā)送缤削。TCP_NODELAY是取消TCP的確認(rèn)延遲機(jī)制窘哈,相當(dāng)于禁用了Nagle 算法。
  • 4亭敢、未設(shè)置TCP_CORK選項(xiàng)時(shí)滚婉,若所有發(fā)出去的小數(shù)據(jù)包(包長(zhǎng)度小于MSS)均被確認(rèn),則允許發(fā)送;
  • 5帅刀、上述條件都未滿足让腹,但發(fā)生了超時(shí)(一般為200ms),則立即發(fā)送扣溺。

三骇窍、通信協(xié)議

在了解了粘包、拆包產(chǎn)生的原因之后锥余,現(xiàn)在來(lái)分析接收方如何對(duì)此進(jìn)行區(qū)分腹纳。道理很簡(jiǎn)單,如果存在不完整的數(shù)據(jù)(拆包)驱犹,則需要繼續(xù)等待數(shù)據(jù)嘲恍,直至可以構(gòu)成一條完整的請(qǐng)求或者響應(yīng)。

通過(guò)定義通信協(xié)議(protocol)雄驹,可以解決粘包佃牛、拆包問(wèn)題。協(xié)議的作用就定義傳輸數(shù)據(jù)的格式医舆。這樣在接受到的數(shù)據(jù)的時(shí)候:

  • 如果粘包了俘侠,就可以根據(jù)這個(gè)格式來(lái)區(qū)分不同的包。
  • 如果拆包了蔬将,就等待數(shù)據(jù)可以構(gòu)成一個(gè)完整的消息來(lái)處理兼贡。

3.1、定長(zhǎng)協(xié)議

定長(zhǎng)協(xié)議:顧名思義娃胆,就是指定一個(gè)報(bào)文的必須具有固定的長(zhǎng)度遍希。例如,我們規(guī)定每3個(gè)字節(jié)里烦,表示一個(gè)有效報(bào)文凿蒜,如果我們分4次總共發(fā)送以下9個(gè)字節(jié):

+---+----+------+----+ 
| A | BC | DEFG | HI | 
+---+----+------+----+ 

那么根據(jù)協(xié)議,我們可以判斷出來(lái)胁黑,這里包含了3個(gè)有效的請(qǐng)求報(bào)文废封,如下:

+-----+-----+-----+ 
| ABC | DEF | GHI | 
+-----+-----+-----+ 

在定長(zhǎng)協(xié)議中:

  • 發(fā)送方,必須保證發(fā)送報(bào)文長(zhǎng)度是固定的丧蘸。如果報(bào)文字節(jié)長(zhǎng)度不能滿足條件漂洋,如規(guī)定長(zhǎng)度是1024字節(jié),但是實(shí)際需要發(fā)送的內(nèi)容只有900個(gè)字節(jié),那么不足的部分可以補(bǔ)充0刽漂。因此定長(zhǎng)協(xié)議可能會(huì)浪費(fèi)帶寬演训。
  • 接收方,每讀取到固定長(zhǎng)度的內(nèi)容時(shí)贝咙,則認(rèn)為讀取到了一個(gè)完整的報(bào)文样悟。

提示:Netty中提供了FixedLengthFrameDecoder,支持把固定的長(zhǎng)度的字節(jié)數(shù)當(dāng)做一個(gè)完整的消息進(jìn)行解碼庭猩。

3.2窟她、特殊字符分隔符協(xié)議

在包尾部增加回車或者空格符等特殊字符進(jìn)行分割 。例如蔼水,按行解析震糖,遇到字符\n、\r\n的時(shí)候趴腋,就認(rèn)為是一個(gè)完整的數(shù)據(jù)包试伙。對(duì)于以下二進(jìn)制字節(jié)流:

+--------------+ 
| ABC\nDEF\r\n | 
+--------------+ 

那么根據(jù)協(xié)議,我們可以判斷出來(lái)于样,這里包含了2個(gè)有效的請(qǐng)求報(bào)文

+-----+-----+ 
| ABC | DEF | 
+-----+-----+ 

在特殊字符分隔符協(xié)議中:

  • 發(fā)送方,需要在發(fā)送一個(gè)報(bào)文時(shí)潘靖,需要在報(bào)文尾部添加特殊分割符號(hào)穿剖。
  • 接收方,在接收到報(bào)文時(shí)卦溢,需要對(duì)特殊分隔符進(jìn)行檢測(cè)糊余,直到檢測(cè)到一個(gè)完整的報(bào)文時(shí),才能進(jìn)行處理单寂。

在使用特殊字符分隔符協(xié)議的時(shí)候贬芥,需要注意的是,我們選擇的特殊字符宣决,一定不能在消息體中出現(xiàn)蘸劈,否則可能會(huì)出現(xiàn)錯(cuò)誤的拆包。例如尊沸,發(fā)送方希望把”12\r\n34”威沫,當(dāng)成一個(gè)完整的報(bào)文,如果是按行拆分洼专,那么就會(huì)錯(cuò)誤的拆分為2個(gè)報(bào)文棒掠。一種解決策略是,發(fā)送方對(duì)需要發(fā)送的內(nèi)容預(yù)先進(jìn)行base64編碼屁商,由于base64編碼只包含64個(gè)字符:0-9烟很、a-z、A-Z、+雾袱、/恤筛,我們可以選擇這64個(gè)字符之外的特殊字符作為分隔符。

提示:netty中提供了DelimiterBasedFrameDecoder根據(jù)特殊字符進(jìn)行解碼谜酒。事實(shí)上叹俏,我們熟悉的的緩存服務(wù)器redis,也是通過(guò)換行符來(lái)區(qū)分一個(gè)完整的報(bào)文僻族。

3.3粘驰、變長(zhǎng)協(xié)議

將消息區(qū)分為消息頭和消息體述么,在消息頭中蝌数,我們使用一個(gè)整形數(shù)字,例如一個(gè)int度秘,來(lái)表示消息體的長(zhǎng)度顶伞。而消息體實(shí)際實(shí)際要發(fā)送的二進(jìn)制數(shù)據(jù)字節(jié)。以下是一個(gè)基本格式:

header    body 
+--------+----------+ 
| Length |  Content | 
+--------+----------+ 

在變長(zhǎng)協(xié)議中:

  • 發(fā)送方剑梳,發(fā)送數(shù)據(jù)之前唆貌,需要先獲取需要發(fā)送內(nèi)容的二進(jìn)制字節(jié)大小,然后在需要發(fā)送的內(nèi)容前面添加一個(gè)整數(shù)垢乙,表示消息體二進(jìn)制字節(jié)的長(zhǎng)度锨咙。
  • 接收方,在解析時(shí)追逮,先讀取內(nèi)容長(zhǎng)度Length酪刀,其值為實(shí)際消息體內(nèi)容(Content)占用的字節(jié)數(shù),之后必須讀取到這么多字節(jié)的內(nèi)容钮孵,才認(rèn)為是一個(gè)完整的數(shù)據(jù)報(bào)文骂倘。

提示:Netty中提供了LengthFieldPrepender給實(shí)際內(nèi)容Content進(jìn)行編碼添加Length字段,接受方使用LengthFieldBasedFrameDecoder解碼巴席。

3.4历涝、序列化

序列化本質(zhì)上已經(jīng)不是為了解決粘包和拆包問(wèn)題,而是為了在網(wǎng)絡(luò)開(kāi)發(fā)中可以更加的便捷漾唉。在變長(zhǎng)協(xié)議中睬关,我們看到可以在實(shí)際要發(fā)送的數(shù)據(jù)之前加上一個(gè)length字段,表示實(shí)際要發(fā)送的數(shù)據(jù)的長(zhǎng)度毡证。這實(shí)際上給我們了一個(gè)很好的思路电爹,我們完全可以將一個(gè)對(duì)象轉(zhuǎn)換成二進(jìn)制字節(jié),來(lái)進(jìn)行通信料睛,例如使用一個(gè)Request對(duì)象表示請(qǐng)求丐箩,使用一個(gè)Response對(duì)象表示響應(yīng)摇邦。

序列化框架有很多種,我們?cè)谶x擇時(shí)屎勘,主要考慮序列化/反序列化的速度施籍,序列化占用的體積,多語(yǔ)言支持等概漱。下面列出了業(yè)界流行的序列化框架:


提示:xml丑慎、json也屬于序列化框架的范疇,上面的表格中并沒(méi)有列出瓤摧。

一些網(wǎng)絡(luò)通信的RPC框架通常會(huì)支持多種序列化方式竿裂,例如dubbo支持hessian、json照弥、kyro腻异、fst等。在支持多種序列化框架的情況下这揣,在協(xié)議中通常需要有一個(gè)字段來(lái)表示序列化的類型悔常,例如,我們可以將上述變長(zhǎng)協(xié)議的格式改造為:

+--------+-------------+------------+ 
| Length |  serializer |   Content  | 
+--------+-------------+------------+ 

這里使用1個(gè)字節(jié)表示Serializer的值给赞,使用不同的值代表不同的框架机打。

發(fā)送方,選擇好序列化框架后編碼后片迅,需要指定Serializer字段的值残邀。

接收方,在解碼時(shí)障涯,根據(jù)Serializer的值選擇對(duì)應(yīng)的框架進(jìn)行反序列化。

3.5膳汪、壓縮

通常唯蝶,為了節(jié)省網(wǎng)絡(luò)開(kāi)銷,在網(wǎng)絡(luò)通信時(shí)遗嗽,可以考慮對(duì)數(shù)據(jù)進(jìn)行壓縮粘我。常見(jiàn)的壓縮算法有l(wèi)z4、snappy痹换、gzip等征字。在選擇壓縮算法時(shí),我們主要考慮壓縮比以及解壓縮的效率娇豫。

我們可以在網(wǎng)絡(luò)通信協(xié)議中匙姜,添加一個(gè)compress字段,表示采用的壓縮算法:

+--------+-----------+------------+------------+ 
| Length | serializer|  compress  |   Content  | 
+--------+-----------+------------+------------+ 

通常冯痢,我們沒(méi)有必要使用一個(gè)字節(jié)氮昧,來(lái)表示采用的壓縮算法框杜,1個(gè)字節(jié)可以標(biāo)識(shí)256種可能情況,而常用壓縮算法也就那么幾種袖肥,因此通常只需要使用2~3個(gè)bit來(lái)表示采用的壓縮算法即可咪辱。

另外,由于數(shù)據(jù)量比較小的時(shí)候椎组,壓縮比并不會(huì)太高油狂,沒(méi)有必要對(duì)所有發(fā)送的數(shù)據(jù)都進(jìn)行壓縮,只有再超過(guò)一定大小的情況下寸癌,才考慮進(jìn)行壓縮专筷。如rocketmq,producer在發(fā)送消息時(shí)灵份,默認(rèn)消息大小超過(guò)4k仁堪,才會(huì)進(jìn)行壓縮。因此填渠,compress字段弦聂,應(yīng)該有一個(gè)值,表示沒(méi)有使用任何壓縮算法氛什,例如使用0莺葫。

3.6、查錯(cuò)校驗(yàn)碼

一些通信協(xié)議傳輸?shù)臄?shù)據(jù)中枪眉,還包含了查錯(cuò)校驗(yàn)碼捺檬。典型的算法如CRC32、Adler32等贸铜。java對(duì)這兩種校驗(yàn)方式都提供了支持堡纬,java.util.zip.Adler32、java.util.zip.CRC32蒿秦。

+--------+-----------+------------+------------+---------+ 
| Length | serializer|  compress  |   Content  |  CRC32  | 
+--------+-----------+------------+------------+---------+ 

這里并不對(duì)CRC32烤镐、Adler32進(jìn)行詳細(xì)說(shuō)明,主要是考慮棍鳖,為什么需要進(jìn)行校驗(yàn)?

有人說(shuō)是因?yàn)榭紤]到安全炮叶,這個(gè)理由似乎并不充分,因?yàn)槲覀円呀?jīng)有了TLS層的加密渡处,CRC32镜悉、Adler32的作用不應(yīng)該是為了考慮安全。

一位同事的觀點(diǎn)医瘫,我非常贊同:二進(jìn)制數(shù)據(jù)在傳輸?shù)倪^(guò)程中侣肄,可能因?yàn)殡姶鸥蓴_,導(dǎo)致一個(gè)高電平變成低電平醇份,或者低電平變成高電平茫孔。這種情況下叮喳,數(shù)據(jù)相當(dāng)于受到了污染,此時(shí)通過(guò)CRC32等校驗(yàn)值缰贝,則可以驗(yàn)證數(shù)據(jù)的正確性馍悟。

另外,通常校驗(yàn)機(jī)制在通信協(xié)議中剩晴,是可選的配置的锣咒,并不需要強(qiáng)制開(kāi)啟,其雖然可以保證數(shù)據(jù)的正確赞弥,但是計(jì)算校驗(yàn)值也會(huì)帶來(lái)一些額外的性能損失毅整。如Mysql主從同步,雖然高版本默認(rèn)開(kāi)啟CRC32校驗(yàn)绽左,但是也可以通過(guò)配置禁用悼嫉。

小結(jié)

本節(jié)通過(guò)一些基本的案例,講解了在TCP編程中拼窥,如何通過(guò)協(xié)議來(lái)解決粘包戏蔑、拆包問(wèn)題。在實(shí)際開(kāi)發(fā)中鲁纠,通常我們的協(xié)議會(huì)更加復(fù)雜总棵。例如,一些RPC框架改含,會(huì)在協(xié)議中添加唯一標(biāo)識(shí)一個(gè)請(qǐng)求的ID情龄,一些支持雙向通信的RPC框架,如sofa-bolt捍壤,還會(huì)添加一個(gè)方向信息等骤视。當(dāng)然,所謂復(fù)雜专酗,無(wú)非是在協(xié)議中添加了某個(gè)字段用于某個(gè)用途唯卖,只要弄清楚這些字段的含義,也就不復(fù)雜了颠锉。

參考:
https://www.cnblogs.com/Leo_wl/p/10297113.html

https://www.cnblogs.com/sidesky/p/6913109.html

https://blog.csdn.net/u022812849/article/details/107254239

http://www.reibang.com/p/c90ec659397c

https://network.51cto.com/art/201910/604438.htm

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瓷蛙,一起剝皮案震驚了整個(gè)濱河市埋市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敌蜂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)旭寿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盅称,“玉大人房蝉,你說(shuō)我怎么就攤上這事∥⑶” “怎么了搭幻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)逞盆。 經(jīng)常有香客問(wèn)我檀蹋,道長(zhǎng),這世上最難降的妖魔是什么云芦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任俯逾,我火速辦了婚禮,結(jié)果婚禮上舅逸,老公的妹妹穿的比我還像新娘桌肴。我一直安慰自己,他們只是感情好琉历,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布坠七。 她就那樣靜靜地躺著,像睡著了一般旗笔。 火紅的嫁衣襯著肌膚如雪彪置。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天蝇恶,我揣著相機(jī)與錄音拳魁,去河邊找鬼。 笑死撮弧,一個(gè)胖子當(dāng)著我的面吹牛潘懊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贿衍,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼授舟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了舌厨?” 一聲冷哼從身側(cè)響起岂却,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤忿薇,失蹤者是張志新(化名)和其女友劉穎裙椭,沒(méi)想到半個(gè)月后躏哩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揉燃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年扫尺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炊汤。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡正驻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抢腐,到底是詐尸還是另有隱情姑曙,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布迈倍,位于F島的核電站伤靠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏啼染。R本人自食惡果不足惜宴合,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迹鹅。 院中可真熱鬧卦洽,春花似錦、人聲如沸斜棚。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弟蚀。三九已至脂新,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粗梭,已是汗流浹背争便。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留断医,地道東北人滞乙。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鉴嗤,于是被迫代替她去往敵國(guó)和親斩启。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容