1. 程式人生 > >一起學Netty(八)之 淺析ByteToMessageDecoder

一起學Netty(八)之 淺析ByteToMessageDecoder

上一節一起學習了幾個解碼器,用於解決TCP協議網路傳輸過程中粘包和拆包的問題,用過Netty的人總會說一句話“用Netty一定要了解一下它的底層原理,這樣才敢用”,其實很有感悟,Netty in action 這本書中也有一個章節分析了codec,也定義了幾個自定義的譯碼器,但是它自定義的幾個譯碼器全部是繼承與ByteToMessageDecoder的,我們上文中的幾個解碼器例如DelimiterBasedFrameDecoder,FixedLengthFrameDecoder,LineBasedFrameDecoder這幾個全部繼承於ByteToMessageDecoder

LineBasedFrameDecoder.

Java

FixedLengthFrameDecoder.java

DelimiterBasedFrameDecoder.java

可以看出常用的一些解碼器都是繼承於ByteToMessageDecoder,說明了這個decoder的重要性

今天我們就分析一下ByteToMessageDecoder這個類,我們並不是分析原始碼,至少現在還不是分析原始碼的時候,我個人覺得框架技術啥的,至少先會用,會用之後看原始碼事半功倍

首先,我們先看下ByteToMessageDecoder的完整宣告:

簡單的分析一下:

1)繼承了我們使用頻率最高的ChannelInboundHandlerAdapter,的確,它必須是一個handler,這樣才可以被新增到channelPipeline中處理資訊流,既然繼承與ChannelInboundHandlerAdapter,我們要看的就是channelRead這個方法

2)這是一個抽象類,抽象類和介面的區別就是它應該有抽象方法沒有實現,如下:

這個decode方法就是一個抽象方法,也就是DelimiterBasedFrameDecoder,FixedLengthFrameDecoder這些子類,具體的實現類需要實現了

簡單的看下,我們就知道我們主要看的是就是這兩個方法了

首先我們先看channelRead方法:


這是channelRead的原始碼,我們可以看出,程式碼一開始就判斷msg是不是ByteBuf,也就是為什麼我們一般把解碼器放在Channelhandler鏈的第一個的原因了,這樣做的好處就是msg一般就是ByteBuf,不會被其他的業務邏輯影響,至少這時msg的很“純潔”的。而且這個msg極有可能是directByteBuf,也就是說這是堆外記憶體的,因為我們ByteBuf在傳輸的時候堆外記憶體傳輸的時候可以少一次複製,之前的章節提及過

然後如果是第一次接收的情況下,直接接data放入到cumulation中,這個cumulation是一個全域性變數:

這樣做的好處就是cumulation相當於一個容器,在上層程式碼多次呼叫channelRead的時候,也就是當傳送端的資訊可能被接收端分多次接收的時候,這個容器儲存資訊

解析來我們接著看:


第135行主要判斷cumulation的可寫下標+當前的讀取的data的可讀容量之和是不是大於cumulation的最大容量,這樣做的就是防止cumulation的ByteBuf容量溢位,如果大於了,則說明cumulation需要擴容了


擴容的程式碼如圖展示,需要注意的就是需要將老的oldCumulation釋放掉

擴容之後,程式碼146行將新新增的data加入到cumulation中,147行再釋放data所佔用的記憶體空間,在149行就開始進行decode了,這個callDecode方法其實是對入參out進行了編輯

之所以out中的值是多個,是因為calldecode方法內部有一個迴圈,輸入的型別是ByteBuf的in變數,只要它的isReadable方法返回true,說明該ByteBuf中還有可讀的byte,可以按照使用者自定的decode方法去切分分割,將按照使用者方法切割的資訊放入入參out中就可以了

我們剛剛也說明了,decode是一個抽象方法,需要每一個具體的類去實現,給出具體的分割轉化的業務邏輯

接下來我覺得也是最最值得我學習的,就是finally這段程式碼:

不是程式碼寫的多麼精闢,只是我從來沒有在finally裡面寫過業務程式碼,最多關關資源之類的動作在裡面寫過,也就是說即使後面的資料處理發生異常或者怎麼怎樣,只要out這個list中有值,則會呼叫後續的fireChannelRead的方法

沒有去對ByteToMessageDecoder這個方法進行深入的解析,只是瞭解它的基本原理~

相關推薦

一起Netty 淺析ByteToMessageDecoder

上一節一起學習了幾個解碼器,用於解決TCP協議網路傳輸過程中粘包和拆包的問題,用過Netty的人總會說一句話“用Netty一定要了解一下它的底層原理,這樣才敢用”,其實很有感悟,Netty in action 這本書中也有一個章節分析了codec,也定義了幾個自定義的譯碼

一起Netty Netty使用Google的ProtoBuf

protobuf是由Google開發的一套對資料結構進行序列化的方法,可用做通訊協議,資料儲存格式,等等。其特點是不限語言、不限平臺、擴充套件性強 Netty也提供了對Protobuf的天然支援,我們今天就寫一個簡單的示例,簡單地瞭解一下Netty對Google的prot

一起Netty SimpleChannelInboundHandler

 其實Netty的知識點還是很零碎的,比如這個SimpleChannelInboundHandler這個類,在《Netty in Action》該書中的原版的Hello world的demo的客戶端就是使用的SimpleChannelInboundHandler來作為處理

一起Netty Hello Netty的原型圖解

上一個小節,寫的一個入門的Hello Netty的案例,它的模型其實很簡單,我們畫個簡單的圖理解一下 package com.lyncc.netty.concept; /** * * @author Bazingalyncc * 描述: * 時間 2016年

一起Netty ChannelHandler,ChannelHandlerContext,ChannelPipeline

本小節一起學習一下ChannelHandler,ChannelHandlerContext,ChannelPipeline這三個Netty常用的元件,不探究它們的底層原始碼,我們就簡單的分析一下用法 首先先分析一下ChannelHandler,ChannelHandler

一起Netty 初識ByteBuf和ByteBuf的常用API

  網路傳輸的載體是byte,這是任何框架誰也逃脫不了的一種規定,JAVA的NIO提供了ByteBuffer,用來完成這項任務,當然ByteBuffer也很好的完成了這個任務,Netty也提供了一個名字很相似的載體叫做ByteBuf,相比於ByteBuf而言,它有著更加更多

一起Netty TCP粘包拆包場景

TCP程式設計底層都有粘包和拆包機制,因為我們在C/S這種傳輸模型下,以TCP協議傳輸的時候,在網路中的byte其實就像是河水,TCP就像一個搬運工,將這流水從一端轉送到另一端,這時又分兩種情況: 1)如果客戶端的每次製造的水比較多,也就是我們常說的客戶端給的包比較大,TC

一起Netty TCP粘包拆包基本解決方案

上個小節我們淺析了在Netty的使用的時候TCP的粘包和拆包的現象,Netty對此問題提供了相對比較豐富的解決方案 Netty提供了幾個常用的解碼器,幫助我們解決這些問題,其實上述的粘包和拆包的問題,歸根結底的解決方案就是傳送端給遠端端一個標記,告訴遠端端,每個資訊的結束

跟我一起python,網路程式設計基礎篇

Socket socket通常也稱作”套接字”,用於描述IP地址和埠,是一個通訊鏈的控制代碼,應用程式通常通過”套接字”向網路發出請求或者應答網路請求。 socket起源於Unix,而Unix/Linux基本哲學之一就是“一切皆檔案”,對於檔案用【開啟】【讀

一起Nettynetty原始碼學習netty server端原始碼初讀

server端是使用了Reactor模式對nio進行了一些封裝,Reactor模式網上有很多資料,不贅述,瞭解了這個模式開始看原始碼 netty的版本是4.0.21.Final <dependency> <groupId>io.netty<

一起Netty十二 Netty心跳簡單Demo

前面簡單地瞭解了一下IdleStateHandler,我們現在寫一個簡單的心跳demo: 1)伺服器端每隔5秒檢測伺服器端的讀超時,如果5秒沒有接受到客戶端的寫請求,也就說伺服器端5秒沒有收到讀事件,則視為一次超時 2)如果超時二次則說明連線處於不活躍的狀態,關閉Serve

一起Netty十七netty原始碼學習大話java NIO

沉澱了一個月安安心心地學習了家純大神的Jupiter(https://github.com/fengjiachun/Jupiter),感覺受益良多,感覺自己學習了這裡面的精華的50%,不是謙虛,而是無知,因為我不知道著裡面還有多少是我沒有理解的,也許我看懂了他的程式碼,但我

一起Netty十四 Netty生產級的心跳和重連機制

sigh,寫這篇部落格的時候老臉還是紅了一下,心裡還是有些唏噓的,應該算是剽竊吧,每個人的程式碼功力的確是有差距的,好在文章的標題是“一起學”,而不是開濤大神的“跟我學”系列的文章,我們還是多花點時間學習吧,感嘆無用~ 最近工作比較忙,但閒暇之餘還是看了阿里的馮家春(fe

Python函數

列表 應該 聚合 作用 接收 求階乘 問題 mage 函數式編程 Python函數 函數作用: (1)代碼重用 (2)一種設計工具,分解復雜問題 (3)將相關功能打包並參數化 函數種類: 全局函數:定義在模塊中 局部函數:嵌套在其他函數中 lambda函數:表達

python爬蟲從入門到放棄 Selenium庫的使用

自動 .com 程序 png 都是 例子 等待 點擊 哪些 一、什麽是Selenium selenium 是一套完整的web應用程序測試系統,包含了測試的錄制(selenium IDE),編寫及運行(Selenium Remote Control)和測試的並行處理(Sele

一步一步Vue

nod png 路由配置 ring 圖片 sca -a 基本 routes 本篇完成如下場景: 1、系統包含首頁、客戶信息查詢、登錄三個模塊 2、默認進入系統首頁,如果要進行用戶查詢,則需要進行登錄授權 3、查詢用戶後點擊列表項,則進入詳情頁面 基於上述場景需求描述

JavaSE集合練習一

can lec set 打印 定義 hello blog 要求 sys 前面把Collection家族給學習完畢了,接下來我們通過幾個練習來鞏固前面的知識。 一、產生10個1-20之間的隨機數要求隨機數不能重復 import java.util.HashSe

python學習筆記運算符

技術 ima 學習 表達式 water nag proc 說明 ddc python學習筆記(八)之運算符 算術運算符 比較運算符 邏輯運算符(1)布爾運算(2)復雜的布爾表達式 說明:以上內容摘自《跟老齊學python》python學習筆記(八)之運算符

04_web基礎車票實現增刪改查初級版本

lose src uri sed RR 實現 手動添加 jsp頁面 ebs 43.web頁面顯示車票列表簡略完成   代碼:   控制層代碼 1 package com.day03.station.controller; 2 3 import com.day03

vue的爬坑----IOS:Safari不兼容Javascript中的Date問題

找到 () 方案 ace 格式 nbsp 後臺 get repl 在IOS5以上版本(不包含IOS5)中的Safari瀏覽器能正確解釋出Javascript中的 new Date(‘2013-10-21‘) 的日期對象。 但是在IOS5版本裏面的Safar