这一节我们来一起看下,一个客户端接入进来是什么情况。首先我们根据之前的分析,先启动服务端,然后打一个断点。

这个断点打在哪里呢?就是NioEventLoop上的select方法上。

然后我们启动一个客户端。

然后我们debug看到,selectedKey的数量 = 1,说明有accept或者读写等事件发生。

接下就会进 processSelectedKeys()

我们上一节讲到,这里的attach就是NioServerSocketChannel, 我们进入 processSelectedKey() 方法

重点来了,这里对各种事件进行分发,debug看我们现在是16,也就是说是accept事件。

继续跟进去F5进去

发现进入到了AbstractNioMessageChannel的read方法。这里进入的是 AbstractNioMessageChannel !!!;

为了加深印象,我们先暂停,重新跑一个读事件

发现当前的selectKey = 1,也就是读事件

F5 进入

发现,读事件进入到AbstractNioByteChannel中,

那么也就是accept进入  AbstractNioMessageChannel , 而 read 进入AbstractNioByteChannel 中。

好了,我们回过头来继续看 AbstractNioMessageChannel 中的read 方法。

关于这个分配器,这里我先不看,待后面分析内存模型的时候再说。我们直接看下面的代码:

我们发现这个是一个循环,不断的调用doReadMessages方法,并且传入了一个readBuf,而且这个readBuf是一个ArrayList, 那这里我们猜测可能是把读取到的客户端放到List集合中保存,然后再循环处理客户端连接。

进入doReadMessage方法一探究竟。

通过工具类调用 NioServerSocketChannel 内部封装的 serverSocketChannel 的 accept 方法,获取一个SocketChannel, 如果大家还记得我第一篇讲NIO的地方Netty源码分析--NIO(一),这里应该会有印象,我这里贴出来:

这里就是获取到了客户端的socketChannel

然后这里将SocketChannel封装成了一个NioSocketChannel,然后添加到了readBuf这个ArrayList中存储。

封装这里,这里不想多说了,跟创建NioServerSocketChannel类似,大家可以去回顾一下 Netty源码分析--创建Channel(三)

继续往下看,这里就是循环readBuf,链式执行 管道中的 handler 的 ChannelRead 方法。

根据前面几篇的分析,我们知道 , pipeline 里面又 4 个 handler ,分别是 Head,LoggingHandler,ServerBootstrapAcceptor,Tail,链式调用其中的 ChannelRead  方法,这里我们着重看  ServerBootstrapAcceptor 中个的 ChannelRead  方法。

这里为刚刚的客户端channel 添加了handler,设置了options和childAttrs,注意这里的addLast方法,并没有调用initChannel方法,具体这里添加了什么,我前面几篇有提及,大家可以再回顾一下。

接下来这里呢,就是把客户端channel注册到多路复用器上,跟服务端channel注册的流程是一样的。大家可以去看

Netty源码分析--Channel注册(上)(五)

Netty源码分析--Channel注册(中)(六)

Netty源码分析--Channel注册&绑定端口(下)(七)

我们直接说重点:

注册完成之后,就进入到了 pipeline.invokeHandlerAddedIfNeeded() 方法,我们跟下这个代码。

跟下去我们会进入上图这个execute()方法,如上图,我们看下  ctx

那么链式结构也就是 HeadContext -> NettyServer【ChannelInitializer】(我的启动类) -> TailContext

不断的跟下去,我们发现其实就是去调用当初我们在NettyServer中的initChannel。

那么也就是说,这里才是真正往pipeline中添加handler的过程!!!

神奇的是,后面还有一个remove方法。

那么这个是啥意思呢?我们再来看下ctx的链式结构

也就是说变成了 HeadContext - > NettyServer ->  IdleStateHandler ...等 -> TailContext

大家发现了吗? NettyServer 还在, 也就是  ChannelInitializer 这个handler 还在链上,但是它的作用已经结束了,没错,这里删除的就是它。

怎么删的就不说了,无非就是把 ChannelInitializer 两段的链表直接连接起来,把 ChannelInitializer  剔除就可以了。

接下来就是  pipeline.fireChannelRegistered(); 和 pipeline.fireChannelActive();

就是在所有的handler中链式调用channelRegister 和 channelActive方法。

总结一下:ServerBootstrapAcceptor 才是那个负责接收客户端连接,并且将其注册到多路复用器上的核心类

那么到这里,客户端的接入就完成了,下一篇我们来看,客户端的读写过程以及Netty的内存模型是什么样子的。

最新文章

  1. 启动Hive时出现的问题
  2. iOS中线程同步基本详解
  3. BUG归因
  4. JS中的_proto_(2)
  5. 13 SELECT 以外的内容
  6. yaml 1.6 操作
  7. SQL学习之高级数据过滤
  8. mybatis 入门优化
  9. Spark 源码解读 -- 依赖
  10. 在ASP.NET MVC3项目中,自定义404错误页面
  11. 基于MyBatis3.0.6的基本操作介绍
  12. 微信小程序 TLS 版本必须大于等于1.2问题解决
  13. Centos7 + Python3.6 + Django + virtualenv + gunicorn + supervisor 环境配置详解
  14. 如何学习sss和前端数据处理
  15. github导入文件操作
  16. VS2017离线安装与Oracle数据库开发环境搭建
  17. BZOJ3771 Triple(FFT+容斥原理)
  18. 转:Session,Token相关区别
  19. django基础 -- 3. urls.py view.py 参数 别名 重定向 常用方法 静态文件
  20. MySQL中实现DROP USER if EXISTS `test`,即创建新用户时检测用户是否存在

热门文章

  1. 对复杂字典Dictionary<T1,T2>排序问题
  2. WPF中获取TreeView以及ListView获取其本身滚动条的方法,可实现自行调节scoll滚动的位置(可相应获取任何控件中的内部滚动条)
  3. c# 编写REST的WCF
  4. UNITY VR 视频/图片 开发心得(二)
  5. 查看window端口占用并结束相关进程
  6. wpf-MVVM界面自适应:界面自适应及字体自适应
  7. VS2012 调试Web项目 遭遇 HTTP 错误 500.23 - Internal Server Error
  8. WPF应用App.Config文件的保存路径
  9. 微信小程序把玩(三十二)Image API
  10. c#利用IronPython调用python的过程种种问题