Netty 粘包 & 拆包 & 編碼 & 解碼 & 序列化 介紹

目錄:

  1. 粘包 & 拆包及解決方案 ByteToMessageDecoder
  2. 基于長度編解碼器
  3. 基于分割符的編解碼器
  4. google 的 Protobuf 序列化介紹
  5. 其他的

前言

Netty 作為一個(gè)網(wǎng)絡(luò)框架筐高,對 TCP 連接中的問題都做了全面的考慮城瞎,比如粘包拆包導(dǎo)致的半包問題,如何編解碼,如何實(shí)現(xiàn)私有協(xié)議,序列化等等。本文主要針對這些問題做一個(gè)簡單介紹募判,目的是想對整個(gè) Netty 的編解碼框架做一個(gè)全盤的審視,以確保在后面的源碼學(xué)習(xí)中不會一葉障目不見泰山咒唆。

1. 粘包 & 拆包及解決方案 ByteToMessageDecoder

由于TCP是面向字節(jié)流的届垫,什么意思呢:雖然應(yīng)用程序和 TCP 的交互是一次一個(gè)數(shù)據(jù)塊(大小不等),但 TCP 把應(yīng)用程序交下來的數(shù)據(jù)僅僅看成式一連串的無結(jié)構(gòu)的字節(jié)流全释。TCP 并不知道所傳送的字節(jié)流的含義装处。

因此 TCP 不保證接收方應(yīng)用程序所收到的數(shù)據(jù)塊和發(fā)送方應(yīng)用程序所發(fā)出的數(shù)據(jù)塊具有對應(yīng)大小的關(guān)系(例如,發(fā)送方應(yīng)用程序交給發(fā)送方的 TCP 共 10 個(gè)數(shù)據(jù)塊浸船,但接收方的 TCP 可能只用了 4 個(gè)就把收到的字節(jié)流交付上層的應(yīng)用程序)妄迁。

同時(shí),TCP 不關(guān)心應(yīng)用進(jìn)程一次把多長的報(bào)文發(fā)送到 TCP 的 緩存 中李命,而是根據(jù)對方給出的窗口值和當(dāng)前網(wǎng)絡(luò)阻塞的程度來決定一個(gè)報(bào)文段應(yīng)包含多少個(gè)字節(jié)(UDP 發(fā)送的報(bào)文長度是應(yīng)用進(jìn)程給出的)登淘。如果應(yīng)用進(jìn)程傳送到 TCP 緩存的數(shù)據(jù)塊太長,TCP 就可以把他劃分短一點(diǎn)再傳送封字。如果應(yīng)用程序一次只發(fā)來一個(gè)字節(jié)黔州,TCP 也可以等待積累有足夠多的字節(jié)后再構(gòu)成報(bào)文段發(fā)送出去。

  • TCP 發(fā)送報(bào)文一般是 3 個(gè)時(shí)機(jī):
  1. 緩沖區(qū)數(shù)據(jù)達(dá)到 最大報(bào)文長度 MSS阔籽;
  2. 由發(fā)送端的應(yīng)用進(jìn)程指明要求發(fā)送報(bào)文段流妻,即 TCP 支持的推送(push)操作;
  3. 當(dāng)發(fā)送方的一個(gè)計(jì)時(shí)器期限到了笆制,即使長度不超過 MSS 绅这,也發(fā)送。

以上引自《計(jì)算機(jī)網(wǎng)絡(luò)-----謝希仁》在辆。

說了這么多证薇,TCP 的這種機(jī)制度苔,會導(dǎo)致什么問題呢?粘包問題棕叫。有了粘包林螃,就需要拆包奕删。

  • 一般解決粘包拆包問題有 4 種辦法:
  1. 固定數(shù)據(jù)的長度俺泣,比如 100 字節(jié),如果不夠就補(bǔ)空格完残。
  2. 學(xué)習(xí) HTTP 伏钠,F(xiàn)TP 等,使用回車換行符號谨设。
  3. 將消息分為 head 和 body熟掂,head 中包含 body 長度的字段,一般 head 的第一個(gè)字段使用 int 值來表示 body 長度扎拣。
  4. 使用更復(fù)雜的應(yīng)用層協(xié)議(等于沒說 =_= !)赴肚。

Netty 作為一個(gè)網(wǎng)絡(luò)框架,直接和 TCP 打交道二蓝,自然考慮了這個(gè)問題誉券。而解決這個(gè)問題的主要實(shí)現(xiàn)就是抽象類 ByteToMessageDecoder,詳見 Netty 解碼器抽象父類 ByteToMessageDecoder 源碼解析刊愚。Netty 使用了模板設(shè)計(jì)模式踊跟,這個(gè)類只定義了共有行為,具體解碼實(shí)現(xiàn)還是子類鸥诽,比如上面提到的 4 種方式商玫。

2. 基于長度編解碼器的具體實(shí)現(xiàn)

基于長度的實(shí)現(xiàn)有2個(gè)現(xiàn)成的類:

  1. FixedLengthFrameDecoder 基于構(gòu)造函數(shù)中的固定長度
    該類很簡單,構(gòu)造方法中牡借,傳入一個(gè)整數(shù)拳昌,該解碼器就會按照這個(gè)數(shù)字對累積區(qū)的字節(jié)進(jìn)行切分。

  2. LengthFieldBasedFrameDecoder 基于流中動態(tài)的長度
    該類比較復(fù)雜钠龙。構(gòu)造函數(shù)參數(shù)多達(dá) 6 個(gè)炬藤,在構(gòu)建私有協(xié)議棧時(shí)大有用處。

3. 基于分割符的編解碼器

同樣有 2 個(gè):

  1. DelimiterBasedFrameDecoder 用戶提供分割符俊鱼。
    該類比較簡單刻像,根據(jù)用戶提供的分割符對累積區(qū)的內(nèi)容進(jìn)行分割。性能相對不是那么完美并闲。

  2. LineBasedFrameDecoder 基于換行符,支持多種換行符 \n \r\n 速度相比自定義較快细睡。
    該類使用更簡單,根據(jù)換行符進(jìn)行拆包粘包帝火。

4. google 的 ProtobufDecoder ProtobufEncoder 序列化介紹

Netty 中有很多序列化工具溜徙,比如 Jboss 的 Marshalling湃缎,同時(shí)也支持 Java 標(biāo)準(zhǔn)的序列化。 但我們重點(diǎn)關(guān)注 google 的 protobuf 庫蠢壹。因?yàn)樗男阅茏罡摺?/p>

上面的 4 個(gè)解碼器都是基于 ByteToMessageDecoder嗓违,將粘包的字節(jié)轉(zhuǎn)為用戶需要的字節(jié)。而ProtobufDecoder 不是繼承自 ByteToMessageDecoder图贸,而是繼承自 MessageToMessageDecoder蹂季,名字都不同。MessageToMessageDecoder 的作用是什么呢疏日?

從名字上看偿洁,該類用于將兩個(gè)消息進(jìn)行轉(zhuǎn)換(比如一種 POJO 轉(zhuǎn)成另一種)。后面我們將花大篇幅講述這個(gè)類庫沟优。

5. 其他的

1. TooLongFrameException

由于 Netty 是一個(gè)異步框架涕滋,所以需要在字節(jié)可以解碼之前在內(nèi)存中緩沖他們。因此不能讓解碼器緩沖大量的數(shù)據(jù)以至于耗盡可用的內(nèi)存挠阁。為了解決這個(gè)問題宾肺,Netty 提供了 TooLongFrameException 類,其將由解碼器在幀超出指定的大小限制時(shí)拋出異常侵俗。

你可以設(shè)置一個(gè)最大的閾值锨用,當(dāng)超過該閾值,這拋出異常坡慌。

2. 寫大型數(shù)據(jù)的 FileRegion

有時(shí)候你可能需要寫一個(gè)大型的數(shù)據(jù)黔酥,如果不停的寫入,可能導(dǎo)致 OOM洪橘,所以在寫大型數(shù)據(jù)時(shí)跪者,需要準(zhǔn)備好處理到遠(yuǎn)程節(jié)點(diǎn)的連接時(shí)慢速連接的情況,這種情況會導(dǎo)致內(nèi)存釋放的延遲熄求。

我們可以使用 NIO 的零拷貝特性渣玲,這種特性消除了將文件內(nèi)容從文件系統(tǒng)移動到網(wǎng)絡(luò)棧的復(fù)制過程。而我們所需要做的就是使用一個(gè) FileRegion 接口的實(shí)現(xiàn)弟晚。
官方定義:

通過支持零拷貝的文件傳輸?shù)?Channel 來發(fā)送的文件區(qū)域忘衍。

6. 總結(jié)

本文并沒有刨析源碼,主要是針對 Netty 中現(xiàn)有的或者設(shè)計(jì)的編解碼卿城,序列化等工具做一個(gè)介紹枚钓,方便后面有條不紊的按照這個(gè)路線研究他們的具體實(shí)現(xiàn)。

good luckI骸2蠼荨!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嫩舟,一起剝皮案震驚了整個(gè)濱河市氢烘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌家厌,老刑警劉巖播玖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異饭于,居然都是意外死亡蜀踏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門镰绎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脓斩,“玉大人,你說我怎么就攤上這事畴栖。” “怎么了八千?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵吗讶,是天一觀的道長。 經(jīng)常有香客問我恋捆,道長照皆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任沸停,我火速辦了婚禮膜毁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愤钾。我一直安慰自己瘟滨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布能颁。 她就那樣靜靜地躺著杂瘸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伙菊。 梳的紋絲不亂的頭發(fā)上败玉,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音镜硕,去河邊找鬼运翼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛兴枯,可吹牛的內(nèi)容都是我干的血淌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼念恍,長吁一口氣:“原來是場噩夢啊……” “哼六剥!你這毒婦竟也來了晚顷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤疗疟,失蹤者是張志新(化名)和其女友劉穎该默,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體策彤,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栓袖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了店诗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裹刮。...
    茶點(diǎn)故事閱讀 38,605評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庞瘸,靈堂內(nèi)的尸體忽然破棺而出捧弃,到底是詐尸還是另有隱情,我是刑警寧澤擦囊,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布违霞,位于F島的核電站,受9級特大地震影響瞬场,放射性物質(zhì)發(fā)生泄漏买鸽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一贯被、第九天 我趴在偏房一處隱蔽的房頂上張望眼五。 院中可真熱鬧,春花似錦彤灶、人聲如沸看幼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽依啰。三九已至拱燃,卻和暖如春链沼,著一層夾襖步出監(jiān)牢的瞬間耍铜,已是汗流浹背畦戒。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工檩赢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搬卒,地道東北人瑟俭。 一個(gè)月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像契邀,于是被迫代替她去往敵國和親摆寄。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評論 2 348

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

  • 為什么要粘包拆包 為什么要粘包 首先你得了解一下TCP/IP協(xié)議,在用戶數(shù)據(jù)量非常小的情況下微饥,極端情況下逗扒,一個(gè)字節(jié)...
    簡書閃電俠閱讀 20,617評論 23 77
  • 簡介 用簡單的話來定義tcpdump,就是:dump the traffic on a network欠橘,根據(jù)使用者...
    保川閱讀 5,942評論 1 13
  • 前奏 https://tech.meituan.com/2016/11/04/nio.html 綜述 netty通...
    jiangmo閱讀 5,846評論 0 13
  • 一矩肩、粘包與拆包 1、發(fā)送時(shí)的粘包與拆包 TCP連接維護(hù)了一個(gè)發(fā)送緩存區(qū)肃续。將要發(fā)送給對端的數(shù)據(jù)會由socket AP...
    益文的圈閱讀 4,259評論 6 14
  • Netty是目前業(yè)界最流行的NIO框架之一黍檩,它的健壯性、高性能始锚、可定制和可擴(kuò)展性在同類框架中都是首屈一指刽酱。它已經(jīng)得...
    FX_SKY閱讀 8,506評論 3 6