Netty源码解析 -- 服务端启动过程

Netty是一个高性能的网络通信框架,支持NIO,OIO等多种IO模式。通常,我们都是使用NIO模式,该系列文章也是解析Netty下NIO模式的实现。
首先,看一个NIO网络通信示意图

Netty源码解析 -- 服务端启动过程


Netty中NIO网络通信过程在此基础上实现,下面来看一下具体实现。

Channel

首先,看一下Netty中的通道Channel,它代表了一个能完成IO操作的通道,提供read, write, connect, bind等方法。
Channel中维护了一个Unsafe对象,用于完成数据传输操作(这类操作通常由IO事件触发,而不是用户触发)。

SocketChannel代表Socket连接的网络通道,面向流,支持读写操作。
ServerChannel表示可以监听新连接的通道,ServerSocketChannel代表实现TCP/IP协议的ServerChannel。

AbstractChannel提供基础逻辑实现,它维护了Unsafe和ChannelPipeline对象,并委托这两个对象完成实际工作。同时,它也提供newUnsafe,newChannelPipeline方法给子类构造他们需要的对象。
AbstractUnsafe是AbstractChannel的内部类,实现了register,bind,disconnect等方法的基础逻辑。

ChannelPipeline可以理解为拦截器链表,维护了一个ChannelHandler链表,ChannelHandler即具体拦截器,负责逻辑处理。
DefaultChannelPipeline是ChannelPipeline接口的默认实现。Netty中Nio相关的Channel都使用它。
可以这样理解,Unsafe负责数据传输,而ChannelPipeline负责逻辑处理。

AbstractNioChannel实现了NIO基础逻辑,如维护(jvm)SelectableChannel,(jvm)SelectionKey等对象,还有一个很关键的selectionKey,代表关注的NIO事件。
AbstractNioUnsafe是AbstractNioChannel内部类,继承于AbstractUnsafe,并实现Unsafe另一个子接口NioUnsafe,添加了SelectableChannel相关的方法,如finishConnect,read。

AbstractNioChannel的子类可以分成ServerChannel实现类和SocketChannel实现类。

ServerChannel实现类是AbstractNioMessageChannel,newUnsafe方法返回的NioMessageUnsafe。
NioServerSocketChannel是AbstractNioMessageChannel子类,实现TCP/IP协议。

SocketChannel实现类是AbstractNioByteChannel,newUnsafe方法返回的NioByteUnsafe。
NioSocketChannel是AbstractNioByteChannel子类,实现TCP/IP协议。

Channel各实现类关系如下

Netty源码解析 -- 服务端启动过程

Netty中将接口划分得很细微,最好大家可以按功能层次理解各接口代表含义以及实现类的​逻辑。​
以免后续看源码时混淆各接口功能。

服务端启动

首先简单了解一下EventLoop,可以理解为它负责处理网络事件和异步任务,后面有对应文章详细解析。
EventLoopGroup则是一组EventLoop集合,它会将操作委托给其中一个EventLoop处理。

Netty的服务端启动引导类ServerBootstrap中维护了两个EventLoopGroup,EventLoopGroup#childGroup和AbstractBootstrap#group。
AbstractBootstrap#group负责管理注册于其上的ServerChannel,处理这些Channel上发生的Accept事件,并将生成的SocketChannel注册到EventLoopGroup#childGroup。
EventLoopGroup#childGroup处理这些SocketChannel上发生的Read,Write事件。
为了方便,下文我将AbstractBootstrap#group称为AcceptGroup,ServerBootstrap#childGroup称为ReadGroup。

这些设计来自Reactor模式,详细可以见java.util.concurrent包的作者Doug Lea的《Scalable IO in Java》。

AbstractBootstrap#bind -> AbstractBootstrap#doBind

private ChannelFuture doBind(final SocketAddress localAddress) { // #1 final ChannelFuture regFuture = initAndRegister(); final Channel channel = regFuture.channel(); if (regFuture.cause() != null) { return regFuture; } if (regFuture.isDone()) { ChannelPromise promise = channel.newPromise(); // #2 doBind0(regFuture, channel, localAddress, promise); return promise; } else { ... } }

#1 初始化及注册ServerChannel。
initAndRegister方法返回ChannelFuture,ChannelFuture继承了(jvm)Future,代表IO异步处理结果,并且可以绑定回调函数,异步IO处理完成Netty后会触发这些回调函数。
我们要有这个意识,Netty是一个异步框架,所有的IO操作都是异步的(充分利用cpu),IO方法不会等待实际IO操作完成,而是返回ChannelFuture。
待实际IO完成后,Netty再触发ChannelFuture中的回调函数处理后续逻辑。
ChannelPromise是一种特殊的ChannelFuture,提供更新操作结果的方法(setSuccess,setFailure方法),一般提供给IO方法作为参数(Unsafe中很多方法都有该参数),IO操作完成后,会调用这些方法更新操作结果。
#2 注册完成后,绑定ServerChannel监听端口。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwsjzf.html