日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

1.Netty的業務場景

? 平臺主要需求是和充電樁對接,并定時對設備進行監控檢查,需要使用Netty作為通信中間件來監聽端口,充電樁通過TCP連接向服務端發送指令,后臺主要是通過netty的ChannelHandler來實現對硬件數據的接收和處理。

2. Netty的主要組件

2.1 Channel

? Channel作為Netty網絡通信的主體,可以看作是通訊的載體,主要有三個狀態:打開、關閉、連接。

? Channel主要的IO操作:讀(read)、寫(write)、連接(connect)、綁定(bind),均為異步,也就是說在調用如上方法后,并不保證IO操作完成,但會在IO操作成功、失敗或取消后,生成相應的記錄保存在一個憑證中并返回。

2.2 ChannelHandler

? 負責Channel中的邏輯處理,可針對性地攔截處理Channel負責的IO操作或事件,然后在它的ChannelPipeline中將其遞交給下一個handler。ChannelHandler中有許多方法需要實現,一般通過繼承ChannelHandlerAdapter來實現。

開源物聯網平臺Thingsboard——Netty實現與硬件設備通訊

 

2.3 ChannelPipeline

? Netty中,ChannelPipeline相當于ChannelHandler的容器,它們可用于攔截和處理channel事件,關系如下圖:

開源物聯網平臺Thingsboard——Netty實現與硬件設備通訊

 

 

? ChannelPipeline相當于ChannelHandler的容器,channel事件消息在ChannelPipeline中傳播流動,而ChannelHandler可以針對性地對事件進行攔截處理、傳遞、忽略或者終止。一個ChannelHandler會綁定一個ChannelHandlerContext對象,ChannelHandler會通過與其對應的Context對象和ChannelPipeline交互,比如向上或向下傳遞events,動態地修改ChannelPipeline,或者通過ChannelHandlerContext中的AttributeKeys存儲與handler相關的信息。

3. Netty服務端的啟動

	ServerBootstrap serverBootstrap = new ServerBootstrap();    //啟動NIO服務的輔助啟動類
            serverBootstrap.group(parentGroup, childGroup).channel(NIOServerSocketChannel.class)  //啟動服務時, 通過反射創建一個NioServerSocketChannel對象
                    //服務器初始化時執行, 屬于AbstracBootstrap的方法
                    .handler(new LoggingHandler(LogLevel.INFO))    //handler在初始化時就會執行,可以設置打印日志級別
                    .option(ChannelOption.SO_BACKLOG, 1024)      //設置tcp緩沖區, 可連接隊列大小
                    .option(ChannelOption.SO_REUSEADDR, true)    //允許重復使用本地地址和端口
                    //客戶端連接成功之后執行, 屬于ServerBootstrap的方法,繼承自AbstractBootstrap
                    .childOption(ChannelOption.SO_KEEPALIVE, true)    //兩小時沒有數據通信時, 啟用心跳保活機制探測客戶端是否連接有效
                    .childOption(ChannelOption.SO_REUSEADDR, true)
                    .childHandler(serverChannelInit);    //childHandler在客戶端成功連接后才執行,實例化ChannelInitializer
            ChannelFuture cf = serverBootstrap.bind(port).sync();    //綁定端口, 添加異步阻塞等待服務器啟動完成
            if (cf.isSuccess() == true) {
                logger.info("NettyServer啟動成功");
            } else {
                logger.error("NettyServer啟動失敗", cf.cause());
            }
            cf.channel().closeFuture().sync();    //等待服務器套接字關閉

 

4. Netty中的編解碼

4.1 解碼器

? 解碼(decode)就是根據約定的協議格式,對二進制數據進行解析解碼(decode),這一功能由解碼器(decoder)完成。這部分的主要工作是:確定協議、編寫協議對應的解碼器。Netty中有一套編解碼框架,輸入的數據由ChannelInboundHandler處理,自定義的解碼器實際上就是這個接口的特殊實現類。

? 對于解碼器(decoder),Netty主要提供了抽象基類ByteToMessageDecoder和MessageToMessageDecoder。

開源物聯網平臺Thingsboard——Netty實現與硬件設備通訊

 

4.1.1 抽象類ByteToMessageDecoder

? 用于將接收的二進制數據(Byte)解碼,得到完整有效的請求報文(Message)。

? 一般ByteToMessageDecoder解碼內容后,會得到一個ByteBuf實例,每個ByteBuf實例都包含了一個完整的報文信息。可以直接把這些ByteBuf實例交給之后的ChannelInboundHandler處理,或將ByteBuf實例解析封裝到不同的JAVA實例對象后,再交給它處理。不管哪一種情況,之后的ChannelInboundHandler在處理時不需要再考慮粘包、拆包問題。

? ByteToMessageDecoder中常見的實現類:

FixedLengthFrameDecoder:定長協議解碼器,可以指定固定字節數算一個完整報文

LineBasedFrameDecoder:行分隔符解碼器,遇到n或者rn,則認為是一個完整的報文

DelimiterBasedFrameDecoder:分隔符解碼器,與LineBasedFrameDecoder類似,但可以自己指定分隔符

LengthFieldBasedFrameDecoder:長度編碼解碼器,將報文劃分為報文頭/報文體,根據報文頭中的Length字段確定報文體的長度,因此報文體的長度是可變的

JsonObjectDecoder:json格式解碼器,當檢測到匹配數量的"{" 、”}”或”[””]”時,則認為是一個完整的json對象或json數組

這些實現類,都只是將接收到的二進制數據解碼,轉成ByteBuf實例后直接交給之后的ChannelInboundHandler處理,并沒有將ByteBuf實例中的信息封裝到Java對象中,因為Netty并不清楚報文具體內容,以及需要封裝到哪個Java對象,所以需要自己手動來解析ByteBuf實例并封裝。

? 可以自定義一個解碼類繼承ByteToMessageDecoder抽象類,重寫它的decode方法:

protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

? 參數列表:

ByteBuf in:解碼前的二進制數據

List out:解碼后的有效報文列表,由于tcp可能出現的粘包問題,入參的in中可能含有多個有效報文,所以需要將解碼后的報文添加到List中,或者可能出現拆包,那么in中的數據就不足以構成一個有效報文,這時無需向List中添加元素。

? 解碼時需要尤其注意的是,應該先判斷是否能構成一整個有效報文,再調用ByteBuf的read方法來讀取數據,通過與in.readableBytes比較,來判斷in中可讀字節數是否大于約定的基本數據幀長度,只有在大于等于的情況下,我們才進行解碼,即讀取指定長度的字節,添加到List中。

4.1.2 抽象類MessageToMessageDecoder

? 用于將一個本身就包含完整報文信息的對象轉成另一個Java對象。

? ByteToMessageDecoder解碼后將包含了報文信息的ByteBuf實例交給后面的ChannelInboundHandler處理,此時可以在ChannelPipeline中再添加一個MessageToMessageDecoder,將ByteBuf中的信息解析后封裝到Java對象中,簡化接下來的ChannelInboundHandler操作。或者是要將已經封裝好的Java對象轉成其他Java對象,所以會出現MessageToMessageDecoder之后接著另一個MessageToMessageDecoder的情況。比如,Tomcat將瀏覽器發送過來的二進制數據解析為HttpServletRequest對象后,我們還需要將其中的數據提取出來封裝成自定義的POJO類,即將現有的Java對象(HttpServletRequest)轉換成另一個Java對象(POJO類)。

? 繼承MessageToMessageDecoder抽象類,也是要重寫它的decode方法:

protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;

? 參數列表:

I msg:配置需要進行解碼的參數

List out:經過MessageToMessageDecoder解析后,得到的Java對象存入列表

? 那么在ChannelPipieline中它們的處理順序如下:

ChannelPipieline ch=...
ch.addLast(new ByteToMessageDecoder());//ByteToMessageDecoder實現類
ch.addLast(new MessageToMessageDecoder());//MessageToMessageDecoder實現類
ch.addLast(new MessageToMessageDecoder());
...

 

? 需要注意的是,即便是指定MessageToMessageDecoder的傳入類型為ByteBuf,也絕對不可以用它來代替ByteToMessageDecoder報文解析的工作,因為ByteToMessageDecoder的內部設計才是針對接收到的二進制數據進行解碼,所以除了解碼,它其中還有對尚不完整的報文進行拆包緩存的功能邏輯,這是MessageToMessageDecoder所不具備的。

? 因此,通常會先用ByteToMessageDecoder解析報文以及粘拆包處理,得到完整有效的ByteBuf實例,之后再交由一個或多個MessageToMessageDecoder對ByteBuf實例中的數據進行解析并封裝成POJO類。

4.2 編碼器

? 相對應地,在ChannelOutboundHandler接口下,Netty也提供了MessageToByteEncoder和MessageToMessageEncoder兩個抽象類來完成編碼。沒有解碼器的內部邏輯復雜,編碼只要將數據轉成約定的二進制格式發送即可,而解碼器除了解析數據,還要處理粘拆包問題。

4.3 編碼解碼器Codec

? Codec同時具備編解碼功能,它同時實現了ChannelInboundHandler和ChannelOutboundHandler兩個接口,因此數據的輸入輸出都能處理。

? Netty提供了一個ChannelDuplexHandler適配器類,編解碼器的抽象基類ByteToMessageCodec和MessageToMessageCodec都繼承了它,整體繼承關系如下:

開源物聯網平臺Thingsboard——Netty實現與硬件設備通訊

 

? ByteToMessageCodec中維護了一個ByteToMessageDecoder和一個MessageToByteEncoder實例,結合二者的功能,泛型參數I可指定接受的編碼類型:

public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler {
    private final TypeParameterMatcher outboundMsgMatcher;
    private final MessageToByteEncoder<I> encoder;
    private final ByteToMessageDecoder decoder = new ByteToMessageDecoder(){…}
  
    ...
    protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;
    protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

 

MessageToMessageCodec中維護了一個MessageToMessageDecoder和一個 MessageToMessageEncoder實例,結合二者的功能,泛型參數INBOUND_IN和OUTBOUND_IN分別表示需要解碼和編碼的數據類型:一個簡單的總結:ByteToMessageCodec和MessageToMessageCodec中分別實現了字節和對象之間、對象和對象之間的編解碼。

分享到:
標簽:聯網
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定