网络I/o编程模型22 netty的源码总结
Posted 健康平安的活着
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络I/o编程模型22 netty的源码总结相关的知识,希望对你有一定的参考价值。
一 netty启动流程
1.new NioEventLoopGroup(1):这个表示bossGroup事件组有1个线程可以指定,如果new NioEventLoopGroup() 则默认会有cpu核数*2 个线程,这样可以充分利用多核的优势。
DEFAULT_EVENT_LOOP_THREADS=Math.max(1,SystemPropertyUtil.getInt("io.netty.eventLoopThreads",NettyRuntime.availableProcessors()*2));
2.从NioserverSocketChannel的初始化过程中,可以看出,pipeline是一个双向链表,并且它本身初始化了head和tail,这里调用addLast方法,也就是将整个handler插入到tail的前面。
3.channelHandlerContext对象是channelHandler和channelpipeline之间的关联,每当有channelHandler添加到pipeline中时,都会创建Context。
4.创建2个EventLoopGroup线程池数组。默认数组大小为cpu*2,方便chooser选择线程时提供性能。
5.BootStrap将boss设置为group属性,将worker设置为children属性。
6.通过bind方法启动,内部重要方法为initAndRegister和dobind方法
7.initAndRegister方法会反射创建NioServerSocketChannel以及相关的NIO对象,pipeline,unsafe同时也为pipeline初始了head节点和tail节点。
8.在register方法调用doBind()方法,该方法会调用NioServerSocketChannel的doBind方法对JDK的channel和端口进行绑定,完成netty服务器的所有启动,并开始监听连接事件。
二 netty接收请求的流程
总体流程:
1.接受连接---->创建一个新的NioSocketChannel------->注册到一个worker EventLoop上 --> 注册selector Read事件。
2.服务器轮询Accept事件,获取事件后调用unsafe的read方法,这个unsafe是serversocket的内部类。
3.DoReadMessage 用于创建NioSocketChannel对象,该对象包装JDK的Nio channel客户端,该方法会像创建ServerSocketChannel类似创建pipeline、unsafe
4.下一步,执行pipeline.fireChannelRead()方法,并将自己绑定到一个chooser选择器选择的workerGroup中的一个EventLoop,并且注册一个0表示成功,但并没有注册读(1)事件。
三 channelpipeline和channelhandlercontext和channelhandler关系
3.1 关系
1.channelSocket与channelPipeline是1:1关系,而channelpipeline包含多个channelhandlercontext,每一个channelhandlercontext都包含一个channelhandler,内部的channelhandlercontext一起组成了双向链表,这些channelhandlercoantext封装了我们编写addLast方法添加的channelhandler。
2.当一个请求进来的时候,会进入socket对应的pipeline,并经过pipeline所有的handler,这就是设计模式中过滤器模式。
3.2 channelpipeline
该接口继承了inBound,outBound,Iterable接口,表示它可以调用数据出站和入站的方法。
1.首先,当一个请求进来的时候,会第一个调用pipeline的相关方法,如果是入站事件,则这些方法都是fire开头,表示开始管道的流动,让后面的handler继续进行处 。
2.pipeline 首先会调用Context的静态方法 fireXXX,并传入Context
3.然后,静态方法调用Context的invoke方法,而invoker方法内部会调用该context所包含的handler的真正的xxx方法,调用结束后,如果还需要继续向后传递,就调用context的firexxx2方法,循环往复。
3.3 channelhandler
channelhandler其作用就是处理IO事件或拦截IO事件,并将其转发给下一个处理程序ChannelHandler。handler处理事件发呢我出站和入站,两个方向的操作都是不同的,因此,netty定义了两个子接口继承channnelhandler。
1.channelInboundhandler 入站事件接口
2.channelOutboundHndler 出站事件接口
bind 方法:当请求将channel绑定到本地地址时调用
close 方法: 当请求关闭channel 时调用等等。
3.4 channelhandlercontext
channelHandlerContext 继承了出站方法调用接口和入站方法调用接口,如下图所示
任何一个channelSocket 创建的同时,都会常见一个pipeline;
当用户或者系统内部调用pipeline的add**方法添加handler时,都会创建一个包装这个handler的Context。这些Context在peipeline中组成双向链表。
3.5 channelhandlercontext调用channelhandler的流程
1.每当创建channelSocket的时候都会创建一个绑定的pipeiline,1:1的关系,创建peipeline的时候会创建tail节点和head节点,形成最初的链表。
2.在调用peipeline的addLast方法的时候,会根据给定的handler创建一个context,然后建这个context插入到链表的尾端(tail的前面)
3.context包装了多个handeler,多个context在pipeline中形成双向链表。
4.入站方向叫inbound,由head节点开始,出站方向叫outbound,由tail节点开始。
因为出站是从内部向外面进行写操作,从tail开始能够让前面的handler进行处理,防止handler被遗漏,如编码。
入站当然就是从head网内部输入,让后面的handler能够处理这些输入的数据。比如解码。
注意:虽然head也实现了outbound接口,但不是从head开始执行出站任务的。
5.而节点中间的传递通过AbstaractChannelHandlerContext类内部的fire系列方法,找到当前节点的下一个节点不断的循环播放,是一个过滤器形成 完成对handler的调度。
以上是关于网络I/o编程模型22 netty的源码总结的主要内容,如果未能解决你的问题,请参考以下文章