Netty中ByteBuf遇到问题

记录一下此次在使用Netty进行RPC的调用过程中遇到的问题,自己实现的一个作业分发的RPC框架。主要有两个角色进程:

JobManager:负责客户端作业的提交管理、解析作业信息形成一张作业图分发到相应的TaskManager下执行。

TaskManager:与JobManager通信,启动的时候自动注册到JobManager,并发送心跳到角色jm中,启动后加载相关的TaskExecutor的实现的插件,通过java的ServiceLoad方式加载。

遇到的问题是:发现客户端发送作业到JobManager后,jm解析作业生成的Task的信息提交到tm的时候序列化后的字节较大,超过2048字节。这样的话在解析器NettyDecode解析提交的任务信息时会出现第一次读取ByteBuf中的字节时超过了2048,出现异常信息:

java.lang.IndexOutOfBoundsException: readerIndex(4) + length(2301) exceeds writerIndex(2048): %s

后来网上疯狂的查资料博客帖子啥的找的方法也没有解决我的问题,但是提供了思路,猜测是传输量大的数据时应该会发生分包发送的情况,推测我这遇到的情况应该是数据也被分包发了,于是在NettyDecode中进行断点发现接受的数据长度应该为2301,但当前的ByteBuf中的大小最大为2048,所以在read的时候出现IndexOutOfBoundsException异常。

后边查资料和代码调试发现ButeBuf的缓冲区是可以动态根据上次传输的数据大小来进行下次扩容的,但是当前这一次读取的数据是有限的不完整的,即实际数据大小为2301,此次读取的最多2048个字节。

解决的方案是当前读取的数据不进行解码处理,等待下一次再次解码时重新从ByteBuf中读取即可。参考代码如下:

编码器NettyEncode

public class NettyEncoder extends MessageToByteEncoder<Object> {

    @Override
    protected void encode(
            ChannelHandlerContext context,
            Object message,
            ByteBuf byteBuf) throws Exception {
        HessianSerializer serializer = new HessianSerializer();
        byte[] data = serializer.serialize(message);
        int dataLength = data.length;
        byteBuf.writeInt(dataLength);
        byteBuf.writeBytes(data);
    }

}

修改前的解码器

public class NettyDecoder extends ByteToMessageDecoder {

    private final Class<?> genericClass;

    public NettyDecoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    protected void decode(
            ChannelHandlerContext context,
            ByteBuf byteBuf,
            List<Object> list) throws Exception {
        int dataLength = byteBuf.readInt();
        if (dataLength < 0) {
            context.close();
        }

        byte[] data = new byte[dataLength];
        byteBuf.readBytes(data);

        HessianSerializer serializer = new HessianSerializer();
//        Serializer serializer = RpcSerializer.getSerializerByType((byte) 1);
        Object object = serializer.deserialize(data, genericClass);
        list.add(object);
    }

}

修改后的解码器

public class NettyDecoder extends ByteToMessageDecoder {

    private final Class<?> genericClass;

    public NettyDecoder(Class<?> genericClass) {
        this.genericClass = genericClass;
    }

    @Override
    protected void decode(
            ChannelHandlerContext context,
            ByteBuf byteBuf,
            List<Object> list) throws Exception {
        int dataLength = byteBuf.readInt();
        if (dataLength < 0) {
            context.close();
        }
        
        int readableBytes = byteBuf.readableBytes();
        if (dataLength > readableBytes) {
            // 待读取的数据长度大于当前ByteBuf中的数据时,
            // 将reader index读取的游标置为初始值0的位置,下次重新开始读取
            byteBuf.resetReaderIndex();
        } else {
            byte[] data = new byte[dataLength];
            byteBuf.readBytes(data);
        
            HessianSerializer serializer = new HessianSerializer();
            Object object = serializer.deserialize(data, genericClass);
            list.add(object);
        }
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
NettyByteBuf是一个可扩展的字节容器,它提供了一系列的API来方便地读取和写入字节数据。下面是一些常见的ByteBuf使用API: 1. 创建ByteBuf对象 可以使用Unpooled工具类来创建ByteBuf对象,例如: ```java ByteBuf buf = Unpooled.buffer(10); ``` 上面的代码创建了一个容量为10的ByteBuf对象。 2. 写入数据 可以使用write方法向ByteBuf写入数据,例如: ```java buf.writeByte(1); buf.writeShort(2); buf.writeInt(3); buf.writeLong(4); buf.writeFloat(5.0f); buf.writeDouble(6.0); buf.writeBytes("hello".getBytes()); ``` 上面的代码依次向ByteBuf写入了一个字节、一个短整型、一个整型、一个长整型、一个单精度浮点数、一个双精度浮点数和一个字符串。 3. 读取数据 可以使用read方法从ByteBuf读取数据,例如: ```java byte b = buf.readByte(); short s = buf.readShort(); int i = buf.readInt(); long l = buf.readLong(); float f = buf.readFloat(); double d = buf.readDouble(); byte[] bytes = new byte[5]; buf.readBytes(bytes); String str = new String(bytes); ``` 上面的代码依次从ByteBuf读取了一个字节、一个短整型、一个整型、一个长整型、一个单精度浮点数、一个双精度浮点数和一个字符串。 4. 获取可读字节数 可以使用可读字节数方法来获取当前ByteBuf可读的字节数,例如: ```java int readableBytes = buf.readableBytes(); ``` 5. 释放ByteBuf 使用完ByteBuf对象后,需要手动调用release方法释放对象,例如: ```java buf.release(); ``` 上面的代码释放了ByteBuf对象,释放后的ByteBuf不能再被使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值