netty 源码分析,netty 源码深入分析
00-1010服务器demoEventLoopGroup介绍函数1:我们来看看注册的通道函数2:执行一些可运行的任务ChannelPipeline介绍绑定进程同步介绍误区4后续
00-1010看下一个简单的Netty服务器端示例
public static void main(String[]args){ EventLoopGroup boss group=new NioEventLoopGroup(1);EventLoopGroup worker group=new NioEventLoopGroup();请尝试{ server bootstrap server bootstrap=new server bootstrap();server bootstrap . group(boss group,workerGroup)。通道(NioServerSocketChannel.class)。选项(ChannelOption。SO_BACKLOG,200)。child handler(new ChannelInitializerSocketChannel(){ @ override protected void init channel(socket channel ch)引发异常{ch.pipeline()。addLast(新的LengthFieldBasedFrameDecoder(80,0,4,0,4));ch.pipeline()。add last(new string decoder(charset . for name( UTF-8 )));ch.pipeline()。addLast(新的TCP server handler());}});channel future f=server bootstrap . bind(8080)。sync();f .频道()。closeFuture()。sync();} catch(interrupted exception e){ e . printstacktrace();} finally { worker group . shut down gracefully();boss group . shut down gracefully();}}我们先简单说一下上面遇到的类:
00-1010它主要包括两个功能:注册通道和执行一些可运行的任务。
00-1010通道在选择器上注册,选择器会调度通道的相关事件,如读、写、接受等事件。
EventLoopGroup的设计是它包含多个EventLoop(每个event loop内部通常包含一个线程)。在执行上述注册的过程中,需要选择EventLoopGroup中的一个来执行上述注册行为。这里有一个选择政策的问题。选择策略的界面是EventExecutorChooser,您也可以自定义一个实现。
从上面可以看出,EventLoopGroup所做的大部分工作都是初始化上述多个Eventloops、EventExecutorChooser等一般性工作。具体的注册通道还是交给它内部的EventLoop来实现。
目录
EventLoopGroup继承了EventExecutorGroup,它也是EventExecutors的集合。EventExecutorGroup还负责EventExecutor的初始化。EventExecutorGroup还选择它的一个内部EventExecutors来执行Runnable任务的具体执行。
netty中的许多任务都是异步执行的。一旦当前线程要在EventLoop上执行相关操作,比如向EventLoop注册通道,如果当前线程和要操作的EventLoop内部的线程不一样,当前线程只是向EventLoop提交一个注册任务,对外返回一个ChannelFuture。
总结:EventLoopGroup包含了以上两个函数,更多的是一个集合,但是具体的函数实现是选择一个内部的item元素来执行相关的任务。这里的内部item元素通常同时实现EventLoop和EventExecutor,比如NioEventLoop等。
00-1010上述EventLoopGroup可以向内部Eve注册一个通道。
ntLoop的Selector上,然后对于这个Channel的相关读写等事件,Netty专门设计了一个ChannelPipeline来进行处理。每一个Channel都有一个ChannelPipeline来处理该Channel的读写等事件。
bind过程
上述serverBootstrap的bind过程如下:
创建出你所指定的NioServerSocketChannel,然后初始化一些Socket方面的参数为上述Channel的ChannelPipeline配置一个ChannelHandler,该ChannelHandler的作用就是在该Channel成功注册到Selector上的时候,初始化一些逻辑,即initChannel方法中执行一些逻辑,该逻辑就是向ChannelPipeline中添加一个新的ChannelHandler即ServerBootstrapAcceptor然后开始将该Channel注册到上述EventLoopGroup bossGroup中,该EventLoopGroup bossGroup会选择内部的一个EventLoop来执行实际的注册行为(这个时候就是当前线程和操作的EventLoop不是同一个线程,即该过程是异步提交一个Runnable),一旦注册完成,就执行上述ChannelHandler的initChannel方法至此,就完成了整个bind过程。一旦EventLoop内部的Selector检测到NioServerSocketChannel有新的连接到来的事件,则会交给NioServerSocketChannel的ChannelPipeline来处理,重点就是ChannelPipeline中的上述ServerBootstrapAcceptor,ServerBootstrapAcceptor做如下操作:
1 为新的Channel的ChannelPipeline配置我们上述代码中的childHandler指定的ChannelHandler2 将新的Channel注册到了上述EventLoopGroup workerGroup中
sync介绍
bind方法返回的是一个ChannelFuture,从上面我们也知道该过程是异步的,sync方法则是一直等待到该异步过程结束。
再看下f.channel().closeFuture().sync()这个方法
每一个ChannelFuture都是和一个Channel绑定的,所以可以通过ChannelFuture来获取对应绑定的Channel对象
每一个Channel对象都有一个CloseFuture closeFuture对象,上述closeFuture方法并不是去执行close方法而是获取到这个CloseFuture closeFuture对象,然后调用它的sync方法即等待这个Future的结束。一般正常情况下是不会调用这个Future的结束方法的,只是在上述过程或者其他过程出现问题的时候,如注册到EventLoop失败等才会去调用这个Feture的结束方法,所以正常情况下主线程会一直阻塞在CloseFuture closeFuture的sync方法上。
误区
上述的bossGroup的创建问题。
我们都知道bossGroup是用来accept连接,然后将连接绑定到workerGroup中的,一般情况下bossGroup设置线程数为1即可(基本只能为1),我们同时知道Ractor模型中可以使用多个Acceptor线程来执行accept操作,加快accept的速度。
如果你想加快accept的速度,想开启多线程来accept,这时候想设置bossGroup的线程数为多个的话,就大错特错了,是根本没效果的。
结合上面的原理,只有在bind端口的时候才会创建一个ServerSocketChannel,然后注册到bossGroup内部的一个EventLoop中,仍然是单线程负责ServerSocketChannel的accept工作,而bossGroup中的多线程仅仅是为bind多个端口服务的。
我们来看下tomcat是如何允许多个Acceptor线程来执行accept操作的:
1 创建了一个ServerSocketChannel serverSock,并bind到某个端口2 开启多个Acceptor线程,每个线程逻辑都是执行上述serverSock的accept方法没有使用Selector来执行accept操作,可以多线程并发执行上述serverSock的accept方法。
一旦使用了Selector,基本上就相当于将ServerSocketChannel serverSock绑定到了Selector所在线程上了(Selector不是线程安全的,只能在一个线程中被调度执行)
4 后续
下一篇就要详细描述下EventLoopGroup了。
以上就是分布式Netty源码分析概览的详细内容,更多关于分布式Netty源码分析的资料请关注盛行IT其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。