Netty服务端源码流程分析

Netty服务端源码流程分析

本节将简单分析下netty服务端的创建过程

1、服务端创建代码如下

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(); 
        try {
            //创建服务器端的启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup) 
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128) 
                    .childOption(ChannelOption.SO_KEEPALIVE, true) 
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //给pipeline 设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("客户socketchannel hashcode=" + ch.hashCode()); 
                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    }); 
            System.out.println(".....服务器 is ready...");
            //绑定一个端口并且同步, 生成了一个 ChannelFuture 对象
            //启动服务器(并绑定端口)
            ChannelFuture cf = bootstrap.bind(6668).sync();
            //给cf 注册监听器,监控我们关心的事件
            cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (cf.isSuccess()) {
                        System.out.println("监听端口 6668 成功");
                    } else {
                        System.out.println("监听端口 6668 失败");
                    }
                }
            });
            //对关闭通道进行监听
            cf.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

1.1、 创建NioEventLoopGroup

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
传入了一个默认的select策略工厂,INSTANCE信息如下图
在这里插入图片描述

继续调用构造方法
在这里插入图片描述
调用父类方法
在这里插入图片描述
在这里插入图片描述
由于我们没有设置系统属性变量io.netty.eventLoopThreads,所以DEFAULT_EVENT_LOOP_THREADS当前会取1,当前args可变数组中目前数据为
在这里插入图片描述
在这里插入图片描述
增加了DefaultEventExecutorChooserFactory
在这里插入图片描述

进入newChild方法
在这里插入图片描述
创建NioEventLoop对象,返回赋值给children数组
在这里插入图片描述

在这里插入图片描述

1.2、创建ServerBootstrap并配置参数

  • 1.2.1、设置两个线程组

在这里插入图片描述
将bossGroup设置到父类的group属性
将workGroup设置到childGroup属性

  • 1.2.2、使用NioSocketChannel 作为服务器的通道实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
创建ReflectiveChannelFactory对象并赋值给ServerBootstrap父类的channelFactory属性

  • 1.2.3、设置线程队列得到连接个数
    在这里插入图片描述
    在这里插入图片描述
  • 1.2.4、设置childHandler
    在这里插入图片描述

在这里插入图片描述

1.3、绑定端口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
进入initAndRegister,分为init和register两个部分
在这里插入图片描述

  • init方法

图3↓
在这里插入图片描述
给当前channel的pipeline添加handler()
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

封装handler为DefaultChannelHandlerContext其父类为AbstractChannelHandlerContext,加入head和tail之间
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

将handler封装到PendingHandlerAddedTask对象中并将task对象赋值给pipeline的pendingHandlerCallbackHead属性
在这里插入图片描述
回到注册方法

  • register
    在这里插入图片描述
    在这里插入图片描述
    1、调用next方法选择一个线程
    在这里插入图片描述
    2、调用NioEventLoop的注册方法(SingkeThreadEventLoop是NioEventLoop的父类)
    在这里插入图片描述

在这里插入图片描述
先将channel封装到DefaultChannelPromise中
在这里插入图片描述
图1↓****
在这里插入图片描述
启动线程前,添加任务到线程的队列中
在这里插入图片描述
在这里插入图片描述
启动线程,进入线程run方法
图4↓
在这里插入图片描述
接上图
在这里插入图片描述

调用hasTasks判断是否有任务
在这里插入图片描述
有任务就调用selectSupplier获取
在这里插入图片描述
在这里插入图片描述
此时结果返回0执行runAllTasks方法
在这里插入图片描述
拉取任务从队列中
在这里插入图片描述
在这里插入图片描述
任务是图1中的register0方法,回到图1位置

在这里插入图片描述
图2↓
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注册主要就是将channel放入select中,并分配ops(个人理解,欢迎指正)
回到图2位置,调用invokeHandlerAddedIfNeeded
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
pendingHandlerCallbackHead是我们之前在init时放入的匿名对象(handler被封装成DefaultChannelHandlerContext继续封装到PendingHandlerAddedTask对象),见图3

调用task的execute方法,此时task就说封装了DefaultChannelHandlerContext的PendingHandlerAddedTask

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
调用initChannel,回到图3位置init代码流程
在这里插入图片描述
如果之前配置了handler,此时会将handler放入pipeline中,我们没有配置,只配置了childHandler,此时会创建ServerBootstrapAcceptor,放入pipeline中
在这里插入图片描述

 private static class ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter {

        private final EventLoopGroup childGroup;
        private final ChannelHandler childHandler;
        private final Entry<ChannelOption<?>, Object>[] childOptions;
        private final Entry<AttributeKey<?>, Object>[] childAttrs;
        private final Runnable enableAutoReadTask;

        ServerBootstrapAcceptor(
                final Channel channel, EventLoopGroup childGroup, ChannelHandler childHandler,
                Entry<ChannelOption<?>, Object>[] childOptions, Entry<AttributeKey<?>, Object>[] childAttrs) {
            this.childGroup = childGroup;
            this.childHandler = childHandler;
            this.childOptions = childOptions;
            this.childAttrs = childAttrs;

         
            enableAutoReadTask = new Runnable() {
                @Override
                public void run() {
                    channel.config().setAutoRead(true);
                }
            };
        }

        @Override
        @SuppressWarnings("unchecked")
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            final Channel child = (Channel) msg;
            child.pipeline().addLast(childHandler);
            setChannelOptions(child, childOptions, logger);
            setAttributes(child, childAttrs);
            try {
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }
        ...

回到图4,之前注册的操作是在runAllTasks中获取任务并执行的,继续图4的线程循环,获取任务不存在,
在这里插入图片描述
调用select 阻塞线程
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值