netty源代码解读-架构流程

今天读了一片关于Netty架构流程的文章,感觉可以作为我上一篇《Netty基础介绍与框架搭建》的补充,在这里转载下。

netty是什么?直接用官方的介绍-netty是一个异步的,基于事件的网络框架。基于它,可以快速开发高性能,易扩展的服务端和客户端程序。一开始,netty还很纯洁,是一个纯粹的NIO网络框架。时光荏苒,它现在已经支持多种网络协议了,变得愈加庞大强大了

netty 架构图

本文的目的是对netty的源代码的网络处理流程进行分析,相对比较零散,阅读者最好结合代码来看,阅读的顺序也最好基于本文的描述顺序。本文使用的netty版本是3.2.5.Final。关于netty的实际应用,可以参考本blog的另外一篇文章(利用netty快速搭建一个高性能的聊天服务器)

从一个最简单的实例开始吧。我们创建一个基于NIO的server程序,代码大致如下:

          // 创建一个server实例,并且配置其SocketChannelFactory
        ServerBootstrap bootstrap = new ServerBootstrap (
                new NioServerSocketChannelFactory (
                        Executors. newCachedThreadPool ( ),
                        Executors. newCachedThreadPool ( ) ) ) ;

        // 再配置它的 pipeline factory.
        bootstrap. setPipelineFactory ( new ChannelPipelineFactory ( ) {
            public ChannelPipeline getPipeline ( ) throws Exception {
                return Channels. pipeline ( new ServerHandler ( ) ) ;
            }
        } ) ;

        //bind,然后开始接受新的链接到来
        bootstrap. bind ( new InetSocketAddress ( 8080 ) ) ;

是不是感觉so easy:) 代码注释已经给出了简单介绍。接下来进入细节。

ServerBootstrap 是一个辅助类,用来创建服务端Channel,接受客户端连接。它有两个重要的属性ChannelFactory和PipelineFactory。可以看到接下来的代码都是在配置这两个属性。看到xxFactory的命名,很自然想到是用了设计模式的工厂模式。这两个类分别是用来创建Channel实例和Pipeline实例的。

Channel 封装了nio 的 SocketChannel。提供了各种I/O操作,需要注意的是,各种操作都是异步的。每个操作函数,你都将获得一个ChannelFuture返回值,可以用它监听各种事件(比如操作结束)。

Pipeline是netty中一个重要的数据结构,是理解netty框架架构,事件机制的关键因素。Pipeline是一个链表结构,节点存储的是ChannelHandler。netty的事件触发机制是这样的:当触发某个事件时候,从pipeline中获得头节点,查看该ChannelHandler有无Override重写该事件的处理函数。如果有,就调用。然后继续查找下一个节点,重复上面的过程,直到链表尾部。

pipeline 结构图

ChannelHandler是各种事件处理操作,比如我们这里的业务逻辑类ServerHandler。我们在ChannelHandler中可以重写Override感兴趣的事件处理函数。基于这种设计架构,我们的代码可以很优雅。比如,客户端发来一条事件,触发了读相关事件,我们可以先调用解码的xxDecoder,然后再继续传递给相关的业务处理Handler。这样,就把业务逻辑跟编码解码解耦了。

这里很有必要在详细描述一下netty的事件机制。在netty中,只包括两种事件upstream 和 downstream。处理upstream时,是从pipeline的第一个节点开始,直到尾部。相反,downstream是从尾节点开始的。也可以这样理解,upstream是由网络层向netty发起的,例如收到一条消息。而downstream是netty向网络层发起的,例如write 操作

下面进入到NioServerSocketChannelFactory内部,它里面包含了boss线程序和woker线程的执行器.这样的好处是boss线程和woker线程可以方便管理了,比如统一关闭销毁.boss线程是负责处理socket连接,worker线程是负责处理io的.worker线程的数目一般设置为cpu核数*2. ChannelFactory内部还有一个称为ChannelSink的部件,我们称为”连接器”.ChannelSink用来接受和处理downstream 事件的终结点.当一个downstream 事件到达底部(也就是pipeline的头节点),会触发ChannelSink的eventSunk函数

终于到绑定操作bind了.这里比较复杂点,首先在boss的pipeline中插入一个Binder handler,用来监听channel open等事件.接着利用上面的ChannelFactory new 一个NioServerChannel.这里开始open ServerSocketChannel,然后抛出ChannelOpen事件。上面的binder handler就监听处理ChannelOpen事件了。事件处理函数主要两个操作,设置socket的相关属性和执行Channels的 bind函数。bind函数将Bound事件传递下去,直到downstream的底端,上面谈过的ChannelSink的eventSunk被触发。

在eventSunk中,真正的socket bind函数被调用。接下来就启动Boss线程,开始接受新的连接了。当一个新的连接到了,就从取得一个worker线程,由worker线程处理读写了

worker线程是整个框架的核心了,主要包括以下操作:处理boss线程推送过来的socket;处理写队列,处理各种selector事件(读写)。最新的版本对写操作做了优化,不用放入写队列,直接写,减少 selector事件的等待,提高效率。

上面的描述可能显得凌乱,最好的办法是拿源代码来进行调试,结合我的这篇blog来分析。其实netty的框架核心是nio,Doug Lea 曾经描述过各种模型,下面的模式是性能最佳的,也是netty的架构雏形

结束:因为netty的庞大,篇幅有限,描述上可能不够清晰,希望你阅读后能有收获。如果有机会,我将继续探讨netty的源代码的其他部分,也欢迎交流。


你可能感兴趣的:(Netty,socket,框架,网络,网络协议,数据结构,设计模式)