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

这篇具有很好参考价值的文章主要介绍了[Netty源码] 服务端启动过程 (二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.ServerBootstrap

ServerBootstrap引导服务端启动流程:

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


//主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

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

AbstractBootstrap.bind()

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

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

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

AbstractBootstrap.initAndRegister()

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

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

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

AbstractBootstrap.channel() 反射创建Channel

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

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

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

3.2 初始化服务端Channel

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

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

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

    @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));
                    }
                });
            }
        });
    }

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

设置 currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs

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

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

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

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

3.3 注册selector

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

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

AbstractChannel.AbstractUnsafe.register()

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

register0()

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

AbstractNioChannel.doRegister()

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

上面有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()方法

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

AbstractChannlHandlerContext.invokeBind()

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

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方法,

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

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

3.5 服务端的读事件

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

AbstractChannel.AbstractUnsafe.bind()

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

HeadContext.channelActive()

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

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

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

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

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

AbstractUnsafe.beginRead()

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

AbstractNioChannel.doBeginRead()

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

这里的readInterestOp就是Acept事件

服务端端口绑定成功, 触发一个Acept事件, 然后调用channel.read()事件, 对于服务端来说就相当于可以读了, 可以读取一个新的连接。文章来源地址https://www.toymoban.com/news/detail-412930.html

到了这里,关于[Netty源码] 服务端启动过程 (二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring架构篇--2.7.2 远程通信基础--Netty原理--ServerBootstrap

    前言:已经初始化了NioEventLoopGroup 的boosGroup 和 workerGroup ,那么ServerBootstrap的作用是干嘛的呢 ,本文在Spring架构篇–2.7.1 远程通信基础–Netty原理–NioEventLoopGroup 之后继续进行探究 1 首先回顾下 nettt 的使用demo: 可以看到ServerBootstrap 的对象做了一系列的配置后最终 通过 bind

    2024年02月08日
    浏览(23)
  • 【Zookeeper源码走读】第二章 服务器的启动过程

    通过运行zk的启动脚本,找到zk服务器端的入口类。脚本如下: 所以,zk的入口类是 QuorumPeerMain ,以下是该类的 main() 方法的完整代码: 跟踪方法中的 initializeAndRun() ,代码如下: 方法中,继续跟踪 ZooKeeperServerMain.main(args) ,代码如下: 上面的代码就是初始化 ZooKeeperServerMai

    2024年02月03日
    浏览(27)
  • 31.Netty源码之客户端启动流程

    如果看了服务器端的启动流程,这里简单看下就可以了。 java package io.netty.server; ​ import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; ​ ​ public final class EchoClient { ​

    2024年02月12日
    浏览(29)
  • 14.Netty源码之模拟简单的HTTP服务器

    HTTP 服务器是我们平时最常用的工具之一。同传统 Web 容器 Tomcat、Jetty 一样,Netty 也可以方便地开发一个 HTTP 服务器。我从一个简单的 HTTP 服务器开始,通过程序示例为你展现 Netty 程序如何配置启动,以及引导器如何与核心组件产生联系。 完整地实现一个高性能、功能完备、

    2024年02月15日
    浏览(33)
  • 32.Netty源码之服务端如何处理客户端新建连接

    Netty 服务端完全启动后,就可以对外工作了。接下来 Netty 服务端是如何处理客户端新建连接的呢? 主要分为四步: md Boss NioEventLoop 线程轮询客户端新连接 OP_ACCEPT 事件; ​ 构造 初始化Netty 客户端 NioSocketChannel; ​ 注册 Netty 客户端 NioSocketChannel 到 Worker 工作线程中; ​ 从

    2024年02月12日
    浏览(31)
  • Seata AT模式源码解析一(Seata Server端启动流程)

    seata-server的入口类在Server类中,源码如下: 在阅读源码的时候,有些源码是要细看的,但是有些源码可以大致猜测一下它的作用,就直接略过去了,抓住真正的重点去看。 SessionHolder负责Session的持久化,一个session对象代表一个事务。SessionHolder包含了4个session管理器,用来操

    2024年02月07日
    浏览(26)
  • Activity启动过程详解(Android 12源码分析)

    启动一个Activity,通常有两种情况,一种是在应用内部启动Activity,另一种是Launcher启动 1、应用内启动 通过startActivity来启动Activity 启动流程: 一、Activity启动的发起 二、Activity的管理——ATMS 三、线程切换即消息处理——mH 四、Activity启动核心实现——初始化及生命周期 2、

    2024年02月13日
    浏览(38)
  • docker服务启动过程分析

    How  docker.service start? just by ref 我们先了解docker的各个核心组件的介绍 runc:runc实现了容器的底层功能,例如创建、运行等。runc通过调用内核接口为容器创建和管理cgroup、namespace等Linux内核功能,来实现容器的核心特性。runc是一个可以直接运行的二进制程序,对外提供的接口

    2024年02月12日
    浏览(24)
  • Android 12 源码分析 —— 应用层 二(SystemUI大体组织和启动过程)

    在前一篇文章中,我们介绍了SystemUI怎么使用IDE进行编辑和调试。这是分析SystemUI的最基础,希望读者能尽量掌握。 本篇文章,将会介绍SystemUI的大概组织架构,以及它的启动过程。本篇文章读完,将会知道: SystemUI为什么选择使用Dagger2 SystemUI怎么新建一个模块 SystemUI的启动

    2024年02月06日
    浏览(56)
  • Elasticsearch 8.9启动时构建接收Rest请求的hander过程源码

    路径: org.elasticsearch.bootstrap.Elasticsearch 这里初始化会有三个初始化阶段。可以直接看 initPhase3 其中 INSTANCE.start(); 如下,代表node启动,并且存活线程运行 其中调用 RestHandler 接口的 handerRequest 的上游是 其他注册在 hander 中的API和 RestGetIndicesAction 类似

    2024年02月07日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包