前言:虽然netty 内部的流程比较复杂,但是对于用户来说还是非常友好的,我们只需要进行必要的参数设置,以及添加处理业务的handler 即可;本文对netty 进行阶段性的回顾。
1 首先看下netty 整体的一个工作流程图:改图包含了服务器端与客户端连接的建立,消息的收发;
2 然后对Netty 中比较关键步骤的回顾:
2.1 Netty 服务器的 bind 方法:
Netty 中除了NioEventLoopGroup 的创建和ServerBootstrap 的初始化工作之外,其余的工作都交由bind() 方法进行处理,所以bind 方法 可以说是了解 Netty 流程的重中之重;
2.2.1 initAndRegister() 方法: 改方法中包含了init 和register ;它们的主要工作如下:
- 完成NioServerSocketChannel 对象的创建及其Pipeline 双向链表的初始化;非阻塞流的设置;
- 在init() 方法中等待NioServerSocketChannel 初始化完成之后在Pipeline 增加处理客户端accept 事件的ServerBootstrapAcceptor handler;
- 在register 方法中 从boos NioEventLoopGroup 获取一个 NioEventLoop 执行占位事件的注册;
- 当管道可用的时候pipeline.fireChannelActive() 调用pipeline 的ChannelActive 方法,在AbstractNioChannel中doBeginRead() 然后关注accept 事件;
2.2.2 AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise) 方法:它的工作如下:
进入NioServerSocketChannel 中的doBind 进行端口的绑定 ,使用原生的java ServerSocketChannel 完成端口的绑定;
在这里完成了channel 监听端口的绑定,channel 事件的注册,以及handler 的处理 ,为后续channel 的通信做了所有的准备工作;
3 Netty accept& read 处理:
Netty 中在完成了端口的绑定和accept 的监听后,后续的工作就是,客户端的连接,并且客户端与服务端的通信工作,其中比较重要的就是服务端对于accept,read ,write 事件的处理 ;
3.1 轮询事件处理:
accept 和 read 事件的处理都是通过NioEventLoop 中run 方法的 this.processSelectedKeys(); 进行的,当有io 事件发生时就会进入该方法;
3.1.1 netty服务端accept 事件处理:
- 如果发生accept 事件会进入 NioNessageUnsafe.read 方法处理,在这里创建了新的创建SocketChannel 对象来处理io 事件,对其设置io 流的非阻塞,对fNioServerSocketChannel读写属性的配置,默认Pipeline设置;
- 将新建的 SocketChannel 的对象作为消息放入到List readBuf 中进入循环通过调用链调用每个pipeline的fireChannelRead 方法并将消息当做参数进行传递;
- 在ServerBootstrapAcceptor 中从worker 的NioEventLoopGroup 中选择一个NioEventLoop ,然后得到NioEventLoop 中的selector 将新建的SocketChannel 进行注册;
- 注册完成通过AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded() 完成对新建的SocketChannel 将自己业务中的ChannelInitializer 的initChannel 方法,进行handler 的添加,最终在关注读事件;
3.1.2 服务端read 事件处理:
- 如果发生read 事件会进入到NioByteUnsafe.read 方法进行处理,从channel 中得到数据;
- 调用pipeline.fireChannelRead(byteBuf)方法依次调用服务端inbound的hadler 处理器中的channelRead0 方法进行业务调用;
3.1.3 Netty 的write 事件处理:
使用SocketChannel 的writeAndFlush 方法会从当前 SocketChannel 中 Pipeline,从tail 向前依次找出outbound的hadler 的write 方法进行调用;
4 参考:
4.1 浅谈Netty中ServerBootstrap服务端源码(含bind全流程);