Bootstrap

netty channelReadComplete和channelRead执行时机

先说结论:
当收到一个完整的应用层消息报文,channelRead会被触发一次。每次读取完Socket的接收缓冲区的报文,channelReadComplete会被触发一次。

实际中都会使用编码器。

  1. 比如定长解码器,规定5个字节是一个完整的消息。
    那么客户端发送了4字节,服务端收到后,计算长度是4,就不需要读取,缓存区待着就好了,等下次有新数据来了我再判断,此时没有触发channelReadComplete。
    后续客户端在发送,如果达到了5,服务端才会去读取,此时channelRead和channelReadComplete都会触发。
  2. 对于分隔符解码器,服务端收到了必须先读取缓冲区才能知道是不是分隔符,所以发一次,服务端就读一次,自然channelReadComplete执行次数大于channelRead了。

下面贴一个代码,可以自行验证。

public class MyServer {
    public static void main(String[] args) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new DelimiterBasedFrameDecoder(1024,
                                            Unpooled.wrappedBuffer("#".getBytes())))
                                    .addLast(new ServerHandler());
                        }
                    });
            ChannelFuture channelFuture = bootstrap.bind(6666).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
class ServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
        System.out.println("server channelRead :" + msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        System.out.println("server channelReadComplete");
    }
}

客户端

    public static void main(String[] args) throws Exception {
        test();
    }

    private static void test() throws InterruptedException {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(eventExecutors)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.SO_SNDBUF, 5)
                .option(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP, false)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline()
                                .addLast(new DelimiterBasedFrameDecoder(1024,
                                        Unpooled.wrappedBuffer("#".getBytes())));
                    }
                }).remoteAddress("127.0.0.1", 6666);
        ChannelFuture future = bootstrap.connect();
        Channel channel = future.sync().channel();

		//分隔符编码器
        // 先发送4字节,服务端socke读取后,调用channelReadComplete方法。
        // 第二次发送5字节,并带上结束符。服务端先channelRead,然后再调用channelReadComplete
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(6);
        buffer.writeBytes(new byte[]{1, 2, 3, 4});
        channel.writeAndFlush(buffer).addListener(future1 -> {
            System.out.println("success");
        });

        ByteBuf buffer1 = ByteBufAllocator.DEFAULT.buffer(6);
        buffer1.writeBytes(new byte[]{1, 2, 3, 4,'#'});
        channel.writeAndFlush(buffer1).addListener(future1 -> {
            System.out.println("success");
        });
    }
}

参考:netty进阶指南-李林峰

本文作者:WKP9418
本文连接:https://blog.csdn.net/qq_43179428/article/details/140578855

;