前言:
当前小伙伴们对“netty encoder decoder”都比较着重,朋友们都想要分析一些“netty encoder decoder”的相关资讯。那么小编在网络上收集了一些关于“netty encoder decoder””的相关内容,希望你们能喜欢,大家快快来了解一下吧!在这里放一下自己对netty长度解码器的理解
想看netty自定义解码器讲解可以直接跳过我自定义的编解码器
开始写之前文章的netty+动态代理的项目的时候,刚开始自己在网上找了一些编码器和解码器的写法,(不完全是自定义,也用到了Kyro)自定义写了一套,直接发送你要发的实体对象,算是先理解一下编解码器的原理。
KyroMsgDecoder
public class KyroMsgDecoder extends ByteToMessageDecoder { public static final int HEAD_LENGTH = 4; private Kryo kryo = new Kryo(); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { if (in.readableBytes() < HEAD_LENGTH) { return; } in.markReaderIndex(); int dataLength = in.readInt(); if (dataLength < 0) { ctx.close(); } if (in.readableBytes() < dataLength) { in.resetReaderIndex(); return; } byte[] body = new byte[dataLength]; in.readBytes(body); Object o = convertToObject(body); out.add(o); } private Object convertToObject(byte[] body) { Input input = null; ByteArrayInputStream bais = null; try { bais = new ByteArrayInputStream(body); input = new Input(bais); return kryo.readObject(input, Student.class);//这是重点,这个Student就是我的实体类 } catch (KryoException e) { e.printStackTrace(); }finally{ IOUtils.closeQuietly(input); IOUtils.closeQuietly(bais); } return null; }}12345678910111213141516171819202122232425262728293031323334353637383940KyroMsgEncoder
public class KyroMsgEncoder extends MessageToByteEncoder<Student> { private Kryo kryo = new Kryo(); //encode的参数直接写成实体类类型。 @Override protected void encode(ChannelHandlerContext ctx, Student msg, ByteBuf out) throws Exception { byte[] body = convertToBytes(msg); int dataLength = body.length; out.writeInt(dataLength); out.writeBytes(body); } //这里也是 private byte[] convertToBytes(Student student) { ByteArrayOutputStream bos = null; Output output = null; try { bos = new ByteArrayOutputStream(); output = new Output(bos); kryo.writeObject(output, student); output.flush(); return bos.toByteArray(); } catch (KryoException e) { e.printStackTrace(); }finally{ IOUtils.closeQuietly(output); IOUtils.closeQuietly(bos); } return null; }}123456789101112131415161718192021222324252627282930313233
netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装重用。
在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。编解码器由两部分组成:编码器、解码器。
解码器:负责将消息从字节或其他序列形式转成指定的消息对象。
编码器:将消息对象转成字节或其他序列形式在网络上传输。
netty自带解码器
LineBasedFrameDecoder
LineBasedFrameDecoder是回车换行解码器,如果发送的消息以回车换行符结束标识,可以用LineBasedFrameDecoder进行解码。
@Overrideprotected void initChannel(SocketChannel arg) throws Exception {arg.pipeline().addLast(new LineBasedFrameDecoder(1024));arg.pipeline().addLast(new StringDecoder());arg.pipeline().addLast(new UserServerHandler());}123456
DelimiterBasedFrameDecoder
DelimiterBasedFrameDecoder是分隔符解码器,用户可以指定消息结束的分隔符,它可以自动选择分隔符。
@Overridepublic void initChannel(SocketChannel ch) throws Exception { ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,delimiter)); ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new UserServerHandler());}}12345678
FixedLengthFrameDecoder
FixedLengthFrameDecoder是固定长度解码器,它能够按照指定的长度对消息进行自动解码,开发者不需要考虑TCP的粘包/拆包等问题,网上说是很实用的。
LengthFieldBasedFrameDecoder(我用的解码器!!!)
Netty提供了LengthFieldBasedFrameDecoder,自动屏蔽TCP底层的拆包和粘包问题,只需要传入正确的参数,即可轻松解决“读半包“问题。
@Override protected void initChannel(SocketChannel ch) throws Exception { /*** maxFrameLength - 发送的数据包最大的长度 lengthFieldOffset - 长度域偏移量,长度域位于整个数据包字节数组中的下标 lengthFieldLength - 长度域自己的字节数长度 lengthAdjustment – 长度域的偏移量矫正。 如果长度域的值,还包含了其他域(如长度域自身)长度,那么值为:包长 - 长度域的值 – 长度域偏移 – 长度域长 initialBytesToStrip – 丢弃的起始字节数。丢弃处于有效数据前面的字节数量。 ***/ ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024,2,4,-4,6)); ch.pipeline().addLast(new StringDecoder(Charset.forName("UTF-8"))); ch.pipeline().addLast(new ClientHandler()); ch.pipeline().addLast(new StringEncoder()); }1234567891011121314