大家好,我是小森。前段时间我们学习了Netty框架,并完成了Netty框架主要组件的入门介绍(没有学习的小伙伴可以看这Netty框架入门);在这个系列中围绕服务端与客户端通信的示例展开学习,对Netty的Bytebuf、ChannelHandler、ChannelPipeline、Bootstrap和EventLoop等模块进行了学习,因为是入门级别所以讲的也不是很深入。但我相信通过这个入门系列的学习你已经学会了Netty框架的使用并且会产生一些思考与问题,例如下面这些:
- Netty的Bootstrap服务端与客户端引导启动时分别做了些什么?
- Netty的Bytebuf是如何做到堆内零拷贝的?池化技术又是如何实现的?
- Netty的ChannelPipeline、ChannelHandlerContext设计
- Netty的Reactor模式是怎样实现的,又分为那些模型
- ……
那么我们将有阅读源码的形式理解上面或更多问题。在做件事情前再来一起回顾下,或者说阅读源码的一个大纲吧。
一、Bootstrap
Bootstrap是一个引导程序,将会重它开始,就像程序启动一样先进行引导再进入业务流程。在这个章节中会分别对服务端的引导和客户端的引导以及AbstractBootstrap类进行阅读分析,过程就像这张类图一样:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CNwYjNxEWYkZ2NiJzMwgTN3cDOwMGM2IjMjFDNkNDZi9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
因为引导还会涉及到EventLoop、ChannelHandler等内容,这一章节也只会简单的描述下它们是如果被初始的,在引导过程中起到的作用,最后以回顾整个引导流程结束这一章节
二、EventLoop与EventLoopGroup
EventLoop在入门篇的示例中并没有明确的用到,但我们使用过NioEventLoopGroup,EventLoop将会在内部使用到;根据流程在客户端打开连接或者在服务端打开监听端口后将创建Channel,而Channel将会被托管在EventLoop中,而EventLoop的创建由EventLoopGroup初始。过程大概如下图:
Netty框架中的事件驱动模型使用Reactor模型实现,支持单Reactor单线程、单Reactor多线程、主从Reactor多线程;另外在EventLoop中还包含了Worker;这个Worker的作用是区分I/O事件与非I/O任务,但这些都交由Reactor线程处理。
Channel
客户端创建一个连接或者服务端收到连接请求都会创建一个Channel,所有的I/O事件都由Channel产生,这些事件包含read、write、connet、accept、close。Channel为用户提供了:
- 当前网络连接通道的状态
- 网络连接的配置信息
- 异步的网络I/O操作,操作返回ChannelFuture实例,通过ChannelFuture可以操作异步的状态,例如取消、关闭等
不同的协议与不同的阻塞类型的连接都有与之对应的Channel类型,下面是常用的Channel类型:
- NioSocketChannel 异步的客户端 TCP Socket 连接。
- NioServiceSocketChannel 异步的服务器端 TCP Socket 连接。
- NioDatagramChannel 异步的 UDP 连接。
- NioSctpChannel 异步的客户端 Sctp 连接。
- NioSctpServiceChannel 异步的 Sctp 服务器端连接
- EpollSocketChannel 异步的客户端TCP Socket连接,底层使用epoll
- EpollServiceSocketChannel异步的服务器端 TCP Socket 连接,底层使用epoll
当然不光有上面列举的Channel类型就不一一列举了,这次的阅读也只会涉及Nio部分。
ChannelHandler、ChannelHandlerContext
ChannelHandler是一个处理Channel事件的接口,通过ChannelHandler可以处理任一的网络I/O事件与数据,引导过程会使用ChannelPipeline将多个ChannelHandler串起来。通常会通过继承ChannelInboundHandler与ChannelOutboundHandler两个子接口类型来处理业务逻辑,这些业务逻辑包含数据的编码、解码、读取、写入以及事件传递等待事情。在这其中有一个很重要的角色ChannnelHandlerContext,它的作用是将对应的ChannelHandler托管,在ChannelPipeline中起到事件向下传递与调用ChannelHandler的作用,另外还存储着当前Channel的相关上下文信息等。
ChannelPipeline
ChannelPipeline在Netty中起着一个很重要的作用,因为有它让Netty在处理各种各样的业务情况时有了很强扩展性与适应性,使得业务可以在运行时对整个ChannelPipeline中的过滤器(这里的过滤器实现类型都是ChannelHandler)进行调整以支持不同的业务形态。下面通过源码中的一张注释图来看看ChannelPipeline是如何工作的:
在ChannelPipeline中会区分入站(ChannelInboundHanndler类型)与出站(ChannelOutboundHandler类型)的过滤器进行自动编排,ChannelPipeline中使用一张链表存储着所有ChannelHandler,先后顺序由引导时插入到链表中的顺序决定,但有时会混合着入站与出站,所以ChannelPipeline会有一个处理方向的概念,如果是处理入站事件时方向就是入站,会过滤不是当前方向上的ChannelHandler。具体的过程留给后文吧。
最后
现在稳定的版本是Netty4,所以源码的阅读与分析与将会使用Netty4的版本。
Netty的源码地址:https://github.com/netty/netty.git
精彩推荐:
Netty源码解析-引导(一)服务端启动
Netty源码解析-EventLoop(二)之EventLoopGroup初始化
更多超前内容请关注: