netty:netty自带四种Docoder解码器

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

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

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页