首页 > Web开发 > 详细

netty ServerBootStrap的启动

时间:2020-09-02 13:08:59      阅读:116      评论:0      收藏:0      [点我收藏+]

NioEventLoopGroup group1= new NioEventLoopGroup();

NioEventLoopGroup group2 = new NioEventLoopGroup();

 

try{

  ServerBootstrap boot = new ServerBootstrap();

  boot.group(group1,group2)

    .channel(NioSeverSocketChannel.class)

    .localAddress(new InetAddress(port))

    .childHanlder(new ChannelInitializer<Channel>(){

            @Override

            public void initChannel(Channel ch){

              ch.pipeline().addLast(handler);

            }

});

     ChannelFuture future = boot.bind().sync();

      future.channel().closeFuture().sync();

}catch(){

}finaly{

  group1.shutdownGracefully();

  group2.shutdowngracefully();

}

 

以上代码是程序启动的简易代码。

对于Nio模型的理解。首先是将要关注的option 和Channel注册给操作系统内核selector。根据option 的值做出对应的操作。

SelectionKey.OP_ACCEPT  =1<<4;

SelectionKey.OP_CONNECt  =1<<3;

SelectionKey.OP_READ  =1<<0;

SelectionKey.OP_WRITE   =1<<2;

NIoEventLoopGroup : 里面包含了一个EventExecutor[ i ] 的线程数组,里面的线程是NioEventLoop

NioEventLoop  里面包含了Selector, SelectionKey   Set<SelectionKey>  主要功能是channel绑定该类,该类开启对应的selectNow(),进行轮训操作。因此该类包含有一个Executor  该线程将会执行一个任务,执行 该类中run 方法,进行轮训。

NioServerSocketChannel  该父类中会包含一个内部类Unsafe   Unsafe 类将会进行对应的register操作和bind操作。将这些操作进行了封装,具体方法参考对应的APi 或者源码。

DefaultChannelPipeline:作为一个职责链。内部有一个链表 DefaultChannelHandlerContext 内部类: HeadContext  TailContext  PendingHandlerCallback...  callback 作为了为handler添加删除创建的一个任务,会在相应的方法中进行回调实现对应的功能。

DefaultChannelHandlerContext:将handler包含在其中,作为handler 使用的文本切换。其实就是使用该链表的iteration进行切换而已。具体的方法会有下一个context方法的回调。

在boot.bind()  方法执行前首先我们创建了两个线程池。group1 和group2 group1 作为启动的注册和绑定的池子,group2 作为IO事件操作的池子。

在对NioEventLoopGroup  进行初始化的时候,我们使用了一个无参构造函数。其实它会调用该类的其他构造函数。可以思考的是,我们需要参数,数组的大小int  在NioEventExecutor 中的执行线程,线程工厂,Selector的构造器,执行option操作的策略模式工厂,rejectionhandler

初始化的时候,也会创建新的NioEventLoop并对其进行初始话。放入到Executor[ ] 数组中,对于NioEventGroup会添加对应的Listeners

ServerBootstrap 通过build方式创建类的初始化构造。

boot.bind()  在源码中我们会看到有两步操作。实际代码我会将他看成3步操作。

1:init

2:register

3:bind

1---第一步初始化的时候,是对channel做初始化操作,具体可以看ServerBootstrap。init(channel) 方法下的内容,值得注意的是在创建NioServerSocketChannel的时候,是通过反射的方式创建其本身类。具体的factory 是ReflectChannelFactory 创建,其中在创建该类时候,会对应的创建DefaulChannelPipeline  而DefaultChannelPipeline会创建HeadContext TailContext 构建初始化的链表。具体字段的初始化,不详细介绍,详细去看构造详情。值得注意的是在对DefaultChannelPipeline 初始化后,会添加一个ChannelInitializer<Channel>  handler 该handler添加细节详细去看DefaultChannelPipeline 中的APi,其操作无非是因为还未注册eventLoop到channel上,会将其添加到ChannelPipeline 中PendingHandlerCallback 任务中,会在后面register 操作的时候回调:pipeline.invokeHandlerAddedIfneed() 调用该handler的初始化方法。;

2-----第二步的操作在AbstractBootstrap 下进行的  confg().group().register(channel);该register的方法调用流程详细看源码操作。其中最重要的一个点是在eventloop.inEventLoop() 做判断的时候,要看下源码中关于execute()方法是如何执行的,在AbstractChannel,register(executor,promise)时候,是一个单线程,如果在main线程中,此时,返回的是false。会执行添加一个任务到NioEventLoop中的taskQueue中。需要注意的是,并没有立即执行,但是会调用执行NioEventLoop下的线程executor 会execute(task)该任务会创建Thread调用NioEventLoop下的run() 方法 也就是会根据策略实现是否开始selector()轮询的操作。 其中taskQueue 中的任务会根据该run()方法下策略情况调用该任务中的run()方法,而并不是新建线程执行该类的方法。因此在后面的代码中关于eventLoop().execute(Runnable task) 时候,要注意并没有开启一个线程。因此到目前为止 也就是开启了两个线程。main 线程和 group1 命名的线程1。最终的register 就是根据NioServerSocketChannel下的Unsafe类进行了具体的注册。其实质本身是使用java APi 下的ServerSocketChannel.register()方法。

3----第三步的操作是对应的bind(SocketAddress) 此时也是将会新建一个任务将其添加到taskQueue中,在线程循环for(;;)中根据情况调用run()方法。在该线程中对NioEventLoop 下的IntSupplier 下的方法调用,主要是开始selectNow()方法调用时候,由于已经注册和绑定 ,会在循环的操作下进行轮询 操作,根据option的策略,进行事件的传播,进行handler传递操作。

当然其中read和write操作主要是通过Accepter 来完成这样的操作。具体详细的情况查看APi,或后续待介绍。

文字并不多,但是需要查看的类和方法是非常多,以及逻辑是根据反复查看源码得到的对自己精简的心得。

源码中有些操作是值得学习的。类的config类,是对相互的引用。如何通过修改config改变其中的内容,另外在其他的类中也反复涉及到这种使用。当然源码中也多次对回调函数的使用。逻辑上要非常的谨慎。

 

netty ServerBootStrap的启动

原文:https://www.cnblogs.com/futureT/p/13601061.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!