天天看点

Netty源码分析-概述

大家好,我是小森。前段时间我们学习了Netty框架,并完成了Netty框架主要组件的入门介绍(没有学习的小伙伴可以看这Netty框架入门);在这个系列中围绕服务端与客户端通信的示例展开学习,对Netty的Bytebuf、ChannelHandler、ChannelPipeline、Bootstrap和EventLoop等模块进行了学习,因为是入门级别所以讲的也不是很深入。但我相信通过这个入门系列的学习你已经学会了Netty框架的使用并且会产生一些思考与问题,例如下面这些:

  • Netty的Bootstrap服务端与客户端引导启动时分别做了些什么?
  • Netty的Bytebuf是如何做到堆内零拷贝的?池化技术又是如何实现的?
  • Netty的ChannelPipeline、ChannelHandlerContext设计
  • Netty的Reactor模式是怎样实现的,又分为那些模型
  • ……

那么我们将有阅读源码的形式理解上面或更多问题。在做件事情前再来一起回顾下,或者说阅读源码的一个大纲吧。

一、Bootstrap

Bootstrap是一个引导程序,将会重它开始,就像程序启动一样先进行引导再进入业务流程。在这个章节中会分别对服务端的引导和客户端的引导以及AbstractBootstrap类进行阅读分析,过程就像这张类图一样:

Netty源码分析-概述

因为引导还会涉及到EventLoop、ChannelHandler等内容,这一章节也只会简单的描述下它们是如果被初始的,在引导过程中起到的作用,最后以回顾整个引导流程结束这一章节

二、EventLoop与EventLoopGroup

EventLoop在入门篇的示例中并没有明确的用到,但我们使用过NioEventLoopGroup,EventLoop将会在内部使用到;根据流程在客户端打开连接或者在服务端打开监听端口后将创建Channel,而Channel将会被托管在EventLoop中,而EventLoop的创建由EventLoopGroup初始。过程大概如下图:

Netty源码分析-概述

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是如何工作的:

Netty源码分析-概述

在ChannelPipeline中会区分入站(ChannelInboundHanndler类型)与出站(ChannelOutboundHandler类型)的过滤器进行自动编排,ChannelPipeline中使用一张链表存储着所有ChannelHandler,先后顺序由引导时插入到链表中的顺序决定,但有时会混合着入站与出站,所以ChannelPipeline会有一个处理方向的概念,如果是处理入站事件时方向就是入站,会过滤不是当前方向上的ChannelHandler。具体的过程留给后文吧。

最后

现在稳定的版本是Netty4,所以源码的阅读与分析与将会使用Netty4的版本。

Netty的源码地址:https://github.com/netty/netty.git

精彩推荐:

Netty源码解析-引导(一)服务端启动

Netty源码解析-EventLoop(二)之EventLoopGroup初始化

更多超前内容请关注:

Netty源码分析-概述