先看一个例子.

有一个简单 Server

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 详情如下

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 发送数据查看执行结果

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

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

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

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

也就是说 read 是先触发 socket 的 read IO 时间, 再进入 handler, 而如果我们最后一个 handler 未能完全处理消息, 调用了 super.channelRead, 则会进入 TailContext. 此时TailContext 会打出 debug 消息告诉你消息进入了最后一个 Handler 而未被处理. 因为一般来讲都应该在自己的 handler 里把消息处理掉. 而不是让他进入到默认 handler 里.

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

2. 再来说说 close 与 channelInactive

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

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

Netty 的 inbound 与 outbound, 以及 InboundHandler 的 channelInactive 与 OutboundHandler 的 close的更多相关文章

  1. pcie inbound、outbound及EP、RC间的互相訪问

    Inbound:PCI域訪问存储器域 Outbound:存储器域訪问PCI域 RC訪问EP: RC存储器域->outbound->RC PCI域->EP PCI域->inbou ...

  2. netty中的Channel、ChannelPipeline

    一.Channel与ChannelPipeline关系 每一个新创建的 Channel 都将会被分配一个新的 ChannelPipeline.这项关联是永久性 的:Channel 既不能附加另外一个 ...

  3. netty中的引导Bootstrap客户端

    一.Bootstrap Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化.下面我以 Netty 源码例子中的 E ...

  4. Netty版本升级血泪史之线程篇

    1. 背景 1.1. Netty 3.X系列版本现状 根据对Netty社区部分用户的调查,结合Netty在其它开源项目中的使用情况,我们可以看出目前Netty商用的主流版本集中在3.X和4.X上,其中 ...

  5. netty源码学习

    概述 Netty is an asynchronous event-driven network application framework for rapid development of main ...

  6. Pipeline inbound(netty源码7)

    netty源码死磕7  Pipeline 入站流程详解 1. Pipeline的入站流程 在讲解入站处理流程前,先脑补和铺垫一下两个知识点: (1)如何向Pipeline添加一个Handler节点 ( ...

  7. 【Netty】(8)---理解ChannelPipeline

    ChannelPipeline ChannelPipeline不是单独存在,它肯定会和Channel.ChannelHandler.ChannelHandlerContext关联在一起,所以有关概念这 ...

  8. Netty 核心组件 Pipeline 源码分析(一)之剖析 pipeline 三巨头

    目录大纲: 前言 ChannelPipeline | ChannelHandler | ChannelHandlerContext 三巨头介绍 三巨头编织过程(创建过程) ChannelPipelin ...

  9. Netty源码分析第4章(pipeline)---->第1节: pipeline的创建

    Netty源码分析第四章: pipeline 概述: pipeline, 顾名思义, 就是管道的意思, 在netty中, 事件在pipeline中传输, 用户可以中断事件, 添加自己的事件处理逻辑, ...

随机推荐

  1. Asp.net core 通过Models 生成数据库的方法

        其实Getting Started当中有着详细的说明,https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html ...

  2. js面向对象的实现(example 一)

    //通过函数原型链(prototype)的方式来构造对象 //通过闭包的方式来对元素类进行封装 //通过函数原型链的方式来构造对象的方法和类的继承 //通过以上步骤就可以用函数的形式来实现类的,封装, ...

  3. 在SQL SERVER中根据某字段分隔符将记录分成多条记录

    XT_RSGL_KQSZ_LS表结构如下图: CREATE TABLE  XT_RSGL_KQSZ_LS( KQFW VARCHAR(400) ) 其中KQFW字段以分割符 , 隔开 INSERT I ...

  4. WKWebView _WebFilterIsActive returning: NO

    写这篇文是因为在UIWebView加载页面的时候有时候会返回: filterBlacklist = ( ); filterWhitelist = ( ); restrictWeb = 1; useCo ...

  5. ZYNQ fsbl阶段的调试方法

    以下是从安富利工程师的技术支持的邮件中摘抄的,在此再次对他们表示感谢. 在我们面对客户单板的时候,fsbl阶段的调试多少会有些问题,在这个过程中怎么快速定位客户的问题,并将有效的信息反馈给希望能帮助到 ...

  6. 那些年,我们一起追的面试题。。to be continued!!!

    1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?答:Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件.Java被 ...

  7. amqp事务

    摘要: 介绍confirm的工作机制.使用spring-amqp介绍事务以及发布确认的使用方式.因为事务以及发布确认是针对channel来讲,所以在一个连接中两个channel,一个channel可以 ...

  8. C语言中两种方式表示时间日期值time_t和struct tm类型的相互转换

    使用gmtime函数或localtime函数将time_t类型的时间日期转换为structtm类型: 使用time函数返回的是一个long值,该值对用户的意义不大,一般不能根据其值确定具体的年.月.日 ...

  9. ---awk 调shell 命令的方法

    cat /etc/passwd | awk -F: '/root/{ system ("echo "$1) }'

  10. SpringBoot-Learning

    SpringBoot-Learning 本项目内容为Spring Boot教程程序样例. 作者博客:http://blog.didispace.com Spring Boot系列博文:http://b ...