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

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

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

1.Netty的業(yè)務(wù)場(chǎng)景

? 平臺(tái)主要需求是和充電樁對(duì)接,并定時(shí)對(duì)設(shè)備進(jìn)行監(jiān)控檢查,需要使用Netty作為通信中間件來(lái)監(jiān)聽端口,充電樁通過(guò)TCP連接向服務(wù)端發(fā)送指令,后臺(tái)主要是通過(guò)netty的ChannelHandler來(lái)實(shí)現(xiàn)對(duì)硬件數(shù)據(jù)的接收和處理。

2. Netty的主要組件

2.1 Channel

? Channel作為Netty網(wǎng)絡(luò)通信的主體,可以看作是通訊的載體,主要有三個(gè)狀態(tài):打開、關(guān)閉、連接。

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

2.2 ChannelHandler

? 負(fù)責(zé)Channel中的邏輯處理,可針對(duì)性地?cái)r截處理Channel負(fù)責(zé)的IO操作或事件,然后在它的ChannelPipeline中將其遞交給下一個(gè)handler。ChannelHandler中有許多方法需要實(shí)現(xiàn),一般通過(guò)繼承ChannelHandlerAdapter來(lái)實(shí)現(xiàn)。

開源物聯(lián)網(wǎng)平臺(tái)Thingsboard——Netty實(shí)現(xiàn)與硬件設(shè)備通訊

 

2.3 ChannelPipeline

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

開源物聯(lián)網(wǎng)平臺(tái)Thingsboard——Netty實(shí)現(xiàn)與硬件設(shè)備通訊

 

 

? ChannelPipeline相當(dāng)于ChannelHandler的容器,channel事件消息在ChannelPipeline中傳播流動(dòng),而ChannelHandler可以針對(duì)性地對(duì)事件進(jìn)行攔截處理、傳遞、忽略或者終止。一個(gè)ChannelHandler會(huì)綁定一個(gè)ChannelHandlerContext對(duì)象,ChannelHandler會(huì)通過(guò)與其對(duì)應(yīng)的Context對(duì)象和ChannelPipeline交互,比如向上或向下傳遞events,動(dòng)態(tài)地修改ChannelPipeline,或者通過(guò)ChannelHandlerContext中的AttributeKeys存儲(chǔ)與handler相關(guān)的信息。

3. Netty服務(wù)端的啟動(dòng)

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

 

4. Netty中的編解碼

4.1 解碼器

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

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

開源物聯(lián)網(wǎng)平臺(tái)Thingsboard——Netty實(shí)現(xiàn)與硬件設(shè)備通訊

 

4.1.1 抽象類ByteToMessageDecoder

? 用于將接收的二進(jìn)制數(shù)據(jù)(Byte)解碼,得到完整有效的請(qǐng)求報(bào)文(Message)。

? 一般ByteToMessageDecoder解碼內(nèi)容后,會(huì)得到一個(gè)ByteBuf實(shí)例,每個(gè)ByteBuf實(shí)例都包含了一個(gè)完整的報(bào)文信息。可以直接把這些ByteBuf實(shí)例交給之后的ChannelInboundHandler處理,或?qū)yteBuf實(shí)例解析封裝到不同的JAVA實(shí)例對(duì)象后,再交給它處理。不管哪一種情況,之后的ChannelInboundHandler在處理時(shí)不需要再考慮粘包、拆包問(wèn)題。

? ByteToMessageDecoder中常見(jiàn)的實(shí)現(xiàn)類:

FixedLengthFrameDecoder:定長(zhǎng)協(xié)議解碼器,可以指定固定字節(jié)數(shù)算一個(gè)完整報(bào)文

LineBasedFrameDecoder:行分隔符解碼器,遇到n或者rn,則認(rèn)為是一個(gè)完整的報(bào)文

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

LengthFieldBasedFrameDecoder:長(zhǎng)度編碼解碼器,將報(bào)文劃分為報(bào)文頭/報(bào)文體,根據(jù)報(bào)文頭中的Length字段確定報(bào)文體的長(zhǎng)度,因此報(bào)文體的長(zhǎng)度是可變的

JsonObjectDecoder:json格式解碼器,當(dāng)檢測(cè)到匹配數(shù)量的"{" 、”}”或”[””]”時(shí),則認(rèn)為是一個(gè)完整的json對(duì)象或json數(shù)組

這些實(shí)現(xiàn)類,都只是將接收到的二進(jìn)制數(shù)據(jù)解碼,轉(zhuǎn)成ByteBuf實(shí)例后直接交給之后的ChannelInboundHandler處理,并沒(méi)有將ByteBuf實(shí)例中的信息封裝到Java對(duì)象中,因?yàn)镹etty并不清楚報(bào)文具體內(nèi)容,以及需要封裝到哪個(gè)Java對(duì)象,所以需要自己手動(dòng)來(lái)解析ByteBuf實(shí)例并封裝。

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

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

? 參數(shù)列表:

ByteBuf in:解碼前的二進(jìn)制數(shù)據(jù)

List out:解碼后的有效報(bào)文列表,由于tcp可能出現(xiàn)的粘包問(wèn)題,入?yún)⒌膇n中可能含有多個(gè)有效報(bào)文,所以需要將解碼后的報(bào)文添加到List中,或者可能出現(xiàn)拆包,那么in中的數(shù)據(jù)就不足以構(gòu)成一個(gè)有效報(bào)文,這時(shí)無(wú)需向List中添加元素。

? 解碼時(shí)需要尤其注意的是,應(yīng)該先判斷是否能構(gòu)成一整個(gè)有效報(bào)文,再調(diào)用ByteBuf的read方法來(lái)讀取數(shù)據(jù),通過(guò)與in.readableBytes比較,來(lái)判斷in中可讀字節(jié)數(shù)是否大于約定的基本數(shù)據(jù)幀長(zhǎng)度,只有在大于等于的情況下,我們才進(jìn)行解碼,即讀取指定長(zhǎng)度的字節(jié),添加到List中。

4.1.2 抽象類MessageToMessageDecoder

? 用于將一個(gè)本身就包含完整報(bào)文信息的對(duì)象轉(zhuǎn)成另一個(gè)Java對(duì)象。

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

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

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

? 參數(shù)列表:

I msg:配置需要進(jìn)行解碼的參數(shù)

List out:經(jīng)過(guò)MessageToMessageDecoder解析后,得到的Java對(duì)象存入列表

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

ChannelPipieline ch=...
ch.addLast(new ByteToMessageDecoder());//ByteToMessageDecoder實(shí)現(xiàn)類
ch.addLast(new MessageToMessageDecoder());//MessageToMessageDecoder實(shí)現(xiàn)類
ch.addLast(new MessageToMessageDecoder());
...

 

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

? 因此,通常會(huì)先用ByteToMessageDecoder解析報(bào)文以及粘拆包處理,得到完整有效的ByteBuf實(shí)例,之后再交由一個(gè)或多個(gè)MessageToMessageDecoder對(duì)ByteBuf實(shí)例中的數(shù)據(jù)進(jìn)行解析并封裝成POJO類。

4.2 編碼器

? 相對(duì)應(yīng)地,在ChannelOutboundHandler接口下,Netty也提供了MessageToByteEncoder和MessageToMessageEncoder兩個(gè)抽象類來(lái)完成編碼。沒(méi)有解碼器的內(nèi)部邏輯復(fù)雜,編碼只要將數(shù)據(jù)轉(zhuǎn)成約定的二進(jìn)制格式發(fā)送即可,而解碼器除了解析數(shù)據(jù),還要處理粘拆包問(wèn)題。

4.3 編碼解碼器Codec

? Codec同時(shí)具備編解碼功能,它同時(shí)實(shí)現(xiàn)了ChannelInboundHandler和ChannelOutboundHandler兩個(gè)接口,因此數(shù)據(jù)的輸入輸出都能處理。

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

開源物聯(lián)網(wǎng)平臺(tái)Thingsboard——Netty實(shí)現(xiàn)與硬件設(shè)備通訊

 

? ByteToMessageCodec中維護(hù)了一個(gè)ByteToMessageDecoder和一個(gè)MessageToByteEncoder實(shí)例,結(jié)合二者的功能,泛型參數(shù)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中維護(hù)了一個(gè)MessageToMessageDecoder和一個(gè) MessageToMessageEncoder實(shí)例,結(jié)合二者的功能,泛型參數(shù)INBOUND_IN和OUTBOUND_IN分別表示需要解碼和編碼的數(shù)據(jù)類型:一個(gè)簡(jiǎn)單的總結(jié):ByteToMessageCodec和MessageToMessageCodec中分別實(shí)現(xiàn)了字節(jié)和對(duì)象之間、對(duì)象和對(duì)象之間的編解碼。

分享到:
標(biāo)簽:聯(lián)網(wǎng)
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定