Netty 的 inbound 与 outbound, 以及 InboundHandler 的 channelInactive 与 OutboundHandler 的 close

先看一个例子.promise

有一个简单 Serversocket

public class SimpleServer {

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

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_REUSEADDR, true)
                .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new SimpleDuplex1());
                        ch.pipeline().addLast(new SimpleDuplex2());
                        ch.pipeline().addLast(new SimpleServerHandler());
                    }
                });
        b.bind(8090).sync().channel().closeFuture().sync();
    }
}

Handler 详情以下ide

public class SimpleDuplex1 extends ChannelDuplexHandler {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("---- write 1 ----");
        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("---- read 1 ----");
        super.channelRead(ctx, msg);
    }
}

public class SimpleDuplex2 extends ChannelDuplexHandler {

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("---- write 2 ----");
        super.write(ctx, msg, promise);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("---- read 2 ----");
        super.channelRead(ctx, msg);
    }
}
public class SimpleServerHandler extends ChannelDuplexHandler {

    @Override
    public void channelRead(ChannelHandlerContext ctx, final Object msg) throws Exception {
        ctx.channel().writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("OK".getBytes())).addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("----- INACTIVE -----");
        super.channelInactive(ctx);
    }

    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise future) throws Exception {
        System.out.println("----- CLOSE -----");
        super.close(ctx, future);
    }
}

启动 Server 之后, 使用 telnet 发送数据查看执行结果oop

---- read 1 ----
---- read 2 ----
成功
---- write 2 ----
---- write 1 ----
----- CLOSE -----
----- INACTIVE -----

1. 先来看看执行顺序, 可见, inbound 的顺序是跟 add 顺序一致的, 而 outbound 的顺序是跟 add 顺序相反的spa

以及, read 的 IO 触发顺序是 "socketChannel.read() -> 顺序 handler -> TailContext.channelRead().releaseMsg"debug

而 write 的 IO 触发顺序是 "逆序 handler -> HeadContext.socketChannel.write()"code

也就是说 read 是先触发 socket 的 read IO 时间, 再进入 handler, 而若是咱们最后一个 handler 未能彻底处理消息, 调用了 super.channelRead, 则会进入 TailContext. 此时TailContext 会打出 debug 消息告诉你消息进入了最后一个 Handler 而未被处理. 由于通常来说都应该在本身的 handler 里把消息处理掉. 而不是让他进入到默认 handler 里.blog

而对于 write 来讲, 则是先进入自定义 handler, 最后在进入 HeadContext 触发 IO 时间事件

2. 再来讲说 close 与 channelInactiveip

前面说到了. Outbound 的顺序是最后才执行到 HeadContext 来执行实际的 IO 操做, close 也是同样, 当你调用 channle.close 的时候, 先会通过你的 handler . 最后调用 HeadContext.socketChannel.close(). 因此, 在咱们的 Handler 中, 先会打印 "---- CLOSE ----" 而后再调用实际的 socketChannel.close. 最后, 当 close 成功时, 触发 ChannelInactive 时间.

因此说 close 与 channelInactive 的关系是 close 是主动关闭 channel 的动做, 而 channelInactive 是关闭成功后收到通知的事件.

相关文章
相关标签/搜索