詳解Netty編碼器和解碼器
一、java的編解碼
1.編碼(Encode)稱為序列化, 它將對(duì)象序列化為字節(jié)數(shù)組,用于網(wǎng)絡(luò)傳輸、數(shù)據(jù)持久化或者其它 用途。
2.解碼(Decode)稱為反序列化,它把從網(wǎng)絡(luò)、磁盤等讀取的字節(jié)數(shù)組還原成原始對(duì)象(通常是原 始對(duì)象的拷貝),以方便后續(xù)的業(yè)務(wù)邏輯操作。
java序列化對(duì)象只需要實(shí)現(xiàn)java.io.Serializable接口并生成序列化ID,這個(gè)類就能夠通過(guò) java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
java序列化對(duì)象只需要實(shí)現(xiàn)java.io.Serializable接口并生成序列化ID,這個(gè)類就能夠通過(guò) java.io.ObjectInput和java.io.ObjectOutput序列化和反序列化。
Java序列化目的:1.網(wǎng)絡(luò)傳輸。2.對(duì)象持久化。
Java序列化缺點(diǎn):1.無(wú)法跨語(yǔ)言。 2.序列化后碼流太大。3.序列化性能太低。
Java序列化僅僅是Java編解碼技術(shù)的一種,由于它的種種缺陷,衍生出了多種編解碼技術(shù)和框 架,這些編解碼框架實(shí)現(xiàn)消息的高效序列化。
二、Netty編解碼器
概念:在網(wǎng)絡(luò)應(yīng)用中需要實(shí)現(xiàn)某種編解碼器,將原始字節(jié)數(shù)據(jù)與自定義的消息對(duì)象進(jìn)行互相轉(zhuǎn)換。網(wǎng)絡(luò)中都是以字節(jié)碼的數(shù)據(jù)形式來(lái)傳輸數(shù)據(jù)的,服務(wù)器編碼數(shù)據(jù)后發(fā)送到客戶端,客戶端需要對(duì)數(shù)據(jù)進(jìn)行解碼。
對(duì)于Netty而言,編解碼器由兩部分組成:編碼器、解碼器
- 解碼器:負(fù)責(zé)將消息從字節(jié)或其他序列形式轉(zhuǎn)成指定的消息對(duì)象。
- 編碼器:將消息對(duì)象轉(zhuǎn)成字節(jié)或其他序列形式在網(wǎng)絡(luò)上傳輸。
Netty 的編(解)碼器實(shí)現(xiàn)了 ChannelHandlerAdapter,也是一種特殊的 ChannelHandler,所 以依賴于 ChannelPipeline,可以將多個(gè)編(解)碼器鏈接在一起,以實(shí)現(xiàn)復(fù)雜的轉(zhuǎn)換邏輯。
Netty里面的編解碼: 解碼器:負(fù)責(zé)處理“入站 InboundHandler”數(shù)據(jù)。 編碼器:負(fù)責(zé)“出站 OutboundHandler” 數(shù)據(jù)。
入棧解碼,出棧編碼:
2.1 解碼器(Decoder)
解碼器負(fù)責(zé) 解碼“入站”數(shù)據(jù)從一種格式到另一種格式,解碼器處理入站數(shù)據(jù)是抽象 ChannelInboundHandler的實(shí)現(xiàn)。需要將解碼器放在ChannelPipeline中。對(duì)于解碼器,Netty中主要提供了抽象基類ByteToMessageDecoder和MessageToMessageDecoder。
抽象解碼器
ByteToMessageDecoder: 用于將字節(jié)轉(zhuǎn)為消息,需要檢查緩沖區(qū)是否有足夠的字節(jié)
ReplayingDecoder: 繼承ByteToMessageDecoder,不需要檢查緩沖區(qū)是否有足夠的字節(jié),但 是 ReplayingDecoder速度略慢于ByteToMessageDecoder,同時(shí)不是所有的ByteBuf都支持。 項(xiàng)目復(fù)雜性高則使用ReplayingDecoder,否則使用ByteToMessageDecoder
MessageToMessageDecoder: 用于從一種消息解碼為另外一種消息(例如POJO到POJO)
核心方法
decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out)
2.2 代碼實(shí)現(xiàn)
MessageDecoder
package com.my.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息解碼器 */ public class MessageDecoder extends MessageToMessageDecoder { @Override protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("正在進(jìn)行消息解碼...."); ByteBuf byteBuf = (ByteBuf) msg; out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個(gè)handler } }
NettyServerHandler
nettyServerHandler 實(shí)現(xiàn)ChannelInboundHandler, 重新若干方法。
通道讀取方法:
/** * 通道讀取事件 * * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("客戶端發(fā)送過(guò)來(lái)的消息:" + msg); }
服務(wù)端在接收客戶端的消息時(shí),首先會(huì)經(jīng)過(guò)MessageDecoder編碼器,將字節(jié)變?yōu)樽址?,因此,在此處可直接輸出?/p>
NettyServer
serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, Boolean.TRUE) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //添加解碼器 ch.pipeline().addLast("messageDecoder", new MessageDecoder()); //向pipeline中添加自定義業(yè)務(wù)處理handler ch.pipeline().addLast(new NettyServerHandler()); } });
在pipeline中添加解碼器
2.3 編碼器(Encoder)
與ByteToMessageDecoder和MessageToMessageDecoder相對(duì)應(yīng),Netty提供了對(duì)應(yīng)的編碼器 實(shí)現(xiàn)MessageToByteEncoder和MessageToMessageEncoder,二者都實(shí)現(xiàn) ChannelOutboundHandler接口。
抽象編碼器
MessageToByteEncoder: 將消息轉(zhuǎn)化成字節(jié)MessageToMessageEncoder: 用于從一種消息編碼為另外一種消息(例如POJO到POJO)
核心方法:
encode(ChannelHandlerContext ctx, String msg, List<Object> out)
2.4 代碼實(shí)現(xiàn)
MessageEncoder
package com.my.codec; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息的編碼器 */ public class MessageEncoder extends MessageToMessageEncoder { @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("消息正在進(jìn)行編碼...."); String str = (String) msg; out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8)); } }
NettyClientHandler
/** * 通道就緒事件 * * @param ctx * @throws Exception */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ChannelFuture future = ctx.writeAndFlush("你好呀.我是Netty客戶端"); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { System.out.println("數(shù)據(jù)發(fā)送成功!"); } else { System.out.println("數(shù)據(jù)發(fā)送失敗!"); } } }); } /** * 通道讀就緒事件 * * @param ctx * @param msg * @throws Exception */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("服務(wù)端發(fā)送的消息:" + msg); }
當(dāng)客戶端通道準(zhǔn)備就緒時(shí),會(huì)向服務(wù)端發(fā)送 “你好呀.我是Netty客戶端”,由于出棧是逆序的,因此,直接傳入字符串,當(dāng)出棧時(shí),會(huì)經(jīng)過(guò)編碼器(在nettyclient中添加的)
NettyClient
bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //添加解碼器 ch.pipeline().addLast("messageDecoder", new MessageDecoder()); //添加編碼器 ch.pipeline().addLast("messageEncoder", new MessageEncoder()); //向pipeline中添加自定義業(yè)務(wù)處理handler ch.pipeline().addLast(new NettyClientHandler()); } });
同時(shí),在NettyServerHandler 中也添加相同的編解碼器。
因?yàn)槭请p向通信,因此,在服務(wù)端和客戶端的pipeline中均需要添加編解碼器。
2.5 測(cè)試結(jié)果
服務(wù)端打?。?/p>
客戶端打印:
三、編碼解碼器Codec
編碼解碼器:
同時(shí)具有編碼與解碼功能,特點(diǎn)同時(shí)實(shí)現(xiàn)了ChannelInboundHandler和 ChannelOutboundHandler接口,因此在數(shù)據(jù)輸入和輸出時(shí)都能進(jìn)行處理。
Netty提供提供了一個(gè)ChannelDuplexHandler適配器類,編碼解碼器的抽象基類
ByteToMessageCodec ,MessageToMessageCodec都繼承與此類
3.1 代碼實(shí)現(xiàn):
package com.my.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; import io.netty.util.CharsetUtil; import java.util.List; /** * 消息編解碼器 */ public class MessageCodec extends MessageToMessageCodec { /** * 編碼 * * @param ctx * @param msg * @param out * @throws Exception */ @Override protected void encode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("消息正在進(jìn)行編碼...."); String str = (String) msg; out.add(Unpooled.copiedBuffer(str, CharsetUtil.UTF_8)); } /** * 解碼 * * @param ctx * @param msg * @param out * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, Object msg, List out) throws Exception { System.out.println("正在進(jìn)行消息解碼...."); ByteBuf byteBuf = (ByteBuf) msg; out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個(gè)handler } }
NettyServer、NettyClient
在NettyServer和NettyClient中添加
ch.pipeline().addLast(new MessageCodec()); //8. 向pipeline中添加自定義業(yè)務(wù)處理handler ch.pipeline().addLast(new NettyServerHandler());
eBuf = (ByteBuf) msg;
out.add(byteBuf.toString(CharsetUtil.UTF_8));//傳遞到下一個(gè)handler
}
}
ch.pipeline().addLast(new MessageCodec()); //8. 向pipeline中添加自定義業(yè)務(wù)處理handler ch.pipeline().addLast(new NettyServerHandler());
測(cè)試結(jié)果與1.2.5測(cè)試結(jié)果一致
到此這篇關(guān)于詳解Netty編碼器和解碼器的文章就介紹到這了,更多相關(guān)Netty編解碼器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot實(shí)戰(zhàn)之靜態(tài)資源處理
這篇文章主要介紹了Spring Boot實(shí)戰(zhàn)之靜態(tài)資源處理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01基于Springboot的高校社團(tuán)管理系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)
本文將基于Springboot+Mybatis開發(fā)實(shí)現(xiàn)一個(gè)高校社團(tuán)管理系統(tǒng),系統(tǒng)包含三個(gè)角色:管理員、團(tuán)長(zhǎng)、會(huì)員。文中采用的技術(shù)有Springboot、Mybatis、Jquery、AjAX、JSP等,感興趣的可以了解一下2022-07-07徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Dr
這篇文章給大家介紹了如如何徹底解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問(wèn)題,文中有詳細(xì)的解決思路以及解決方法,需要的朋友可以參考下2023-11-11Java中switch判斷語(yǔ)句典型使用實(shí)例
這篇文章主要介紹了Java中switch判斷語(yǔ)句典型使用實(shí)例,本文直接給出代碼實(shí)例,在忘記switch語(yǔ)法時(shí)特別有用,復(fù)制修改即可使用,需要的朋友可以參考下2015-06-06Spring Gateway處理微服務(wù)的路由轉(zhuǎn)發(fā)機(jī)制
我們?cè)敿?xì)地介紹了Spring Gateway,這個(gè)基于Spring 5、Spring Boot 2和Project Reactor的API網(wǎng)關(guān),通過(guò)這篇文章,我們可以清晰地看到Spring Gateway的工作原理,以及它的強(qiáng)大之處,感興趣的朋友一起看看吧2024-08-08字節(jié)二面SpringBoot可以同時(shí)處理多少請(qǐng)求
這篇文章主要為大家介紹了字節(jié)二面之SpringBoot可以同時(shí)處理多少請(qǐng)求面試分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07