欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

netty:netty自带四种Docoder解码器

程序员文章站 2022-04-10 19:37:33
在这里放一段自己对长度解码器的理解netty自带解码器LineBasedFrameDecoderLineBasedFrameDecoder是回车换行解码器,如果发送的消息以回车换行符结束标识,可以用LineBasedFrameDecoder进行解码。@Overrideprotected void initChannel(SocketChannel arg) throws Exception {arg.pipeline().addLast(new LineBasedFrameDecoder(102...

在这里放一下自己对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;
    }
}

KyroMsgEncoder

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;
    }
}

netty提供了强大的编解码器框架,使得我们编写自定义的编解码器很容易,也容易封装重用。

在网络应用中需要实现某种编解码器,将原始字节数据与自定义的消息对象进行互相转换。网络中都是以字节码的数据形式来传输数据的,服务器编码数据后发送到客户端,客户端需要对数据进行解码。编解码器由两部分组成:编码器、解码器。

解码器:负责将消息从字节或其他序列形式转成指定的消息对象。
编码器:将消息对象转成字节或其他序列形式在网络上传输。

netty自带解码器

LineBasedFrameDecoder
LineBasedFrameDecoder是回车换行解码器,如果发送的消息以回车换行符结束标识,可以用LineBasedFrameDecoder进行解码。

@Override
protected void initChannel(SocketChannel arg) throws Exception {
arg.pipeline().addLast(new LineBasedFrameDecoder(1024));
arg.pipeline().addLast(new StringDecoder());
arg.pipeline().addLast(new UserServerHandler());
}

DelimiterBasedFrameDecoder
DelimiterBasedFrameDecoder是分隔符解码器,用户可以指定消息结束的分隔符,它可以自动选择分隔符。

@Override
public 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());
}
}

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());
    }

学习时,看的一些厉害博主:好一个大布丁 (有部分是从他的一片文章参考的)

还有另外一个博主的文章:https://blog.csdn.net/u010853261/article/details/54575626

有帮助的话,来个三连吧!!!

本文地址:https://blog.csdn.net/wyyzy0420/article/details/110188295