[Netty源码] 服务端启动过程 (二)

news2024/9/28 21:18:37

文章目录

      • 1.ServerBootstrap
      • 2.服务端启动过程
      • 3.具体步骤分析
        • 3.1 创建服务端Channel
        • 3.2 初始化服务端Channel
        • 3.3 注册selector
        • 3.4 端口绑定
        • 3.5 服务端的读事件

1.ServerBootstrap

ServerBootstrap引导服务端启动流程:

在这里插入图片描述


//主EventLoopGroup
NioEventLoopGroup master = new NioEventLoopGroup();
//从EventLoopGroup
NioEventLoopGroup worker = new NioEventLoopGroup();
//服务端引导类
ServerBootstrap bootstrap = new ServerBootstrap();
//配置主从EventLoopGroup
bootstrap.group(master, worker);
//channel选项配置
bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
  .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000);
bootstrap.channel(NioServerSocketChannel.class);
//主EventLoopGroup ChannelHandler配置
bootstrap.handler(new ChannelInboundHandlerAdapter(){
  @Override
  public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
    System.out.println("Master:" + ctx.channel().eventLoop().toString());
    super.channelRegistered(ctx);
  }
});
//从EventLoopGroup ChannelHandler配置
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
  @Override
  protected void initChannel(SocketChannel ch) throws Exception {
    System.out.println("Child:" + ch.eventLoop().toString());
  }
});
//调用bind方法开始监听端口8888
ChannelFuture future = bootstrap.bind(8888).sync();
future.channel().closeFuture().sync();

master.shutdownGracefully().sync();

以上代码使用的是Netty框架中经典的主从事件驱动模式

2.服务端启动过程

  1. main方法调用ServerBootstrap.bind()方法

  2. validate()方法验证必要配置参数

  3. 调用AbstractBootstrap.initAndRegister()方法

  4. 调用channelFactory.newChannel()方法创建Channel实例

  5. ServerBootstrap.init()初始化Channel实例,配置ChannelOption、attributes;在Channel的pipeline中配置默认的ChannelHandler实例

  6. 将Channel实例注册到主EventLoopGroup中并返回ChannelFuture

  7. 注册ChannelFuture回调,在完成后调用channel.bind()方法完成端口监听

3.具体步骤分析

1.创建服务端Channel
2.初始化服务端Channel
3.注册Selector
4.端口绑定
5.触发读事件

3.1 创建服务端Channel

在这里插入图片描述

AbstractBootstrap.bind()

在这里插入图片描述

  1. validate(): 验证必要配置参数
  2. AbstractBootstrap.doBind()

在这里插入图片描述

AbstractBootstrap.initAndRegister()

在这里插入图片描述

  1. 利用反射创建Channel, 得到NioServerSocketChannel
  2. 初始化channel中的一些参数

在这里插入图片描述

AbstractBootstrap.channel() 反射创建Channel

在这里插入图片描述

利用反射创建channel, 得到ReflectiveChannelFactory, 调用channelFactory利用工厂模式, 最后生成NioServerSocketChannel

在这里插入图片描述

3.2 初始化服务端Channel

ServerBootstrap.init() 初始化一些基本参数

初始化一些Options和Attrs和group和handler的参数

在这里插入图片描述

    @Override
    void init(Channel channel) throws Exception {
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }

        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(0));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
        }

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

在这里插入图片描述

设置 currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs

在这里插入图片描述

在Channel的pipeline中配置默认的ChannelHandler实例

在这里插入图片描述

ServerBootstrapAcceptor 添加连接器, ServerBootstrapAcceptor本质是一个handler

3.3 注册selector

bind -> initAndRegister -> AbstractChannel.register -> this.eventLoop = eventLoop, register0 实际注册 -> doRegister(), invokeHandlerAddedIfNeeded(), fireChannelRegistered() 传播事件

在这里插入图片描述

AbstractChannel.AbstractUnsafe.register()

在这里插入图片描述

register0()

在这里插入图片描述

AbstractNioChannel.doRegister()

在这里插入图片描述

上面有javaChannel.register(), 利用jdk底层去创建selector

3.4 端口绑定

bind() -> doBind() -> doBind0() -> AbstracChannel,bind() -> DefaultChannelPipeline.bind() -> AbstractChannlHandlerContext.bind() -> AbstractChannlHandlerContext.invokeBind() -> DefaultChannelPipeline.HeadContext.bind() -> NioSocketChannel.doBind0(), pipeline.fireChannelActive();

最后将会调用DefaultChannelPipeline.HeadContext.bind(), 因为DefaultChannelPipeline在初始化时会设置pipeline队列的首尾分别为DefaultChannelPipeline.HeadContext与DefaultChannelPipeline.TailContext
bind()在Pipeline中走的是出站方法,是从管道的后面向前走,最后到达管道头部的ChannelHandler(也就是DefaultChannelPipeline.HeadContext),这一过程会调用同一方向上所有ChannelHandler的bind()事件。

AbstractBootstrap.doBind0(): 添加一个任务至EventLoop中, 最后将会调用DefaultChannelPipeline.HeadContext.bind()方法

在这里插入图片描述

AbstractChannlHandlerContext.invokeBind()

在这里插入图片描述

DefaultChannelPipeline.HeadContext.bind() -> AbstractChannel.AbstractUnsafe.bind()

        @Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();
            
            if (!promise.setUncancellable() || !ensureOpen(promise)) {
                return;
            }
            
            boolean wasActive = isActive();
            try {
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }

            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }
  1. NioSocketChannel.doBind() -> NioSocketChannel.doBind0()
  2. pipeline.fireChannelActive()

通过在pipline中的层层传递, 现在来到了最终执行bind操作的终点, 执行bind方法,

在这里插入图片描述

可以通过SocketUtils.bind() 绑定JDK底层的端口

3.5 服务端的读事件

最后如果触发了一个事件的话, 会调用Channel.read()事件(AbstractNioChannel.doBeginRead()), 这个事件对于服务端来说就是一个新的连接接入。

AbstractChannel.AbstractUnsafe.bind()

在这里插入图片描述

HeadContext.channelActive()

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

这个tail.read(), 触发的是beginRead()方法

AbstractUnsafe.beginRead()

在这里插入图片描述

AbstractNioChannel.doBeginRead()

在这里插入图片描述

这里的readInterestOp就是Acept事件

服务端端口绑定成功, 触发一个Acept事件, 然后调用channel.read()事件, 对于服务端来说就相当于可以读了, 可以读取一个新的连接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/429743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入浅出:理解 RPC 和 Dubbo 架构

简介 Apache Dubbo是一款高性能的Java RPC框架.其前身是阿里巴巴公司开源的一个高性能,轻量级的开源Java RPC框架,可以和Spring框架无缝集成. Dubbo 官网 RPC RPC介绍 Remote Procedure Call 远程过程调用,是分布式架构的核心,按响应方式分以下两种: 同步调用:客户端调用…

App/Web自动化的面试题

App/Web自动化的面试题&#xff08;详细答案自己百度哈,红色的表示app自动化专有问题、绿色表示web自动化专有的问题&#xff0c;未标色的表示共有的问题&#xff09; 备注&#xff1a;一般面试的时候是结合简历上的项目一步一步深入进行问的问题&#xff0c;只要你实际做过一个…

HPE: smart storage: hpssacli:

文章目录参考命令实例问题参考 https://cmdref.net/hardware/proliant/hpssacli.html https://support.hpe.com/connect/s/softwaredetails?languageen_US&softwareIdMTX_9849e3ae326f43f2825d92dce0 https://community.hpe.com/hpeb/attachments/hpeb/itrc-264/148204/3…

SpringBoot—JPA和Mybatis多数据源配置和使用

JPA多数据源配置 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apa…

VM 增加硬盘

1、使用“fdisk -l”的命令查看当前系统的分区&#xff08;如果刚才设置VMware--“设置”的时候运行了系统&#xff0c;则会出现下图情况&#xff1a;没有识别到新的磁盘即sdb&#xff09;&#xff0c;解决办法&#xff0c;重启虚拟机&#xff1a;shutdown -r now 2、 输入 # …

【Python_Selenium学习笔记(八)】基于Selenium模块实现滑块验证码破解

基于Selenium模块实现滑块验证码破解 前言 有些网站页面会在 访问时进行滑块验证&#xff0c;针对此问题&#xff0c;此篇文章中会介绍如何基于 Selenium 模块实现滑块验证码的破解 &#xff0c;并以模拟登录豆瓣网&#xff0c;破解其滑块验证码 为例进行讲解。 正文 1、滑…

需要买apple pencil吗?ipad第三方电容笔了解下

第一款ipad早在诞生于十年前&#xff0c;并被作为一款平板电脑使用&#xff0c;其性能十分出色。随着IPAD的不断更新换代&#xff0c;IPAD已经被越来越多的人接受了。其中&#xff0c;iPad的附属配件起到了很大的作用&#xff0c;就像今天要介绍的电容笔&#xff0c;它是我们进…

Python接外包养无敌可爱的她,每天都随便花~

人生苦短&#xff0c;我用python 女友好不容易放假&#xff0c;她带着我花花花的样子真的很迷人~ python 安装包资料:点击此处跳转文末名片获取 不为什么 我的女友我来宠&#xff01; 作为一个程序员&#xff0c;要有会用自己的技术创造价值的自觉~ 今天来给大家展示一下用py…

第七章 法律行为与法律意识

目录 第一节 法律行为 一、 法律行为的含义与特征二、 法律行为的结构 &#xff08;一&#xff09;法律行为的内在方面 动机目的认知能力 &#xff08;二&#xff09;法律行为的外在方面 行动&#xff08;行为&#xff09;手段结果 三、法律行为的分类 第二节 法律意识 一、法…

【WebRTC技术专题】大势所趋,迈向认识 WebRTC 的第一步(2)

每日一句 人生的挑战&#xff0c;无处不在&#xff0c;满怀信心&#xff0c;轻装上路&#xff0c;明天永远是充满希望的战场。 承接上文 承接上文的内容介绍完相关WebRTC技术的概念和发展历程后&#xff0c;开始初步摸索一下相关WebRTC技术的功能和原理。&#x1f33a;【WebRTC…

【科普】一篇搞定发paper基本概念:SCI、EI、会议/期刊、分区、CCF、DOI、IF、h-index、及cs/ee常见会议:CVPR、GlobeCOM等

文章目录基础概念SCI、EI、CPCI&#xff08;ISTP&#xff09;论文类型&#xff1a;Journal、magazine、transaction、letter、 proceedingsDOI&#xff08;数字对象标识Digital Object Identifier&#xff09;IF 期刊影响因子(Impact Factor&#xff0c;IF)H指数 (h-index/h-fa…

时间序列 | MATLAB实现CNN-LSTM-Attention时间序列预测

时间序列 | MATLAB实现CNN-LSTM-Attention时间序列预测 目录时间序列 | MATLAB实现CNN-LSTM-Attention时间序列预测预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现CNN-LSTM-Attention时间序列预测&#xff0c;CNN-LSTM结合注意力机制时间序列预测。 模…

使用wait监听tomcat服务启动

文章的wait脚本素材会放在末尾 执行docker-compose.yml文件之后就有mysql的主服务器&#xff0c;还有从服务器&#xff0c;还有tomcat服务&#xff0c;在tomcat中部署一个crm项目&#xff0c;tomcat服务中我们添加了启动顺序&#xff0c; # 启动顺序 depends_on: - mysql…

低压接地系统:TN-C 、TN-S、TN-C-S、TT、IT

电力系统的接地直接关系到用户的人身和财产安全,以及电气设备和电子设备的正常运行。如何针对实际情况选择合适的接地系统,确保配电系统及电气设备的安全使用,是电气设计人员面临的首要问题。 根据 国际电工委员会(IEC)规定的各种保护接地方式的术语概念,低压配电系统按…

如何利用开源思想开发一个SEO友好型网站

当你对一个网站进行 SEO 优化的时候&#xff0c;不要期望你的努力能立即得到回报。耐心等待并更正内容营销策略&#xff0c;最终会发现你的网站很受用户欢迎。下面就教你如何利用开源思维开发一个SEO友好型网站&#xff01; 首先&#xff0c;你应该知道&#xff1a;93% 的网站…

修复开源VS Code 插件Trino Driver的三个小问题

前言 最近产品中使用到一款SQLTools的VS Code插件。该插件可以在VS Code中实现数据库管理&#xff0c;而且支持非常多的数据源类型&#xff0c; 官方的数据源类型有CockroachDB&#xff0c;MariaDB&#xff0c;MySQL&#xff0c;PostgreSQL&#xff0c;SQLite&#xff0c;Micr…

电脑录屏按哪个键?您可以这样操作!

案例&#xff1a;电脑按哪3个键&#xff0c;可以录屏&#xff1f; 【我平常喜欢使用快捷键在电脑上快速完成一些操作。最近接触到了电脑录屏&#xff0c;感觉使用它一系列的操作比较麻烦。想在这里问问小伙伴们&#xff0c;有没有使用快捷键成功操作过的朋友&#xff01;】 电…

【Linux】页表的深入分析

上一篇文章介绍了线程的基本概念 而本篇文章我们来深入理解一下, CPU再调度我们以往理解的进程和如今的线程都会涉及到的一个内容: 页表 文章目录深入理解页表 *页表的实际组成*什么是page&#xff1f;深入理解页表 * 在介绍进程时, 博主没有深入介绍过页表. 只是简单说了 页…

DAY 40 firewalld 防火墙

firewalld防火墙是centos7系统默认的防火墙管理工具&#xff0c;取代了之前的iptables防火墙&#xff0c;也是工作在网络层&#xff0c;属于包过滤防火墙。 支持IPv4、IPv6防火墙设置以及以太网桥支持服务或应用程序直接添加防火墙规则接口拥有两种配置模式&#xff1a;临时模…

【快乐手撕LeetCode题解系列】—— 环形链表 II

【快乐手撕LeetCode题解系列】—— 环形链表 II&#x1f60e;前言&#x1f64c;环形链表 II&#x1f64c;画图分析&#xff1a;&#x1f60d;思路分析&#xff1a;&#x1f60d;源代码分享&#xff1a;&#x1f60d;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客…