netty中的channelRead()与channelRead0()区别

版本定位:netty4.1.x

前言:在netty的api使用中,一般我们自定义处理器类的时候,会继承ChannelInboundHandlerAdapter或者SimpleChannelInboundHandler。而SimpleChannelInboundHandler是ChannelInboundHandlerAdapter的抽象子类,其中必须重写channelRead0抽象方法。看其方法源码:

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        boolean release = true;

        try {
            if (this.acceptInboundMessage(msg)) {
                this.channelRead0(ctx, msg);
            } else {
                release = false;
                ctx.fireChannelRead(msg);
            }
        } finally {
            if (this.autoRelease && release) {
                ReferenceCountUtil.release(msg);  // 自动释放接收的信息占用的资源
            }

        }

    }

channelRead0是在重写了父类的channelRead方法中调用的。

问题根源:

因为我们知道,当接收到数据的时候,会自动调用channelRead方法,那么这里重写的方法中明显最终会释放消息所占用的资源。而我们在重写channelRead0()方法的时候,有时场景需要处理接收的信息并发回给对端。比如:

@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
    // 接收到的数据后,处理原信息并返回给对端
    channelHandlerContext.channel().writeAndFlush(LocalDateTime.now() + "-" + msg);
    TimeUnit.MILLISECONDS.sleep(500);
}

而writeAndFlush()源码中的write()方法是异步执行的,若其正在处理 msg,而此时 SimpleChannelInboundHandler 中的 channelRead()方法执行完毕了,则会将 msg 给释放了。此时就会报错。所以有丢失资源的可能。那么要解决这里的问题,注意使用Api的场景即可。

解决方案:

  • 若对方没有向自己发送数据,则自定义处理器建议继承自ChannelInboundHandlerAdapter。因为若继承自 SimpleChannelInboundHandler 需要重写channelRead0()方法。而重写该方法的目的是对来自于对方的数据进行处理。因为对方根本就没有发送数据,所以也就没有必要重写 channelRead0()方法。
  • 若对方向自己发送了数据,而自己又需要将该数据再发送给对方,则自定义处理器建议继承自 ChannelInboundHandlerAdapter。因为 writeAndFlush()源码中的write()方法的执行是异步的,且SimpleChannelInboundHandler 中的 channelRead()方法会自动释放掉来自于对方的 msg。而使用ChannelInboundHandlerAdapter的channeRead()时,可以创建新的 ByteBuf 对象来存储响应数据,而不必担心消息的内存资源被提前释放。但是注意释放ByteBuf的内存资源,以免发生内存泄漏。代码如下:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
    // 强制转换为ByteBuf
    ByteBuf byteBuf = (ByteBuf) msg;
    try {
        // 处理接收到的消息,例如读取数据、解析等操作
        // ...

        // 释放ByteBuf的内存资源
        byteBuf.release();
    } catch (Exception e) {
        // 异常处理
    } finally {
        // 一般在finally块中确保资源被释放
        // 如果发生异常,也需要保证资源被释放
        // ...
    }
}

最后还是附上netty官网,知识源头~Netty: Home

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值