Spring架构篇--2.5.2 远程通信基础Select 源码篇--window--sokcet.register
前言:通过Selector.open() 获取到Selector 的选择器后,服务端和客户的socket 都可以通过register 进行socker 的注册;
服务端 ServerSocketChannel 的注册:
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);// 设置非阻塞serverSocketChannel.socket().bind(new InetSocketAddress(8080));// 连接事件注册到多路复用serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
ServerSocketChannel 的类关系:
1)ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl;
2)ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel;
3) SelChImpl extends Channe;
先看下ServerSocketChannel 实例的初始化: ServerSocketChannel.open()
ServerSocketChannel 类:
public static ServerSocketChannel open() throws IOException {return SelectorProvider.provider().openServerSocketChannel();
}
可以看到先拿到了Select.open() 时创建的SelectorProvider 实例,然后在调用openServerSocketChannel;
SelectorProviderImpl 类:
public ServerSocketChannel openServerSocketChannel() throws IOException {// 创建ServerSocketChannelImpl 实例return new ServerSocketChannelImpl(this);
}public SocketChannel openSocketChannel() throws IOException {return new SocketChannelImpl(this);
}
ServerSocketChannelImpl 类:
private static NativeDispatcher nd;private final FileDescriptor fd;private int fdVal;private volatile long thread = 0L;private final Object lock = new Object();private final Object stateLock = new Object();private static final int ST_UNINITIALIZED = -1;private static final int ST_INUSE = 0;private static final int ST_KILLED = 1;private int state = -1;private InetSocketAddress localAddress;private boolean isReuseAddress;ServerSocket socket;ServerSocketChannelImpl(SelectorProvider var1) throws IOException {// 传递创建的 SelectorProvider 实例super(var1);this.fd = Net.serverSocket(true);this.fdVal = IOUtil.fdVal(this.fd);this.state = 0;}
可以看到 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();中 serverSocketChannel 实际指向的是其子类(ServerSocketChannelImpl)对象。
要说明的是:ServerSocketChannel ssc = ServerSocketChannel.open()创建的这个新的Channel中的Socket是最初的,必须对这个Socket通过bind方法绑定指定的地址之后才能接收连接;
再来看服务端socket 的建立: serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.socket():
ServerSocketChannelImpl 类中:
public ServerSocket socket() {synchronized(this.stateLock) {// 加锁保证 同一个ServerSocketChannel socket 的唯一性if (this.socket == null) {this.socket = ServerSocketAdaptor.create(this);}return this.socket;}
}
serverSocketChannel.socket().bind() 绑定要监听的端口;
接下来看serverSocketChannel实例的注册:
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
SelectableChannel 类中register 方法返回注册的SelectionKey:
public final SelectionKey register(Selector sel, int ops)throws ClosedChannelException{return register(sel, ops, null);}
调用: AbstractSelectableChannel 类中register 方法:
public final SelectionKey register(Selector sel, int ops,Object att)throws ClosedChannelException
{synchronized (regLock) {// 获取锁if (!isOpen())// serverSocketChannel 通道是否打开throw new ClosedChannelException();if ((ops & ~validOps()) != 0)// serverSocketChannel 的操作行验证throw new IllegalArgumentException();if (blocking)// 如果建立的serverSocketChannel 通道是阻塞的直接抛出异常throw new IllegalBlockingModeException();// 当前通道有没在 Selector进行过注册,如果已经注册则修改属性后直接返回SelectionKey k = findKey(sel);if (k != null) {k.interestOps(ops);k.attach(att);}// 当前通道没有在当前selector 注册if (k == null) {// New registrationsynchronized (keyLock) {if (!isOpen())throw new ClosedChannelException();// 当前管道注册到selector 选择器上k = ((AbstractSelector)sel).register(this, ops, att);addKey(k);}}return k;}
}
validOps:
public final int validOps() {return SelectionKey.OP_ACCEPT;
}
再来看下 ((AbstractSelector)sel).register(this, ops, att):
实现将当前管道注册到当前的Selector 上并返回SelectionKey
protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {if (!(var1 instanceof SelChImpl)) {throw new IllegalSelectorException();} else {// 新建 SelectionKeyImpl 赋值属性SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);var4.attach(var3);synchronized(this.publicKeys) {// 防止并发多个管道同时 向selector 注册的安全性问题this.implRegister(var4);}var4.interestOps(var2);// 返回新建的SelectionKey 对新return var4;}
}
SelectionKeyImpl的构造方法:可以看出将当前selector 和要注册的管道封装到了SelectionKeyImpl 对象中
final SelChImpl channel;
public final SelectorImpl selector;private int index;private volatile int interestOps;private int readyOps;SelectionKeyImpl(SelChImpl var1, SelectorImpl var2) {this.channel = var1;this.selector = var2;}
继续看 this.implRegister(var4) 具体的注册方法:
WindowsSelectorImpl类
protected void implRegister(SelectionKeyImpl var1) {// 传入上一步封装的SelectionKeyImpl synchronized(this.closeLock) {// 获取selector 的关闭锁,防止正在注册的时候 ,selector关闭if (this.pollWrapper == null) {throw new ClosedSelectorException();} else {// SelectionKeyImpl 管道数组是否需要进行扩容this.growIfNeeded();// 当前管道放入channelArray数组中this.channelArray[this.totalChannels] = var1;var1.setIndex(this.totalChannels);this.fdMap.put(var1);// publicKeys 增加注册的管道SelectionKeythis.keys.add(var1);// 管道增加到 pollWrapperthis.pollWrapper.addEntry(this.totalChannels, var1);// 管道数量增加++this.totalChannels;}}
}
将管道放入到channelArray 和pollWrapper 中,并增加管道的数量;
growIfNeeded 扩容方法:
private void growIfNeeded() {if (this.channelArray.length == this.totalChannels) {// 2 倍扩容int var1 = this.totalChannels * 2;SelectionKeyImpl[] var2 = new SelectionKeyImpl[var1];System.arraycopy(this.channelArray, 1, var2, 1, this.totalChannels - 1);this.channelArray = var2;this.pollWrapper.grow(var1);}// 辅助线程的数量,当注册到selector 的数量每次达到1024个,就将辅助线程+1if (this.totalChannels % 1024 == 0) {this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, this.totalChannels);++this.totalChannels;++this.threadsCount;}}
通过register 可以看出,它的作用就是将管道注册到selector上,selector 中的publicKeys 记录所有注册的SelectionKey;
再来看下客户端的注册:
SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress(8080));// 连接事件注册到多路复用socketChannel.register(selector, SelectionKey.OP_CONNECT);
SocketChannel.open() 打开连接:
public static SocketChannel open() throws IOException {return SelectorProvider.provider().openSocketChannel();
}
SelectorProviderImpl 类中获取socket:
public SocketChannel openSocketChannel() throws IOException {return new SocketChannelImpl(this);
}
SocketChannelImpl 的构造方法:
private static NativeDispatcher nd;private final FileDescriptor fd;private final int fdVal;private volatile long readerThread = 0L;private volatile long writerThread = 0L;private final Object readLock = new Object();private final Object writeLock = new Object();private final Object stateLock = new Object();private boolean isReuseAddress;private static final int ST_UNINITIALIZED = -1;private static final int ST_UNCONNECTED = 0;private static final int ST_PENDING = 1;private static final int ST_CONNECTED = 2;private static final int ST_KILLPENDING = 3;private static final int ST_KILLED = 4;private int state = -1;private InetSocketAddress localAddress;private InetSocketAddress remoteAddress;private boolean isInputOpen = true;private boolean isOutputOpen = true;private boolean readyToConnect = false;private Socket socket;SocketChannelImpl(SelectorProvider var1) throws IOException {super(var1);this.fd = Net.socket(true);this.fdVal = IOUtil.fdVal(this.fd);this.state = 0;}
可以看到 new SocketChannelImpl(this)也仅仅是做了初始化,所以返回的SocketChannel 要有自己建立连接的操作;
继续看 socketChannel.register(selector, SelectionKey.OP_CONNECT);
同样调用AbstractSelectableChannel 的register 完成注册:
public final SelectionKey register(Selector sel, int ops,Object att)throws ClosedChannelException{synchronized (regLock) {if (!isOpen())// 检查SocketChannel 是否建立连接throw new ClosedChannelException();if ((ops & ~validOps()) != 0)// 检查SocketChannel 的操作符throw new IllegalArgumentException();if (blocking)// 检查SocketChannel 通道是否阻塞throw new IllegalBlockingModeException();// 当前SocketChannel 通道是否已经注册到 当前的selector 对象上SelectionKey k = findKey(sel);if (k != null) {k.interestOps(ops);k.attach(att);}if (k == null) {// New registrationsynchronized (keyLock) {if (!isOpen())throw new ClosedChannelException();k = ((AbstractSelector)sel).register(this, ops, att);addKey(k);}}return k;}}
总结:
1 服务端 ServerSocketChannel.open() 和客户端的SocketChannel.open() 只是做了初始化,它们的连接并没有建立;
2 register 方法用来将当前的通道注册到selector对象上,selector 的WindowsSelectorImpl 实例记录了注册的通道信息;
相关文章:
Spring架构篇--2.5.2 远程通信基础Select 源码篇--window--sokcet.register
前言:通过Selector.open() 获取到Selector 的选择器后,服务端和客户的socket 都可以通过register 进行socker 的注册; 服务端 ServerSocketChannel 的注册: ServerSocketChannel serverSocketChannel ServerSocketChannel.open(…...
ISIS协议
ISIS协议基础简介应用场景路由计算过程地址结构路由器分类邻居Hello报文邻居关系建立DIS及DIS与DR的类比链路状态信息的载体链路状态信息的交互路由算法网络分层路由域区域间路由简介…...
CRM系统哪种品牌的好?这五款简单好用!
CRM系统哪种品牌的好?这五款简单好用! CRM系统是指利用软件、硬件和网络技术,为企业建立一个客户信息收集、管理、分析和利用的信息系统。CRM系统的基础功能主要包括营销自动化、客户管理、销售管理、客服管理、报表分析等,选择合…...
QT_dbus(ipc进程间通讯)
QT_dbus(ipc进程间通讯) 前言: 参考链接: https://www.cnblogs.com/brt3/p/9614899.html https://blog.csdn.net/weixin_43246170/article/details/120994311 https://blog.csdn.net/kchmmd/article/details/118605315 一个大型项目可能需要多个子程序同…...
华为OD机试 - 数组排序(C++) | 附带编码思路 【2023】
刷算法题之前必看 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:https://blog.csdn.net/hihell/category_12199283.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 华为OD机试题…...
字符串转换为二进制-课后程序(JAVA基础案例教程-黑马程序员编著-第五章-课后作业)
【案例5-4】 字符串转换为二进制 【案例介绍】 1.任务描述 本例要求编写一个程序,从键盘录入一个字符串,将字符串转换为二进制数。在转换时,将字符串中的每个字符单独转换为一个二进制数,将所有二进制数连接起来进行输出。 案…...
SpringIOC
一、为什么要使用Spring? Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。 为…...
Debezium系列之:基于数据库信号表和Kafka信号Topic两种技术方案实现增量快照incremental技术的详细步骤
Debezium系列之:基于数据库信号表和Kafka信号Topic两种技术方案实现增量快照incremental技术的详细步骤 一、需求背景二、增量快照技术实现的两种方案三、基于数据库信号表实现增量快照技术的原理1.基于水印的快照2.信令表3.增量快照4.连接起重启四、基于数据库信号表实现增量…...
华为OD机试 - 第 K 个最小码值的字母(Python) | 机试题+算法思路+考点+代码解析 【2023】
第 K 个最小码值的字母 题目 输入一个由n个大小写字母组成的字符串 按照 ASCII 码值从小到大进行排序 查找字符串中第k个最小 ASCII 码值的字母(k>=1) 输出该字母所在字符串中的位置索引(字符串的第一个位置索引为 0) k如果大于字符串长度则输出最大 ASCII 码值的字母所在…...
PointNet++训练自己的数据集(附源码)
本文针对PointNet强大的三维点云分类功能,详细讲解怎么训练自己的数据集,在此之前,需要确保已经能够跑通源码的训练和测试,如果没有,请参考PointNet的源码运行。数据放置1.1. 在mytensor_shape_names.txt中配置自己的分…...
ROS2可视化利器---Foxglove Studio
0. 简介 之前作者已经讲了《ROS1可视化利器—Webviz》,然后就有读者问,ROS2有没有可以使用的可视化工具呢,答案是肯定的,除了plotjuggler这种ROS1和ROS2通用的可视化利器,还有一种全平台通用的软件FoxgloveStudio&…...
python实战应用讲解-【语法基础篇】流程控制-控制流的元素及语句(附示例代码)
目录 控制流的元素 条件 代码块 程序执行 代码块嵌套 控制流语句 if 语句...
[蓝桥杯 2019 省 A] 外卖店优先级
蓝桥杯 2019 年省赛 A 组 G 题题目描述“饱了么”外卖系统中维护着 N家外卖店,编号 1 ∼ N。每家外卖店都有一个优先级,初始时 (0 时刻)优先级都为0。每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1&#x…...
Jetson Xavier nx(ubuntu18.04)安装rtl8152网卡驱动和8192网卡驱动
含义 Bus 002 : 指明设备连接到哪条总线。 Device 003 : 表明这是连接到总线上的第二台设备。 ID : 设备的ID,包括厂商的ID和产品的ID,格式 厂商ID:产品ID。 Realtek Semiconductor Corp. RTL8153 Gigabit Ethernet Adapter:生产商名字和设备…...
Rocky 9.1操作系统实现zabbix6.0的安装部署实战
文章目录前言一. 实验环境二. 安装zabbix过程2.1. 安装zabbix源2.2 安装zabbix相关的软件2.3 安装数据库并启动2.4 开始初始化数据库:2.5 创建数据库实例及对应的用户2.6 导入官网提供的数据2.7 配置zabbix 服务的配置文件2.8. 启动服务2.9 从网页进行安装2.10 登陆…...
AQS-ReentrantLock
一、AQS 在 Lock 中,用到了一个同步队列 AQS,全称 AbstractQueuedSynchronizer,它是一个同步工具,也是 Lock 用来实现线程同步的核心组件。 1.AQS 的两种功能 独占和共享。 独占锁:每次只能有一个线程持有锁&#x…...
SpringCloud+Dubbo3 = 王炸 !
前言 全链路异步化的大趋势来了 随着业务的发展,微服务应用的流量越来越大,使用到的资源也越来越多。 在微服务架构下,大量的应用都是 SpringCloud 分布式架构,这种架构总体上是全链路同步模式。 全链路同步模式不仅造成了资源…...
机器学习主要内容的思维导图
机器学习 机器学习: 定义:能够从经验中学习从而能够 把事情不断做好的计算机程序 人工智能的一个分支和 实现方式 理论基础:概率论 数理统计 线性代数 数学分析 数值逼近 最优化理论 计算复杂理论 核心要素:数据 算法 模型 机器…...
嵌套走马灯Carousel
Carousel 的应用很广泛,基础用法这里不多做阐述,感兴趣的可以去element-gui了解Carousel 组件。 今天主要是梳理嵌套走马灯的逻辑,背景如下: 需要对项目做一个展示,项目可能有一个或多个,同时一个项目可能…...
实战——缓存的使用
文章目录前言概述实践一、缓存数据一致1.更新缓存类2.删除缓存类二、项目实践(商城项目)缓存预热双缓存机制前言 对于我们日常开发的应用系统。由于MySQL等关系型数据库读写的并发量是有一定的上线的,当请求量过大时候那数据库的压力一定会上…...
Unity项目DrawCall降不下来?试试用Mesh Baker合并贴图集,保姆级图文教程
Unity性能优化实战:用Mesh Baker合并贴图集降低DrawCall全流程解析当你的Unity项目帧率开始卡顿,Profiler里DrawCall数字居高不下时,合并贴图集往往是解决问题的关键一步。本文将以一个实际项目为例,带你从零开始使用Mesh Baker的…...
Log4Shell漏洞深度解析:Spring Boot日志注入原理与四层修复方案
1. 这个漏洞不是“远程执行代码”那么简单——它是一次对Java生态信任链的系统性击穿Log4j CVE-2021-44228,业内常简称为“Log4Shell”,2021年12月爆发时,我正在给一家金融客户的Spring Boot微服务集群做灰度发布前的安全加固。凌晨三点收到告…...
如何快速掌握MPC视频渲染器:面向初学者的完整教程
如何快速掌握MPC视频渲染器:面向初学者的完整教程 【免费下载链接】VideoRenderer Внешний видео-рендерер 项目地址: https://gitcode.com/gh_mirrors/vi/VideoRenderer 想要在Windows系统上获得影院级的视频播放体验吗?MPC…...
DeepSeek-R1代码补全实测报告:37个真实项目、8类编程语言、48小时压测后,我删掉了Copilot
更多请点击: https://intelliparadigm.com 第一章:DeepSeek-R1代码补全实测报告总览 DeepSeek-R1 是深度求索(DeepSeek)推出的开源大语言模型,专为代码理解与生成任务优化。本章聚焦其在主流 IDE 环境中代码补全能力的…...
低空旅游观光与低空通勤(eVTOL)运营管理与服务保障平台建设方案
本方案旨在为eVTOL载具构建集运营管理、空中交通管制、安全保障与乘客服务于一体的数字化平台。通过微服务架构、5G-A融合感知、空域网格化与零信任安全等核心技术,解决高密度飞行中的资源调度与安全冲突问题。目标实现毫秒级冲突解算与15分钟内快速周转,…...
AI专著生成必备工具,轻松撰写20万字专著,质量与效率双保障!
学术专著的写作是一个严谨的过程,其背后需要大量的资料和数据作为基础。搜集和整理这些资料与数据往往是写作过程中最繁琐且耗时的部分。研究人员需要广泛收集国内外的前沿文献,确保所用文献不仅具备权威性,还要与研究主题密切相关。同时&…...
CI/CD流水线中的幽灵依赖——DeepSeek项目92%存在未声明的transitive risk,你中招了吗?
更多请点击: https://intelliparadigm.com 第一章:CI/CD流水线中的幽灵依赖——DeepSeek项目92%存在未声明的transitive risk,你中招了吗? 在现代CI/CD实践中,开发者常误以为 package.json 或 requirements.txt 中显式…...
【MATLAB】OFDM系统峰均比抑制算法仿真
【MATLAB】OFDM系统峰均比抑制算法仿真 摘要:OFDM(正交频分复用)技术凭借抗多径衰落、频谱利用率高、抗干扰能力强等优势,广泛应用于4G/5G移动通信、WiFi、数字广播电视等无线通信系统。但OFDM系统存在固有缺陷,多子载波叠加导致时域信号出现大幅峰值,产生较高峰值平均功…...
GetStoreApp核心功能解析:离线部署Microsoft Store应用的5大优势
GetStoreApp核心功能解析:离线部署Microsoft Store应用的5大优势 【免费下载链接】GetStoreApp 离线下载 Microsoft Store 商店应用 项目地址: https://gitcode.com/gh_mirrors/ge/GetStoreApp GetStoreApp是一款专为Windows用户设计的离线下载工具ÿ…...
STM32F407 ADC采样值跳得厉害?HAL库时钟配置与软件滤波避坑指南
STM32F407 ADC采样值跳得厉害?HAL库时钟配置与软件滤波避坑指南 在嵌入式系统开发中,ADC(模数转换器)的稳定性直接关系到整个系统的测量精度。特别是对于STM32F407这类高性能MCU,当应用于电源监控、医疗设备或工业传感…...
