Netty Review - NioServerSocketChannel源码分析

news2025/1/21 8:57:37

文章目录

  • 概述
  • 入口
  • NioServerSocketChannel 类继承关系
  • 实例化过程中做的事情
  • 小结

在这里插入图片描述

在这里插入图片描述


概述

在这里插入图片描述


入口

ChannelFuture channelFuture = serverBootstrap.bind(9000).sync();

我们进入bind方法

/**
 * Create a new {@link Channel} and bind it.
 */
public ChannelFuture bind(int inetPort) {
    // 调用bind方法,并传入一个InetSocketAddress对象,其中端口号由参数inetPort指定
    return bind(new InetSocketAddress(inetPort));
}

这个方法的作用是创建一个新的Channel并绑定到指定的端口。它首先创建一个InetSocketAddress对象,该对象包含了要绑定的端口号,然后调用bind方法将新创建的Channel绑定到该InetSocketAddress。

这个方法的参数inetPort表示要绑定的端口号。通过调用bind(int inetPort)方法,可以方便地将新创建的Channel绑定到指定的端口。


final ChannelFuture regFuture = initAndRegister();

继续跟进去会进到 io.netty.bootstrap.AbstractBootstrap#doBind

    private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
 		......
 		......      
}

我们重点关注 initAndRegister

这段代码是NioServerSocketChannel类中的一个私有方法,用于初始化并注册一个新的Channel。让我们逐步解释它:

```java
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
        // 使用ChannelFactory创建一个新的Channel实例
        channel = channelFactory.newChannel();
        // 初始化Channel,包括设置Channel的配置、分配Channel的ID等
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            // 如果Channel已经创建但是初始化过程中发生了异常,则强制关闭Channel
            channel.unsafe().closeForcibly();
            // 创建一个新的ChannelPromise并设置异常
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        // 如果Channel还未创建就发生了异常,则创建一个FailedChannel实例,并设置异常
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }

    // 将Channel注册到EventLoopGroup中,并获取注册结果
    ChannelFuture regFuture = config().group().register(channel);
    // 如果注册过程中出现了异常
    if (regFuture.cause() != null) {
        // 如果Channel已经注册成功,直接关闭Channel
        if (channel.isRegistered()) {
            channel.close();
        } else {
            // 如果Channel尚未注册成功,强制关闭Channel
            channel.unsafe().closeForcibly();
        }
    }

    // 返回注册结果
    return regFuture;
}

这个方法的作用是初始化并注册一个新的Channel。它首先使用ChannelFactory创建一个新的Channel实例,然后调用init方法对其进行初始化。如果在初始化过程中发生了异常,则会强制关闭Channel,并返回一个带有异常的ChannelPromise。

接着,它将新创建的Channel注册到指定的EventLoopGroup中,并获取注册结果。如果注册过程中出现了异常,则会根据Channel是否已经注册成功来决定是直接关闭Channel还是强制关闭Channel。最后,返回注册结果。

这个方法的设计使得在初始化和注册Channel的过程中能够处理各种异常情况,并保证Channel的状态正确。


我们重点关注 channelFactory.newChannel();在这里插入图片描述

在这里插入图片描述

来会看一下

在这里插入图片描述


那就继续 NioServerSocketChannel的构造函数 ,这里就是 NioServerSocketChannel初始化的地方 。


NioServerSocketChannel 类继承关系

在这里插入图片描述


实例化过程中做的事情

    @Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

从上面的源码中,我们可以知道必然是无参构造函数 。

无参构造函数

/**
 * Create a new instance
 */
public NioServerSocketChannel() {
    // 调用另一个构造函数,传入一个新创建的Java NIO ServerSocketChannel实例
    this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}

这段代码是NioServerSocketChannel类的构造函数,它调用了另一个私有构造函数来创建一个新的NioServerSocketChannel实例。

这个构造函数的作用是创建一个新的NioServerSocketChannel实例。它通过调用另一个私有构造函数来完成实例的创建过程。在调用私有构造函数时,传入了一个新创建的Java NIO ServerSocketChannel实例作为参数。

这样,NioServerSocketChannel实例就会持有这个Java NIO ServerSocketChannel实例,并在需要时对其进行操作。


`newSocket

我们继续看下 newSocket

private static ServerSocketChannel newSocket(SelectorProvider provider) {
    try {
        // 使用指定的SelectorProvider打开一个新的ServerSocketChannel  (熟悉的NIO代码)
        return provider.openServerSocketChannel();
    } catch (IOException e) {
        // 如果发生异常,则抛出ChannelException异常
        throw new ChannelException("Failed to open a server socket.", e);
    }
}
 private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

这段代码是NioServerSocketChannel类中的一个私有静态方法,用于使用指定的SelectorProvider创建一个新的ServerSocketChannel。

这个方法的作用是使用指定的SelectorProvider打开一个新的ServerSocketChannel。在Java NIO中,SelectorProvider用于提供新的SelectableChannel实例。方法首先调用指定的SelectorProvider的openServerSocketChannel()方法来创建一个新的ServerSocketChannel实例。如果创建过程中发生了IO异常,则会捕获并抛出ChannelException异常。

provider.openServerSocketChannel() 熟悉的NIO代码


this(newSocket(DEFAULT_SELECTOR_PROVIDER));

/**
 * Create a new instance using the given {@link ServerSocketChannel}.
 */
public NioServerSocketChannel(ServerSocketChannel channel) {
    // 调用父类构造函数,传入null作为EventLoopGroup参数(因为NioServerSocketChannel没有父类EventLoopGroup),传入给定的ServerSocketChannel实例以及OP_ACCEPT作为感兴趣的事件
    super(null, channel, SelectionKey.OP_ACCEPT);
    // 创建一个新的NioServerSocketChannelConfig实例,用于配置NioServerSocketChannel的参数
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

这段代码是NioServerSocketChannel类的另一个构造函数,它接受一个ServerSocketChannel实例作为参数,并调用父类构造函数来初始化NioServerSocketChannel实例。

这个构造函数的作用是使用给定的ServerSocketChannel实例来创建一个新的NioServerSocketChannel实例。

在构造函数中,首先调用了父类AbstractNioMessageChannel的构造函数,传入了null作为EventLoopGroup参数(因为NioServerSocketChannel没有父类EventLoopGroup)、给定的ServerSocketChannel实例以及OP_ACCEPT作为感兴趣的事件。

然后,创建一个新的NioServerSocketChannelConfig实例,用于配置NioServerSocketChannel的参数。

在这里插入图片描述

SelectionKey.OP_ACCEPT是Java NIO中SelectableChannel所支持的一种操作兴趣标志。在Netty中,它通常用于NioServerSocketChannel,用于指示对新连接请求的接受操作感兴趣。

具体来说,SelectionKey.OP_ACCEPT表示SelectableChannel对新连接请求的接受操作感兴趣。当有新的连接请求到达时,Selector会将该事件通知给对应的SelectableChannel,并在之后的事件循环中处理该连接请求。在Netty中,NioServerSocketChannel通常会注册SelectionKey.OP_ACCEPT事件,以便及时响应新的连接请求。

通过使用这个操作兴趣标志,Netty能够利用Java NIO的非阻塞IO特性,实现高效的TCP服务器端编程,能够处理大量并发的连接请求,提高系统的性能和并发能力。

在这里插入图片描述


super(null, channel, SelectionKey.OP_ACCEPT)

这段代码是AbstractNioChannel类的受保护构造函数,用于创建一个新的AbstractNioChannel实例。让我们逐步解释它:

/**
 * Create a new instance
 *
 * @param parent            the parent {@link Channel} by which this instance was created. May be {@code null}
 * @param ch                the underlying {@link SelectableChannel} on which it operates
 * @param readInterestOp    the ops to set to receive data from the {@link SelectableChannel}
 */
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
    // 调用父类构造函数,传入父Channel实例
    super(parent);
    // 初始化成员变量,保存SelectableChannel和读取操作的兴趣操作
    this.ch = ch;
    this.readInterestOp = readInterestOp;
    try {
        // 将SelectableChannel设置为非阻塞模式  (熟悉的NIO方法)
        ch.configureBlocking(false);
    } catch (IOException e) {
        try {
            // 发生异常时关闭SelectableChannel
            ch.close();
        } catch (IOException e2) {
            if (logger.isWarnEnabled()) {
                logger.warn("Failed to close a partially initialized socket.", e2);
            }
        }
        // 抛出ChannelException异常
        throw new ChannelException("Failed to enter non-blocking mode.", e);
    }
}

这个构造函数用于创建一个新的AbstractNioChannel实例。

它接受三个参数:

  • 父Channel、
  • 底层的SelectableChannel
  • 读取数据时的操作兴趣标志。

在构造函数内部,首先调用了父类构造函数,将父Channel传入以便建立关系。然后,初始化了成员变量,保存了SelectableChannel和读取操作的兴趣标志。

接着,尝试将SelectableChannel设置为非阻塞模式。如果设置过程中发生IO异常,会关闭SelectableChannel并抛出ChannelException异常。


super(parent);

这段代码是AbstractChannel类的受保护构造函数,用于创建一个新的AbstractChannel实例。让我们逐步解释它:

/**
 * Creates a new instance.
 *
 * @param parent
 *        the parent of this channel. {@code null} if there's no parent.
 */
protected AbstractChannel(Channel parent) {
    // 将父Channel赋值给成员变量parent
    this.parent = parent;
    // 生成唯一的通道ID
    id = newId();
    // 创建一个新的Unsafe实例,用于执行底层操作
    unsafe = newUnsafe();
    // 创建一个新的ChannelPipeline实例,用于存储和处理ChannelHandler
    pipeline = newChannelPipeline();
}

这个构造函数用于创建一个新的AbstractChannel实例。它接受一个参数parent,用于指定这个Channel的父Channel。

在构造函数内部,首先将父Channel赋值给成员变量parent,然后生成一个唯一的通道ID,接着创建一个新的Unsafe实例用于执行底层操作,最后创建一个新的ChannelPipeline实例用于存储和处理ChannelHandler。

newChannelPipeline();创建一个新的ChannelPipeline实例,用于存储和处理ChannelHandler

/**
 * Returns a new {@link DefaultChannelPipeline} instance.
 */
protected DefaultChannelPipeline newChannelPipeline() {
    // 创建一个新的DefaultChannelPipeline实例,传入当前的Channel作为参数
    return new DefaultChannelPipeline(this);
}

这段代码是AbstractChannel类中的一个受保护方法,用于创建一个新的DefaultChannelPipeline实例。

这个方法用于创建一个新的DefaultChannelPipeline实例,并将当前的Channel作为参数传入。DefaultChannelPipeline是Netty中用于管理ChannelHandler链的默认实现。每个Channel都有自己的ChannelPipeline,用于存储和处理ChannelHandler。调用这个方法会创建一个新的ChannelPipeline实例,并将当前的Channel作为其所属的Channel。

protected DefaultChannelPipeline(Channel channel) {
    // 将传入的Channel赋值给成员变量channel
    this.channel = ObjectUtil.checkNotNull(channel, "channel");
    // 创建一个新的SucceededChannelFuture实例,表示成功的Future
    succeededFuture = new SucceededChannelFuture(channel, null);
    // 创建一个新的VoidChannelPromise实例,表示空的Promise
    voidPromise =  new VoidChannelPromise(channel, true);

    // 创建一个新的TailContext实例,表示管道中的尾部节点
    tail = new TailContext(this);
    // 创建一个新的HeadContext实例,表示管道中的头部节点
    head = new HeadContext(this);

    // 设置头部节点的下一个节点为尾部节点,尾部节点的上一个节点为头部节点
    head.next = tail;
    tail.prev = head;
}

这段代码是DefaultChannelPipeline类的受保护构造函数,用于创建一个新的DefaultChannelPipeline实例。

这个构造函数用于创建一个新的DefaultChannelPipeline实例。在构造函数内部,首先将传入的Channel赋值给成员变量channel,并创建了一个成功的Future实例(succeededFuture)和一个空的Promise实例(voidPromise)。

接着创建了头部节点(HeadContext)和尾部节点(TailContext),并设置头部节点的下一个节点为尾部节点,尾部节点的上一个节点为头部节点。

这样就构成了一个空的ChannelPipeline链表结构。


ch.configureBlocking(false)

ch.configureBlocking(false);熟悉的NIO代码

ch.configureBlocking(false)是将一个Java NIO的SelectableChannel配置为非阻塞模式。

在Java NIO中,SelectableChannel是一个可以注册到Selector上并监听IO事件的通道,比如SocketChannelServerSocketChannel等。在默认情况下,这些通道都是阻塞模式的,意味着当没有数据可读或无法写入时,读取和写入操作会一直阻塞当前线程,直到有数据可用或者通道关闭。

通过调用configureBlocking(false)方法,可以将这些通道配置为非阻塞模式。在非阻塞模式下,当没有数据可读或无法写入时,读取和写入操作会立即返回而不会阻塞当前线程,这样就可以在单个线程上处理多个通道的IO操作,提高了系统的并发处理能力。

在Netty中,通常会将SelectableChannel配置为非阻塞模式,以利用Java NIO的非阻塞IO特性,实现高效的事件驱动的网络编程。

在这里插入图片描述


小结

NioServerSocketChannel是Netty中用于处理TCP服务器端Socket的通道实现之一。它继承自AbstractNioMessageChannel,是基于Java NIO的ServerSocketChannel的封装。以下是关于NioServerSocketChannel的总结:

  1. 构造函数

    • 有两个构造函数:一个接受ServerSocketChannel实例作为参数,另一个不接受任何参数。
    • 构造函数负责初始化NioServerSocketChannel实例,其中包括调用父类构造函数、配置SelectableChannel为非阻塞模式等操作。
  2. 初始化和注册

    • 使用initAndRegister方法初始化和注册NioServerSocketChannel。
    • 在初始化过程中,会调用channelFactory.newChannel()方法创建一个新的NioServerSocketChannel实例,并初始化该实例。
    • 如果初始化过程中出现异常,会尝试关闭部分初始化的SocketChannel,并返回一个包含异常信息的DefaultChannelPromise实例。
  3. 功能和特性

    • 用于接受TCP连接请求,并创建对应的NioSocketChannel实例来处理连接。
    • 可以设置Channel的各种参数,如TCP参数、选项等。
    • 通过继承自AbstractNioMessageChannel,具有处理读写事件的能力。
  4. 底层实现

    • 使用了Java NIO的ServerSocketChannel来处理TCP连接请求。
    • 通过配置SelectableChannel为非阻塞模式,实现了高性能的非阻塞IO操作。

综上所述,NioServerSocketChannel是Netty中用于处理TCP服务器端Socket的通道实现,它基于Java NIO,提供了高性能的非阻塞IO操作,并具有初始化、注册、配置参数等功能。

在这里插入图片描述

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

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

相关文章

【学网攻】 第(26)节 -- 综合网络实验一

系列文章目录 目录 系列文章目录 文章目录 前言 一、综合实验 二、实验 1.引入 实验目标 实验设备 实验拓扑图 实验配置 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4)节…

Ubuntu Desktop - Files Preferences

Ubuntu Desktop - Files Preferences 1. Behavior2. ViewsReferences 1. Behavior Go to file browser’s Menu -> Edit -> Preferences -> Behavior 2. Views Go to file browser’s Menu -> Edit -> Preferences -> Views ​​​ References [1] Yong…

猫头虎分享已解决Bug || AttributeError: ‘Sequential‘ object has no attribute ‘session‘

博主猫头虎的技术世界 🌟 欢迎来到猫头虎的博客 — 探索技术的无限可能! 专栏链接: 🔗 精选专栏: 《面试题大全》 — 面试准备的宝典!《IDEA开发秘籍》 — 提升你的IDEA技能!《100天精通鸿蒙》 …

盘点数据可视化大屏焦点图十种样式

所谓焦点图就是大屏中居于中心位置的图,是视觉的中心,本位列举了十种焦点图样式供大家参考。 地球作为焦点图 图片来自网络 地图作为焦点图 图片来自网络 城市作为焦点图 图片来自网络 园区做焦点图 图片来自网络 建筑做焦点图 图片来自网络 生产线…

【lesson51】信号之信号处理

文章目录 信号处理可重入函数volatileSIGCHLD信号 信号处理 信号产生之后,信号可能无法被立即处理,一般在合适的时候处理。 1.在合适的时候处理(是什么时候?) 信号相关的数据字段都是在进程PCB内部。 而进程工作的状态…

Centos9部署LAMP

配置LAMP 参考文档 https://blog.csdn.net/weixin_51432789/article/details/112254685 首先安装 yum install -y libxml2-devel 安装apr-1.7.4 解压 tar xf apr-1.7.4.tar.gz 安装以来 yum -y install gcc cd apr-1.7.4/ 预编译 ./configure --prefix/usr/local/…

RK3588平台开发系列讲解(视频篇)RKMedia 数据流向

文章目录 一、 获取RKMedia模块通道中的数据二、RKMedia的数据源和接收者三、模块通道绑定API调用 沉淀、分享、成长,让自己和他人都能有所收获!😄 📢RKMedia是RK提供的一种多媒体处理方案,可实现音视频捕获、音视频输…

计算机网络——10FTP

FTP FTP:文件传输协议 向远程主机上传输文件或从远程主机接收文件客户/服务器模式 客户端:发起传输的一方服务器:远程主机 ftp:RFC 959ftp服务器:端口号为21 FTP:控制连接与数据连接分开 控制连接 FTP客户端与FTP服…

数据结构与算法:单链表

朋友们大家好,本节来到数据结构与算法的新内容:单链表 在上篇文章中,我们知道顺序表通常需要预分配一个固定大小的内存空间, 通常以二倍的大小进行增容,可能会造成空间的浪费,本篇文章我们介绍的链表可以解…

Day 43 | 动态规划 1049. 最后一块石头的重量 II 、494. 目标和 、 474.一和零

1049. 最后一块石头的重量 II 题目 文章讲解 视频讲解 思路&#xff1a;dp[j] 表示容量为 j 的背包&#xff0c;最多可以背最大重量为dp[j]。 class Solution {public int lastStoneWeightII(int[] stones) {int sum 0;for (int i 0; i < stones.length; i) {sum stone…

HCIA-HarmonyOS设备开发认证V2.0-轻量系统内核内存管理-静态内存

目录 一、内存管理二、静态内存2.1、静态内存运行机制2.2、静态内存开发流程2.3、静态内存接口2.4、实例2.5、代码分析&#xff08;待续...&#xff09;坚持就有收货 一、内存管理 内存管理模块管理系统的内存资源&#xff0c;它是操作系统的核心模块之一&#xff0c;主要包括…

微信小程序(四十一)wechat-http的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序&#xff08;二十&#xff09;Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 …

【开源】JAVA+Vue+SpringBoot实现学生综合素质评价系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生功能2.2 教师功能2.3 教务处功能 三、系统展示四、核心代码4.1 查询我的学科竞赛4.2 保存单个问卷4.3 根据类型查询学生问卷4.4 填写语数外评价4.5 填写品德自评问卷分 五、免责说明 一、摘要 1.1 项目介绍 基于J…

【Time Series】基于Transformer的时间序列预测代码实战

一、简介 在上篇《【Time Series】LSTM代码实战》中&#xff0c; 采用的是LSTM方法实现时序预测任务。自Transformer问世以来&#xff0c;在各个CV/NLP两个领域不断迭代不断屠榜&#xff0c;但在Time Series Predict(TSP)类型的任务中&#xff0c;从21年以后开始研究才慢慢红火…

五.实战软件部署 1-3实战章节-前言MYSQL 5.7版本在centos系统安装MYSQL 8.0版本在centos系统安装

目录 五.实战软件部署 1-实战章节-前言 五.实战软件部署 2-MYSQL 5.7版本在centos系统安装 1-配置yum仓库 2-使用yum安装mysql 3-安装完成后&#xff0c;启动mysql并配置开机自启动 4-检查mysql的运行状态 --配置 1-获取mysql的初识密码 2-登录mysql数据库系统 3-修改…

java SSM新闻管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM新闻管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S…

【达芬奇调色教程】

文章目录 第一章&#xff1a; 达芬奇软件基本了解1. 项目管理2. 新建项目3. 项目设置面板4. 偏好设置5. 界面布局 第一章&#xff1a; 达芬奇软件基本了解 1. 项目管理 前面的滑块可以控制缩略图的大小 2. 新建项目 项目管理器在操作本项目的时候&#xff0c;可以查看其他项目…

音视频基础

本篇文章我们来讲一下音视频基础 像素点: 将以下图片的美女眼睛放大 能够看到一个一个的小方块 这就是像素点 照片像素宽像素点*高像素点 像素点 代码实例&#xff1a; #include <opencv2/opencv.hpp>int main() {// 创建一个200x100的黑色图像cv::Mat image(100, 200,…

操作系统基础:IO管理概述【上】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;OS从基础到进阶 &#x1f3c6;&#x1f3c6;本文完整PDF源文件请翻阅至文章底部下载。&#x1f3c6;&#x1f3c6; &#x1f3ae;1 I/O设备的基本概念与分类&#x1f52b;1.1 总览&#x…

计网day2

三 物理层 3.1 物理层基本概念 物理接口特性&#xff1a; 物理层解决如何连接各种计算机的传输媒体上传输数据比特流&#xff0c;而不是指具体的传输媒体 3.2 编码&调制 3.3 数据交换方式 电路交换&#xff1a; 报文交换&#xff1a; 分组交换&#x…