1.服务器启动后肯定要接受客户端请求并返回客户端想要的信息,下面分析Netty在启动之后是如何接受客户端请求的
说明:
1.从之前的服务器启动的源码中,我们得知,服务器最终注册一个Accept事件等待客户端连接,我们也知道,NioServerSocketChannel将自己注册到了boss单例线程池(reactor线程上),也就是EventLoop
2.EventLoop逻辑简单理解:
1.有条件的等待Nio事件
2.处理Nio事件
3.处理消息队列中的任务
4.仍用前面的项目来分析:进入到NioEventLoop源码中后,在
private voidprocessSelectedKey(SelectionKey k,AbstractNioChannel ch) 方法开始调试最终我们要分析到 AbstractNioChannel 的 doBeginRead 方法, 当到这个方法时,针对于这个客户端的连接就完成了,接下来就可以监听读事件了


源码分析

1.在NioEventLoop的如下方法 processSelectedKey断点

  1. if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
  2. unsafe.read(); //断点位置
  3. }

2.客户端发送请求
3.然后我们可以看到,readyOps是16,也就是检测到了Accept事件,说明客户端的请求已经发送过来了
4.进入read方法
说明:
1.检查该eventloop线程是否是当前线程
2.执行doReadMessages,并传入一个readBuf变量,这个变量是一个List,也就是容器
3.循环容器,执行pipeline.fireChannelRead(readBuf.get(i))
4.doReadMessages 是读取 boss 线程中的 NioServerSocketChannel接受到的请求,并把这些请求放到容器中
5.循环遍历容器中所有的请求,调用pipeline 的fireChannelRead方法,用于处理这些接受的请求或者其他事件,在read方法中,循环调用ServerSocket的pipeline 的fireChannelRead方法,开始执行,管道中的handler 的 ChannelRead方法
6.追踪一下doReadMessages方法
1.通过工具类调用NioServerSocketChannel内部封装的ServerSocketChannel的accept方法,这时Nio的做法
2.获取到一个JDK的SocketChannel,然后,使用NioSocketChannel进行封装,最后添加到容器中
3.这样容器buf中就有了NioSocketChannel
7.回到read方法,继续分析 循环执行,pipeline.fireChannelRead方法
1.前面分析doReadMessages方法的作用是通过ServerSocket的accept方法获取到TCP连接,然后封装成Netty的NioSocketChannel对象,最后添加到容器中
2.在read方法中,循环调用ServerSocket的pipeline的fireChannelRead方法,开始执行 管道中的handler的ChannelRead方法
3.经过多次debug,会反复执行多个handler的ChannelRead,pipeline中会有4个handler,分别是Head、LoggingHandler、ServerBootstrapAcceptor、Tail
4.分析ServerBootstrapAcceptor的channelRead方法
说明:
1.添加NioSocketChannel的pipeline的handler,就是main方法中设置的childHandler中设置的
2.设置NioSockerChannel的各种属性‘
3.将该NioSocketChannel注册到childGroup中的一个EventLoop上,并添加一个监听器
4.这个childGroup就是我们main方法创建数组workerGroup


Netty接受请求过程梳理

总体流程:接受连接——>创建一个新的NioSocketChannel——->注册到一个worker EventLoop上———>注册selector Read事件
1.服务器轮询Accept事件,获取事件后调用unsafe的read方法,这个unsafe是ServerSocket的内部类,该方法内部由两部分组成
2.doReadMessages用于创建NioSocketChannel对象,该对象包装类JDK的Nio Channel客户端,该方法会像创建ServerSocketChannel类似创建相关的piprline,unsafe,config
3.随后执行 pipeline.fireCHannelRead方法,并将自己绑定到一个chooser选择器选择的workerGroup中的一个EventLoop,并且注册一个0,表示注册成功