继续上一篇Netty文章,这篇文章主要分析Netty对Channel事件的处理以及空轮询Bug的解决
当Netty中采用循环处理事件和提交的任务时
由于此时我在客户端建立连接,此时服务端没有提交任何任务
此时select方法让Selector进入无休止的阻塞等待
此时selectCnt++进行一次计数,ioRatio用来设置处理非事件任务所占总事件的比例
紧接着进入processSelectedKeys方法内部,处理连接事件
由于NioEventLoop中维护了一个Selector,这里的SelectedKeys是对原始Selector中的SelectedKeys的一种优化,后续文章会总结Netty做的优化
这段代码作用就是获得到对应事件,然后通过附件的方式拿到NioServerSocketChannel
紧接着利用NioServerSocketChannel中的unsafe类完成消息的写出的读入
调用unsafe的read方法后,通过read方法中的doReadMessages拿到Java ServerSocketChannel建立的SocketChannel
拿到SocketChannel后,创建一个NioSocketChannel,并创建对应的pipleline,config等等和NioServerSocketChannel一样。然后把它暂存在一个List集合buf中
紧接着调用NioServerSocketChannel的pipleline方法出发read事件,这里提醒一下pipleline的组成一次是head,logging,acceptor,tail组成
此方法内部其实就是不断的查找下一个Handler,调用Read方法
并且由于一些任务比较耗时为了不阻塞链接线程可以使用自己设置线程组
当轮到acceptor方法处理时
注意:这里的childHandler是我们在server端最开始的strap代码时填入childHandler属性中的Handler,同时下方的childGroup就是server端最开始的childNioEventLoopGroup
接下来register方法内部就是我们上一篇文章讲到的进行线程切换,把NioSocketChannel以附件的形式绑定到SocketChannel。由于每个NioEventLoop都维护了一个Selector,同时把SocketChannel注册到(child)NioEventLoopGroup中的NioEventLoop中的Selector接着继续循环监听事件处理提交的任务。分析到这里我们可以理解Netty的基本线程模型了
接下来连接事件处理完毕,BossGroup该处理普通任务了
可以看到ioRation是控制所占用时间的比例的
而selectCnt是为了避免在Linux中导致selector不阻塞从而进行计数,当超过512时就认为出现bug,Netty解决方法就是重新创建一个Selector,并把原始信息复制一份。
接下来我们研究数据的发送和读写