一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)

lemonvita
发布于 2022-7-18 17:20
浏览
0收藏

1. 前文回顾


在前边的系列文章中,笔者为大家详细剖析了 Reactor 模型在 netty 中的创建启动运行接收连接接收数据发送数据的完整流程,在详细剖析整个 Reactor 模型如何在 netty 中实现的过程里,我们或多或少的见到了 pipeline 的身影。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 Reactor启动后的结构.png


比如在 Reactor 启动的过程中首先需要创建 NioServerSocketChannel ,在创建的过程中会为 NioServerSocketChannel 创建分配一个 pipeline ,用于对 OP_ACCEPT 事件的编排。

 

当 NioServerSocketChannel 向 main reactor 注册成功后,会在 pipeline 中触发 ChannelRegistered 事件的传播。

 

当 NioServerSocketChannel 绑定端口成功后,会在 pipeline 中触发 ChannelActive 事件的传播。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 主从Reactor组完整结构.png


又比如在 Reactor 接收连接的过程中,当客户端发起一个连接并完成三次握手之后,连接对应的 Socket 会存放在内核中的全连接队列中,随后 JDK Selector 会通知 main reactor 此时 NioServerSocketChannel 上有 OP_ACCEPT 事件活跃,最后 main reactor 开始执行 NioServerSocketChannel 的底层操作类 NioMessageUnsafe#read 方法在 NioServerSocketChannel 中的 pipeline 中传播 ChannelRead 事件。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 传播ChannelRead事件.png


最终会在 NioServerSocketChannel 的 pipeline 中的 ServerBootstrapAcceptor 中响应 ChannelRead 事件并创建初始化 NioSocketChannel ,随后会为每一个新创建的 NioSocetChannel 创建分配一个独立的 pipeline ,用于各自 NioSocketChannel 上的 IO 事件的编排。并向 sub reactor 注册 NioSocketChannel ,随后在 NioSocketChannel 的 pipeline 中传播 ChannelRegistered 事件,最后传播 ChannelActive 事件。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 传播ChannelRegister事件.png


还有在《Netty如何高效接收网络数据》一文中,我们也提过当 sub reactor 读取 NioSocketChannel 中来自客户端的请求数据时,会在 NioSocketChannel 的 pipeline 中传播 ChannelRead 事件,在一个完整的 read loop 读取完毕后会传播 ChannelReadComplete 事件。

 

《一文搞懂Netty发送数据全流程》一文中,我们讲到了在用户经过业务处理后,通过 write 方法和 flush 方法分别在 NioSocketChannel 的 pipeline 中传播 write 事件和 flush 事件的过程。

 

笔者带大家又回顾了一下在前边系列文章中关于 pipeline 的使用场景,但是在这些系列文章中并未对 pipeline 相关的细节进行完整全面地描述,那么本文笔者将为大家详细的剖析下 pipeline 在 IO 事件的编排和传播场景下的完整实现原理。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 内容概要.png

 

2. pipeline的创建

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区 主从Reactor组完整结构.png


Netty 会为每一个 Channel 分配一个独立的 pipeline ,pipeline 伴随着 channel 的创建而创建。

 

前边介绍到 NioServerSocketChannel 是在 netty 服务端启动的过程中创建的。而 NioSocketChannel 的创建是在当 NioServerSocketChannel 上的 OP_ACCEPT 事件活跃时,由 main reactor 线程在 NioServerSocketChannel 中创建,并在 NioServerSocketChannel 的 pipeline 中对 OP_ACCEPT 事件进行编排时(图中的 ServerBootstrapAcceptor 中)初始化的。

 

无论是创建 NioServerSocketChannel  里的 pipeline 还是创建 NioSocketChannel 里的 pipeline , 最终都会委托给它们的父类 AbstractChannel 。

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区

 image.png

 

public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {

    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        //channel全局唯一ID machineId+processId+sequence+timestamp+random
        id = newId();
        //unsafe用于底层socket的相关操作
        unsafe = newUnsafe();
        //为channel分配独立的pipeline用于IO事件编排
        pipeline = newChannelPipeline();
    }

    protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

}
public class DefaultChannelPipeline implements ChannelPipeline {

      ....................

    //pipeline中的头结点
    final AbstractChannelHandlerContext head;
    //pipeline中的尾结点
    final AbstractChannelHandlerContext tail;

    //pipeline中持有对应channel的引用
    private final Channel channel;

       ....................

    protected DefaultChannelPipeline(Channel channel) {
        //pipeline中持有对应channel的引用
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        
        ............省略.......

        tail = new TailContext(this);
        head = new HeadContext(this);

        head.next = tail;
        tail.prev = head;
    }

       ....................
}

在前边的系列文章中笔者多次提到过,pipeline 的结构是由 ChannelHandlerContext 类型的节点构成的双向链表。其中头结点为 HeadContext ,尾结点为 TailContext 。其初始结构如下:

一文聊透Netty IO事件的编排利器pipeline |详解所有IO事件(一)-鸿蒙开发者社区pipeline的初始结构.png

标签
已于2022-7-18 17:20:05修改
收藏
回复
举报
回复
    相关推荐