当前位置: 首页 > news >正文

根据实例逐行分析NIO到底在做什么

Selector(选择器)是 Channel 的多路复用器,它可以同时监控多个 Channel 的 IO 状况,允许单个线程来操作多个 ChannelChannel在从Buffer中获取数据。

选择器、通道、缓冲池是NIO的核心组件。

一、新建选择器


此时选择器内只包含这一条负责监听连接请求的通道

二、减少阻塞之事件触发送到嘴边

一、不用阻塞等待建立连接

答:最最关键的一步是选择器的存在,同时下图第一个红框,ServerSocketChannel属性设置为非阻塞也有一定作用

选择器监听通道,所监视的正是通道中的事件,key就代表通道中出现的事件,在循环开始后,选择器调用select() 方法监控选择器中通道状态

有 3 种方式可以 select 就绪事件:

1)select() 阻塞方法,只要出现一个就绪事件就会返回。没有则一直保持阻塞状态。

2)select(long timeout) 阻塞方法,有一个就绪事件,或者其它线程调用了 wakeup(),或者当前线程被中断,或者阻塞时长达到了 timeout 时返回。不抛出超时异常。

3)selectNode() 不阻塞,如果无就绪事件,则返回 0;如果有就绪事件,则将就绪事件放到一个集合,返回就绪事件的数量。

那么select方法实现了什么? 这个方法实现了选择器中的通道只有 出现一批就绪事件才会主动去处理,若没有就绪事件就等着啥也不干。

这个是NIO选择器的优势:来活了才干,不来活就等着,没活干了也不占坑死等(存在就绪事件的通道才会占用资源,减少功耗)

当第一次开始循环,选择器中只有一个ServerSocketChannel通道,也就是说这时只能进行客户端到服务端的连接,上图中红框key.channel()就是获得当前事件所在的ServerSocketChannel,

调用accept()方法就相当于:如果没有连接阻塞,成功等来了连接请求后,进行三次握手建立连接,所以这就是

NIO优势:通过选择器可以无需阻塞等待请求到来,因为只有选择器检测到了通道中出现连接请求(ServerSocketChannel)或者传输数据(SocketChannel)才会使用通道进行建立连接(ssChannel1.accept())或者读取数据(sChannel.read(buffer))无需等待无需等待!!!

二、不用阻塞等待数据

上边这个是优势中的无需等待建立连接,那么无需等待请求数据在哪实现的呢?

答:根据ServerSocketChannel建立ServerSocket后,将属性设置为非阻塞

答案在上图, 根据ServerSocket通道中的连接请求,建立出的新连接SocketChannel,属性Blocking设为False, 表明这是一个无需等待的非阻塞数据传输通道

我们后续使用的所有数据传输通道SocketChannel 都是基于这行代码创建出来的。

优势在哪呢, 就是如果是阻塞通道,那么假设已经开始读数据,如果一天之后才发数据下面这条语句就要等待一天直到获取完全部数据。

而因为是非阻塞,所以要是没数据了直接断开就是。

当然这一切都要在最外围的死循环中执行。

三、哪里不能减少阻塞

图中有三个地方,实际可以归结于两个地方。

Selector 作为多路复用 I/O 模型的核心组件,能够同时监控多路 I/O 通道。选择器在 select()方法等待就绪事件地时候会阻塞,在处理 I/O 事件的时候也会阻塞,它的优势在于在阻塞的时候可以等待多路 I/O 就绪,是一种异步阻塞 I/O 模型。与多线程处理多路 I/O 相比,多路复用模型只需要单个线程即可处理万级连接,没有线程切换的开销。

四、用图直观描述

**************************这个图服务端最上边前四个应该是ServerSocket****************************

最开始的时候,服务端选择器开始监听(监听各通道中是否有就绪事件),目前只有一个ServerSocketChannel通道,这个通道也在监听(监听连接请求), 这个通道就在listen这个地方一直等着。 

之后客户端根据IP +  端口像服务端发送连接请求,嗯服务端的通道获得了这个就绪事件(accept事件),选择器也轮询查到了,直接开始处理这个通道,也就是处理这个就绪事件——执行accept()方法,要经过三次握手建立TCP连接。

accept()方法建立完成之后要返回一个SocketChannel通道,也就是从RecV()开始就是SocketChannel再执行了。

这两个SocketChannel就像TCP连接的两个抽象端口,中间有一条看不见的线,我们用这两个套接字通道就可以当成TCP连接对外提供的API,直接用就好,毕竟TCP很复杂,官方提供了一个封装好的API。

1)SelectionKey.OP_ACCEPT 表示 accept 事件就绪。例如:对于 ServerSocketChannel 来说,该事件就绪表示可以调用 accept() 方法来获得与客户端连接的通道 SocketChannel。

2)SelectionKey.OP_CONNECT 表示客户端与服务端连接成功。

3)SelectionKey.OP_READ 表示通道中已经有了可读数据,可以调用 read() 方法从通道中读取数据。

4)SelectionKey.OP_WRITE 表示写事件就绪,可以调用 write() 方法往通道中写入数据。

五、大佬文章

Java NIO - 基础详解 | Java 全栈知识体系

https://www.cnblogs.com/robothy/p/14242971.html

【死磕NIO】— 探索 SocketChannel 的核心原理-CSDN博客

Java NIO 中的 Channel 详解 - 掘金

Java NIO浅析 - 美团技术团队

六、完整实例代码

NIO服务端

public class NIOServer {public static void main(String[] args) throws IOException {Selector selector = Selector.open();ServerSocketChannel ssChannel = ServerSocketChannel.open();ssChannel.configureBlocking(false);ssChannel.register(selector, SelectionKey.OP_ACCEPT);ServerSocket serverSocket = ssChannel.socket();InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);serverSocket.bind(address);while (true) {selector.select();Set<SelectionKey> keys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = keys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {ServerSocketChannel ssChannel1 = (ServerSocketChannel) key.channel();// 服务器会为每个新连接创建一个 SocketChannelSocketChannel sChannel = ssChannel1.accept();sChannel.configureBlocking(false);// 这个新连接主要用于从客户端读取数据sChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {SocketChannel sChannel = (SocketChannel) key.channel();System.out.println(readDataFromSocketChannel(sChannel));sChannel.close();}keyIterator.remove();}}}private static String readDataFromSocketChannel(SocketChannel sChannel) throws IOException {ByteBuffer buffer = ByteBuffer.allocate(1024);StringBuilder data = new StringBuilder();while (true) {buffer.clear();int n = sChannel.read(buffer);if (n == -1) {break;}buffer.flip();int limit = buffer.limit();char[] dst = new char[limit];for (int i = 0; i < limit; i++) {dst[i] = (char) buffer.get(i);}data.append(dst);buffer.clear();}return data.toString();}
}

NIO客户端 

public class NIOClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("127.0.0.1", 8888);OutputStream out = socket.getOutputStream();String s = "hello world";out.write(s.getBytes());out.close();}
}

相关文章:

根据实例逐行分析NIO到底在做什么

Selector&#xff08;选择器&#xff09;是 Channel 的多路复用器&#xff0c;它可以同时监控多个 Channel 的 IO 状况&#xff0c;允许单个线程来操作多个 Channel。Channel在从Buffer中获取数据。 选择器、通道、缓冲池是NIO的核心组件。 一、新建选择器 此时选择器内只包含…...

TypeScript-对象的类型(接口)

1.接口 说明&#xff1a;TypeScript 中的接口&#xff08;Interfaces&#xff09;是一种用来定义对象的结构或者契约的方式。通过接口&#xff0c;你可以定义对象应该具有哪些属性、方法以及它们的类型。 2.一致性 说明&#xff1a;接口的属性名和对象的属性名必须一致性。 …...

Windows服务器安全策略配置几个步骤,轻松加强服务器安全

Windows服务器安全策略怎么做&#xff1f;不要觉得这是一个非常深奥遥不可及的问题&#xff0c;其实也是从各个方面去加固系统的安全性而已&#xff0c;它没有一个定论&#xff0c;今天德迅云安全就跟用户们分享一下windows服务器基本安全策略保障服务器基本安全的一些简单实用…...

Hive详解(2)

​​Hive 表结构 分区表 多字段分区&#xff1a;需要使用多个字段来进行分区&#xff0c;那么此时字段之间会构成多层目录&#xff0c;前一个字段形成的目录会包含后一个字段形成的目录&#xff0c;从而形成多级分类的效果。例如商品的大类-小类-子类&#xff0c; 省市县、年…...

【浅尝C++】STL第二弹=>迭代器失效详解/vector常用接口使用示例/vector底层结构探索/vector模拟实现代码详解

&#x1f3e0;专栏介绍&#xff1a;浅尝C专栏是用于记录C语法基础、STL及内存剖析等。 &#x1f3af;每日格言&#xff1a;每日努力一点点&#xff0c;技术变化看得见。 文章目录 vector介绍vector常用接口及使用示例构造类函数迭代器的使用容量操作增删改查 迭代器失效详解与v…...

【pytest】pytest` 中几种常用的参数化方法

pytest 是一个强大的 Python 测试框架&#xff0c;它提供了多种参数化测试的方法。参数化测试允许你使用不同的输入集来运行相同的测试逻辑&#xff0c;从而确保代码在各种条件下都能正常工作。以下是 pytest 中几种常用的参数化方法&#xff1a; 1. 使用 pytest.mark.paramet…...

设计模式-装饰者模式在Java中使用实例-打印发票装饰抬头和脚注

场景 设计模式-装饰者模式在Java中的使用示例&#xff1a; 设计模式-装饰者模式在Java中的使用示例_java装饰者模式例子-CSDN博客 上面装饰器的调用示例如下 AbstarctComputer computer;//要买1台电脑computer new BaseComputer();//加一个内存条computer new MemoryDecor…...

parallel linux虚拟机没有root权限

前言 今天刚在parallel上装上linux虚拟机&#xff0c;安装的是Debian发行版。用终端输入命令时&#xff0c;无意间发现当前用户竟然不是root用户&#xff0c;岂有此理&#xff01;众所周知&#xff0c;Linux系统一般安装之后都是默认root用户的&#xff0c;但是可能parallel先…...

科技下乡:数字乡村改变乡村生活方式

在科技飞速发展的时代&#xff0c;数字化、信息化浪潮正以前所未有的速度席卷全球。在这场科技革命中&#xff0c;乡村不再是滞后的代名词&#xff0c;而是成为了数字乡村建设的热土。科技下乡&#xff0c;让数字乡村成为了改变乡村生活方式的重要力量。 一、科技下乡&#xf…...

【GitLab】Ubuntu使用宝塔安装GitLab最新社区版

首先在Ubuntu安装宝塔面板 在官网可以找到脚本一键安装 安装GitLab社区版 然后在宝塔面板的“软件商店”里面找到GitLab最新社区版 12.8.1一键安装 安装过程中可能出现以下问题&#xff1a; 1.卡在ruby_block[wait for logrotate service socket] action run 解决办法&…...

C++入门(2)

目录 3. C输入&输出 4. 缺省(默认)参数 4.1 缺省参数概念 4.2 缺省参数分类 全缺省参数 半缺省参数 5. 函数重载 5.1 函数重载概念 6. 引用 6.1 引用概念 6.2 引用特性 6.3 常引用 6.4 使用场景 6.5 传值、传引用效率比较 6.5.1 值和引用的作为返回值类型的性能比较 6.6 引…...

Prometheus +Grafana +node_exporter可视化监控Linux + windows虚机

1、介绍 背景&#xff1a;需要对多台虚机进行负载可视乎监控&#xff0c;并进行及时的报警 2、架构图 node_exporter &#xff1a;主要是负责采集服务器的信息。 Prometheus &#xff1a;主要是负责存储、抓取、聚合、查询方面。 Grafana &#xff1a; 主要是…...

腾讯云容器与Serverless的融合:探索《2023技术实践精选集》中的创新实践

腾讯云容器与Serverless的融合&#xff1a;探索《2023技术实践精选集》中的创新实践 文章目录 腾讯云容器与Serverless的融合&#xff1a;探索《2023技术实践精选集》中的创新实践引言《2023腾讯云容器和函数计算技术实践精选集》整体评价特色亮点分析Serverless与Kubernetes的…...

python 字典练习

def main():dict1{姓名:张三, 工资: 5000}dict2{姓名:李四, 工资: 6600}dict3{姓名:王五, 工资: 8500}dict4{}dict1.update(dict2)#字典的写法print(dict1)dict1.setdefault("3月",0)#存在不作为&#xff0c;不存在则增补print(dict1)names[]list[dict1,dict2,dict3]…...

Postman进阶功能实战演练

Postman除了前面介绍的一些功能&#xff0c;还有其他一些小功能在日常接口测试或许用得上。今天&#xff0c;我们就来盘点一下&#xff0c;如下所示&#xff1a; 1.数据驱动 想要批量执行接口用例&#xff0c;我们一般会将对应的接口用例放在同一个Collection中&#xff0c;然…...

Flink基于Hudi维表Join缺陷解析及解决方案

Hudi&#xff0c;这个近年来备受瞩目的数据存储解决方案&#xff0c;无疑是大数据领域的一颗耀眼新星。其凭借出色的性能和稳定性&#xff0c;以及对于数据湖场景的深度适配&#xff0c;赢得了众多企业和开发者的青睐。然而&#xff0c;正如任何一项新兴技术&#xff0c;Hudi在…...

3.31学习总结

(本次学习总结,总结了目前学习java遇到的一些关键字和零碎知识点) 一.static关键字 static可以用来修饰类的成员方法、类的成员变量、类中的内部类&#xff08;以及用static修饰的内部类中的变量、方法、内部类&#xff09;&#xff0c;另外可以编写static代码块来优化程序性…...

Android Studio控制台输出中文乱码问题

控制台乱码现象 安卓在调试阶段&#xff0c;需要查看app运行时的输出信息、出错提示信息。 乱码&#xff0c;会极大的阻碍开发者前进的信心&#xff0c;不能及时的根据提示信息定位问题&#xff0c;因此我们需要查看没有乱码的打印信息。 解决步骤&#xff1a; step1: 找到st…...

itextPdf生成pdf简单示例

文章环境 jdk1.8&#xff0c;springboot2.6.13 POM依赖 <dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version></dependency><dependency><groupId>com.ite…...

【Linux系列】tree和find命令

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Kirara-AI:全栈AI应用开发框架,快速构建生产级智能助手

1. 项目概述&#xff1a;一个面向开发者的AI应用快速构建框架最近在折腾AI应用开发的朋友&#xff0c;应该都体会过那种“从想法到原型”的中间环节有多磨人。你想做一个能联网搜索的智能客服&#xff0c;或者一个能处理多格式文档的问答助手&#xff0c;光是搭建基础环境、处理…...

Minecraft服务器技能数据自动化管理:mcpskills-cli命令行工具实战指南

1. 项目概述与核心价值 最近在折腾一些Minecraft服务器的自动化管理&#xff0c;发现很多重复性的技能配置、权限同步工作特别耗时。手动去游戏里敲指令&#xff0c;或者对着配置文件一条条改&#xff0c;效率低还容易出错。就在这个当口&#xff0c;我发现了 alibiinformatio…...

Blender到Unity模型导出的终极解决方案:免费插件完整指南

Blender到Unity模型导出的终极解决方案&#xff1a;免费插件完整指南 【免费下载链接】blender-to-unity-fbx-exporter FBX exporter addon for Blender compatible with Unitys coordinate and scaling system. 项目地址: https://gitcode.com/gh_mirrors/bl/blender-to-uni…...

在DOSBox中运行Appler模拟器:重温Apple II的复古计算体验

1. 项目概述&#xff1a;在DOS的土壤里复活Apple II的灵魂如果你和我一样&#xff0c;对计算机历史的交汇点着迷&#xff0c;那么“在8086的机器上模拟一颗6502的心脏”这个想法本身就充满了极客浪漫主义色彩。Appler正是这样一个跨越时代的产物——一个专为MS-DOS编写的Apple …...

如何评估拓客数据的有效性?避开无效内耗,精准提效

当下企业拓客越来越注重精细化&#xff0c;不少团队投入大量精力收集数据&#xff0c;却陷入“数据越多&#xff0c;效果越差”的困境——空号、无效线索、非目标客群占据大半&#xff0c;不仅浪费人力成本&#xff0c;更拖慢增长节奏。其实&#xff0c;拓客的核心不在于“量”…...

手动测试射频放大器P1dB:原理、步骤与校准实战指南

1. 项目概述&#xff1a;为什么我们需要手动测试P1dB&#xff1f;在射频放大器、混频器乃至整个收发链路的设计与验证中&#xff0c;1dB增益压缩点&#xff08;P1dB&#xff09;是一个绕不开的核心指标。它直观地告诉工程师&#xff0c;你的器件在多大功率下开始“力不从心”—…...

科技晚报|2026年5月15日:AI 代理开始补协作、编排和护栏

科技晚报&#xff5c;2026年5月15日&#xff1a;AI 代理开始补协作、编排和护栏 一句话导读&#xff1a;今晚更值得看的&#xff0c;不是哪家模型榜单又变了&#xff0c;而是几家平台同时在补 AI 代理真正进生产前最缺的三块能力&#xff1a;跨 IDE 共享状态、团队级可观测&…...

Fusion 360安装后想改位置?别重装!试试这个Windows符号链接‘乾坤大挪移’

Fusion 360安装路径迁移&#xff1a;无需重装的Windows符号链接实战指南 你是否遇到过这样的困扰——Fusion 360默认安装在C盘&#xff0c;随着项目文件增多&#xff0c;宝贵的SSD空间被快速吞噬&#xff1f;传统认知告诉我们&#xff0c;软件一旦安装就无法更改路径&#xff0…...

ARM Cortex-M0+极限性能优化:从超频到外设压榨的嵌入式实战

1. 项目概述&#xff1a;一次基于经典平台的极限性能探索“飞思卡尔Freedom打造新记录&#xff01;”这个标题&#xff0c;对于很多嵌入式领域的老兵而言&#xff0c;瞬间就能勾起一段充满挑战与激情的回忆。飞思卡尔&#xff08;Freescale&#xff0c;现为NXP的一部分&#xf…...

NotebookLM技能集成:自动化文档问答与RAG应用实践

1. 项目概述&#xff1a;当NotebookLM遇上自定义技能最近在折腾AI工具链的时候&#xff0c;发现了一个挺有意思的项目&#xff1a;jasontsaicc/notebooklm-studio-skill。乍一看这个名字&#xff0c;你可能和我最初的反应一样&#xff0c;有点摸不着头脑。NotebookLM我知道&…...