开发常见问题_Netty开发常见问题

717fea2bd1b8d33d0344b618d0fb7081.png
  • pipeline的添加是有顺序的,如果用到IdleStateHandler,它需要添加到第一个
channel.pipeline()
        .addLast(new IdleStateHandler(0, 0, 500, TimeUnit.MILLISECONDS))
        .addLast(new HttpServerCodec());
  • 如果handler继承自SimpleChannelInboundHandler,那么通过channelRead0在读取消息的时候是自动释放消息对象的,下面代码是SimpleChannelInboundHandler的处理过程
   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);
            }

        }

    }

    protected abstract void channelRead0(ChannelHandlerContext var1, I var2) throws Exception;
  • Netty的零拷贝带来高性能的同时,会带来对象释放的问题,需要开发者手动通过
ReferenceCountUtil.release();

释放,因为这些对象不是JVM堆内对象,垃圾回收程序不会自动回收这部分对象

  • 如果有多个自定义pipeline,需要通过
ctx.fireChannelRead();

进行消息传递,否则消息不会传递给下一层的pipeline

  • 由于大量JVM堆外对象的使用,极易出现内存泄露的问题,可以通过
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID);

这个设置,系统会捕捉内存泄露

  • 如果想实现定时执行任务,类似心跳的处理,可以使用IdleStateHandler,这个handler会根据配置的链接读写情况,按设定的时间定时执行,IdleStateHandler是时间轮算法实现,效率非常高,占用资源很少
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {

    if (evt instanceof IdleStateEvent) {
        IdleStateEvent event = (IdleStateEvent) evt;
        if (event.state() == IdleState.ALL_IDLE) {
   
        }
    } else {
        super.userEventTriggered(ctx, evt);
    }
}
  • 可以在下面的pipeline中实现协议解析
socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024 * 4000, 4, 4, 0, 0));
  • ByteBuf默认是使用PooledByteBufAllocator来实现的,不需要池化的场景用
Unpooled.copiedBuffer();
  • 回写数据的时候最好判断下channel状态以及是否可写,否则有可能写数据失败
if (ctx.channel().isActive() && ctx.channel().isWritable()) {
}
  • Netty在writeAndFlush是异步写入,如果需要查看是否成功,需要注册一个ChannelFutureListener,以便在操作完成时获得通知
channelFuture.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
        if (future.isSuccess()) {

        } else {

        }
    }
});
  • 定时任务的另一种实现
if(scheduledFuture == null){
     scheduledFuture = ctx.channel().eventLoop().scheduleAtFixedRate(new Runnable() {
         @Override
         public void run() {
             businessTask(ctx);
         }
     }, 0, 500, TimeUnit.MILLISECONDS);
}

如果需要停止定时任务,调用

if (scheduledFuture != null) {
    scheduledFuture.cancel(false);
}
  • 在pipeline内都是线程安全的,在某个pipeline内,不用考虑和并发的问题。最重要的一点,特别注意,不要在pipeline内执行耗时任务,否则eventLoop会被阻塞,造成其他连接对应的pipeline无法执行,切切切。标准的操作是把耗时任务丢给其他线程处理,等下个eventLoop再查询执行结果。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值