Java-NIO详解-(2)非阻塞式网络通信

java nio总结 1.主要内容1. Java NIO 简介2. Java NIO 与 IO 的主要区别3. 缓冲区(Buffer)和通道(Channel)4. 文件通道(FileChannel)5. NIO 的非阻塞式网络通信 选择器(Selector)SocketChannel、ServerSocketChannel、DatagramChannel6. 管道(Pipe)7. Java NIO2 (Path、... 阅读详情

1.阻塞与非阻塞

(1)传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不 能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会 阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理, 当服务器端需要处理大量客户端时,性能急剧下降。

(2)Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数 据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时 间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入 和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同 时处理连接到服务器端的所有客户端。

2.阻塞式NIO代码演示

public class TestBlockingNIO {
    //客户端
    @Test
    public void client() {
        SocketChannel outChannel = null;
        try {
            //1.获取通道
            outChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
            //2.分配缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            //3.读取本地文件,并发送到服务端
            while (true) {
                byteBuffer.put(("LOL怎么可能有Dota2好玩"+new Random().nextInt(100)).getBytes());
                byteBuffer.flip();
                outChannel.write(byteBuffer);
                byteBuffer.clear();
                Thread.sleep(1000);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //服务端
    @Test
    public void server() {
        ServerSocketChannel channel = null;
        SocketChannel inChannel = null;
        try {
            //1.获取通道
            channel = ServerSocketChannel.open();
            //2.绑定端口
            channel.bind(new InetSocketAddress(9898));
            //3.获取客户端连接的通道
            inChannel = channel.accept();
            //4.接收客户端的数据
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            int len;
            while ((len = inChannel.read(byteBuffer)) > 0) {
                byteBuffer.flip();
                System.out.println("客户端说:" + new String(byteBuffer.array(), 0, len));
                byteBuffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

当我们运行服务端和客户端的时候,结果如下图:在这里插入图片描述
然后我们把客户端发送的信息改一下,改成如下图所示,在启动一个客户端
在这里插入图片描述
运行结果如下图:
在这里插入图片描述
可见服务端和两个客户端都启动了,但是服务端并没有接收第二个客户端发送的信息,这种IO就是阻塞的。只有当服务端与客户端的通信完成之后,服务端才能去处理下一个客户端。因此,在完成网络通信进行 IO 操作时,由于线程会 阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理, 当服务器端需要处理大量客户端时,性能急剧下降。

3.选择器(Selector)

(1)选择器(Selector) 是 SelectableChannle 对象的多路复用器,Selector 可 以同时监控多个 SelectableChannel 的 IO 状况,也就是说,利用 Selector 可使一个单独的线程管理多个 Channel。Selector 是非阻塞 IO 的核心。

(2) SelectableChannle 的结构如下图:
在这里插入图片描述
4.选择器的应用
(1)创建 Selector :通过调用 Selector.open() 方法创建一个 Selector。

//4.获取选择器
Selector selector = Selector.open();

(2)向选择器注册通道:SelectableChannel.register(Selector sel, int ops)

//1.获取通道
channel = ServerSocketChannel.open();
//2.绑定端口
channel.bind(new InetSocketAddress(9898));
//3.切换成非阻塞模式
channel.configureBlocking(false);
//4.获取选择器
Selector selector = Selector.open();
//5.将通道注册到选择器上,并监听接收事件
channel.register(selector, SelectionKey.OP_ACCEPT);

(3)当调用 register(Selector sel, int ops) 将通道注册选择器时,选择器 对通道的监听事件,需要通过第二个参数 ops 指定。

(4)可以监听的事件类型(可使用 SelectionKey 的四个常量表示):
 读 : SelectionKey.OP_READ (1<<0)
 写 : SelectionKey.OP_WRITE (1<<2)
 连接 : SelectionKey.OP_CONNECT (1<<3)
 接收 : SelectionKey.OP_ACCEPT (1<<4)

(5)若注册时不止监听一个事件,则可以使用“位或”操作符连接。

channel.register(selector, SelectionKey.OP_ACCEPT|SelectionKey.OP_READ);

5.SelectionKey
(1) SelectionKey:表示 SelectableChannel 和 Selector 之间的注册关系。每次向 选择器注册通道时就会选择一个事件(选择键)。选择键包含两个表示为整 数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操
作。

(2)SelectionKey常用方法:

方法描述
int interestOps()获取感兴趣事件集合
int readyOps()获取通道已经准备就绪的操作的集合
SelectableChannel channel()获取注册通道
Selector selector()返回选择器
boolean isReadable()检测 Channal 中读事件是否就绪
boolean isWritable()检测 Channal 中写事件是否就绪
boolean isConnectable()检测 Channel 中连接是否就绪
boolean isAcceptable()检测 Channel 中接收是否就绪

6.Selector的常用方法

方法描述
Set keys(所有的 SelectionKey 集合。代表注册在该Selector上的Channel
selectedKeys()被选择的 SelectionKey 集合。返回此Selector的已选择键集
int select()监控所有注册的Channel,当它们中间有需要处理的 IO 操作时, 该方法返回,并将对应得的 SelectionKey 加入被选择的 SelectionKey 集合中,该方法返回这些 Channel 的数量。
int select(long timeout可以设置超时时长的 select() 操作
int selectNow()执行一个立即返回的 select() 操作,该方法不会阻塞线程
Selector wakeup()使一个还未返回的 select() 方法立即返回
void close()关闭该选择器

7.非阻塞式IO代码演示

public class TestNoBlockingNIO {
    //客户端
    @Test
    public void client() {
        SocketChannel outChannel = null;
        try {
            //1.获取通道
            outChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
            //2.把通道切换成非阻塞
            outChannel.configureBlocking(false);
            //3.分配缓冲区
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            //4.读取本地文件,并发送到服务端
            while (true) {
                byteBuffer.put(("LOL怎么可能有Dota2好玩"+new Random().nextInt(100)).getBytes());
                byteBuffer.flip();
                outChannel.write(byteBuffer);
                byteBuffer.clear();
                Thread.sleep(1000);
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (outChannel != null) {
                try {
                    outChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //服务端
    @Test
    public void server() {
        ServerSocketChannel channel = null;
        SocketChannel inChannel = null;
        SocketChannel readChannel = null;
        try {
            //1.获取通道
            channel = ServerSocketChannel.open();
            //2.绑定端口
            channel.bind(new InetSocketAddress(9898));
            //3.切换成非阻塞模式
            channel.configureBlocking(false);
            //4.获取选择器
            Selector selector = Selector.open();
            //5.将通道注册到选择器上,并监听接收事件
            channel.register(selector, SelectionKey.OP_ACCEPT);
            //6.循环获取选择器上已经“准备就绪”的事件
            while (selector.select() > 0) {
                //7.获取当前选择器中所有注册以就绪的事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    //8.获取准备就绪的事件
                    SelectionKey key = iterator.next();
                    //9.判断具体是什么事件
                    if (key.isAcceptable()) {
                        //10.获取客户端连接的通道
                        inChannel = channel.accept();
                        //11.切换成非阻塞模式
                        inChannel.configureBlocking(false);
                        //12.将通道注册到选择器上,并监听接收事件
                        inChannel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isReadable()) {
                        //13.获取当前选择器上读就绪的通道
                        readChannel = (SocketChannel) key.channel();
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        int len;
                        while ((len = readChannel.read(byteBuffer)) > 0) {
                            byteBuffer.flip();
                            System.out.println("客户端说:" + new String(byteBuffer.array(), 0, len));
                            byteBuffer.clear();
                        }
                    }
                    //14.取消选择键,不然下次还会成功
                    iterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (readChannel != null) {
                try {
                    readChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inChannel != null) {
                try {
                    inChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

当我们运行服务端和客户端的时候,结果如下图:
在这里插入图片描述

然后我们把客户端发送的信息改一下,改成如下图所示,在启动一个客户端
在这里插入图片描述运行结果如下图:
在这里插入图片描述
可见服务端和两个客户端都启动了,服务端也接收第二个客户端发送的信息,这种IO就是非阻塞的。因此,NIO 可以让服务器端使用一个或有限几个线程来同 时处理连接到服务器端的所有客户端。

NIO--尚硅谷java学习笔记 Java NIO(New IO或 Non Blocking IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 java IO 与 java NIO 的区别 通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类), 而 通道 可以用于读、写或者同时用于读写。 因为它们是双向的,所以 阅读详情

相关推荐

InsightFace实战:如何在树莓派上部署轻量级人脸识别系统(附完整代码)

本文详细介绍了如何在树莓派上部署基于InsightFace框架的轻量级人脸识别系统。通过硬件选型、环境配置、模型优化(如MobileFaceNet)及完整代码实战,指导开发者构建本地化、低功耗的智能应用,如智能门铃,并提供了性能调优与系统服务化的进阶技巧。

weixin_29043895的博客 351

【JAVA基础】- 同步非阻塞模式NIO详解

同步非阻塞的特点:应用程序的线程需要不断的进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,直到完成IO系统调用为止。同步非阻塞IO的特点:每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会被阻塞,实时性较好。不断地轮询内核,这将占用大量的CPU时间,效率低下。总体来说,在高并发应用场景下,同步非阻塞IO也是不可用的。一般Web服务器不适用这种IO模型。这种IO模型一般很少直接使用,而是在其他IO模型中使用非阻塞IO这一特性。

记录总结工作过往 3937

Ubuntu20.04安装Eigen3.3.7、模板类Sophus和Ceres

Sophus的使用必须依赖3.3以上的Eigen版本。如果版本太低,Sophus库将无法安装使用。

qq_62964142的博客 3422

NIO(非阻塞 I/O)和 IO(阻塞 I/O)详解

本文详细介绍了阻塞IO和非阻塞NIO,分析NIO中的Channel、Buffer和Selector等内容,附带示例介绍,同时利用代码对比了阻塞IO和非阻塞NIO

青灯文案的博客 3885

知识导航神器:Obsidian Breadcrumbs 插件全攻略

Parent: 插件Child: Breadcrumbs 用法这样,它就能识别出你和其他笔记的关系。

m0_73735578的博客 1630

【无人机智能避障】基于深度强化学习的城市复杂环境路径规划实战

本文探讨了基于深度强化学习的无人机在城市复杂环境中的智能避障与路径规划。针对传统算法难以应对动态与非结构化障碍的痛点,文章详细介绍了如何利用DQN算法,通过设计合理的状态空间、奖励函数,并结合经验回放、目标网络等技巧,训练无人机自主学会在楼宇间安全、高效飞行的策略。

weixin_28224217的博客 736

NIO的非阻塞式实现

首先解释一下阻塞和非阻塞 对于传统的BIO,线程在同一时间只能等待数据的发送和接收,在此期间不能做其他的事 用图来表示 所以对于这种io,我们应该使用多线程的方式完成io通信 多线程虽然能完成同时接收和发送,但是本质上也是多个阻塞的单线程,多个线程中某个陷入阻塞,该线程还是不能做其他的事,造成资源的浪费。 NIO非阻塞模式,将每一个用于传输数据的通道都注册到选择器上,选择器监控通道的io状况...

qq_41184055的博客 2085

汽车OTA安全启动:ECU双验签机制与实战排障指南

汽车OTA升级中的安全启动,本质是基于密码学的信任建立过程,其核心在于ECU上电时对固件镜像的可信验证。该机制依托硬件信任根(Secure Boot ROM),通过RSA/ECDSA等非对称算法完成签名验签,确保升级包未被篡改且来源可信。技术价值体现在防止恶意固件注入、支撑功能安全(ASIL)与信息安全(ISO/SAE 21434)合规。典型应用场景包括4S店远程升级、BMS控制器固件更新及多ECU协同启动。实践中,验签名失败往往源于证书链断裂、Flash布局错位或KeyUsage字段不匹配等底层工程细节,

weixin_29314405的博客 77

非阻塞式 I/O 模型的工作原理【NIO】

非阻塞式 I/O(Non-blocking I/O,NIO)是一种改进的 I/O 模型,引入了通道(Channel)和缓冲区(Buffer)的概念。相比于阻塞式 I/O,非阻塞式 I/O 允许在进行读/写操作时不会导致线程阻塞,而是立即返回,如果数据没有准备好,方法会返回一个特殊的值(通常是零),表示操作无法立即完成。在非阻塞式 I/O 中,一个线程可以管理多个连接,通过选择器(Selector)实现多路复用,从而提高了系统的并发能力和性能。

bareape的博客 1482

深入解析CRC-16校验算法及其Verilog硬件实现

本文深入解析了CRC-16校验算法的原理及其在Verilog中的硬件实现方法。从基础的模2除法到串行和并行实现方案,详细介绍了LFSR结构、状态转移分析以及工业应用中的优化技巧。通过实际案例和性能对比,帮助开发者理解如何选择适合的CRC实现方案,确保数据传输的可靠性。

yolo5detector的博客 322

【WRF-Urban数据集】中国60个城市的1 km分辨率城市冠层参数(UCPs)

中国60个城市的1 km分辨率城市冠层参数(UCPs)

WW、forever的博客 1068

NIO(非阻塞式IO)

新I/OByteBuffer 实际上,新 I/O 使用 NIO(同步非阻塞)的方式重写了老的 I/O 了,因此它获得了 NIO 的种种优点。 即使我们不显式的使用 NIO 进行编程,也能带来性能和速度的提高。这种提升不仅仅体现在文件读写(File I/O),同时也体现在网络读写(NetWork I/O)中,如,网络编程。 速度的提升来自于使用了更接近操作系统的 I/O 执行方式的结构:Channel(通道)和 Buffer(缓冲区)。可以将通道想象成矿井,缓冲区就是运送煤炭的小车。通过小车装煤,也可以从车

凄戚的博客 707

基于深度学习的农作物病虫害检测识别系统:YOLOv8 + UI界面 + 数据集

该系统的目标是使用YOLOv8模型自动检测农作物的病虫害,并通过UI界面提供实时反馈。用户可以通过上传图像,系统会输出图像中是否存在病虫害以及具体种类。数据集准备与处理:收集并准备包含农作物病虫害图像的数据集,并进行标注和数据增强。YOLOv8模型训练:使用YOLOv8训练农作物病虫害检测模型。UI界面设计与开发:开发一个用户友好的界面,支持上传图像并展示检测结果。系统测试与优化:评估模型的准确性、实时性,并对系统进行优化。

YOLO 883

Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库

一、NIO非阻塞式网络通信   1.阻塞与非阻塞的概念  传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不 能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会 阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理, 当服务器端需要处理大量客户端时,...

weixin_30449453的博客 141

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

JAVA NIO学习记录2-非阻塞式网络通信

  一、阻塞与非阻塞   传统的IO 流都是阻塞式的。也就是说,当一个线程调用read() 或write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。   Java NIO 是非阻塞模式的。...

QQ40153258的博客 127

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java NIO概述

一、Java NIO 简介 Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 二、Java NIO 与 IO 的主要区别 三、通道(Channel )与缓冲区(Bu...

sunshine_2017的博客 255

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Java基础知识 (NIO)

Java NIO 学习笔记 1.学习内容 Java NIO 简介 Java NIO 与 IO 的主要区别 缓冲区 (Buffer) 和通道 (Channel) 文件通道 (FileChannel) NIO 的非阻塞式网络通信 选择器 (Selector) SocketChannel , ServerSocketChannel, DatagramChannel 管道 (P...

Liyuehahaha的博客 230

10. Java基础之NIO

Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。 NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

weixin_45267102的博客 386

Ty-NIO笔记

NIO 简介 Java NIO(New IO)是从Java 1.4版本开始引入的 一个新的IO API,可以替代标准的Java IO API。 NIO与原来的IO有同样的作用和目的,但是使用 的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作 NIO与IO的主要区别 IO NIO 面向流 面向缓冲区 阻塞IO 非阻塞IO 选择器 缓冲区-Buffer和通道-Channel Java NIO系统的核心在于:通道(Channel

Ty的博客 245

NIO

NIO主要内容1. Java NIO 简介2. Java NIO 与 IO 的主要区别3. 缓冲区(Buffer)和通道(Channel) 1. Java NIO 简介 Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 2. Java NIO 与 IO 的主要区别 3. 缓冲区

qq1075666462的博客 172

IO 与 NIO 的区别:Java 输入输出的演进与核心差异

维度IONIO设计目标简化基础操作支持高并发和非阻塞处理资源开销高(每连接一线程)低(单线程多连接)学习曲线简单复杂适用领域传统文件操作、低并发网络高并发网络服务、大数据传输选择建议传统 IO:优先用于简单的文件操作或低并发场景。NIO:用于高并发网络服务或需要非阻塞处理的场景。NIO.2(AIO):需要异步处理时选择(如大文件异步读写)。通过理解 IO 与 NIO 的核心差异,开发者可以更高效地选择适合的工具,构建高性能的 Java 应用。

SOS5418818845的博客 1190

nio学习笔记

Java NIO(New IO或 Non Blocking IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 java IO 与 java NIO 的区别 一、通道(Channel)与缓冲区(Buffer) 若需要使用 NIO 系统,需要获取用于连接 ...

weixin_30697239的博客 73

Java文件

Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

AngleWang 210

NIO 笔记

NIO 笔记 (尚硅谷)NIO简介NIO 与 IO 的主要区别核心 缓冲区(Buffer)和通道(Channel)缓冲区(Buffer)Buffer 常用子类:Buffer 中的重要概念:Buffer 的常用方法直接缓冲区与非直接缓冲区:通道(Channel)通道: 可以类似于火车轨道Channel 接口提供的最主要实现类获取通道通道之间的数据传输分散(Scatter)与聚集(Gather)分散(Scatter)聚集(Gather)字符集(Charset)编码与解码NIO的非阻塞式网络通信 NIO简介 J

weixin_42029418的博客 368

NIO的入门和使用记录

一、Java NIO 简介 Java NIO(New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。 二、Java NIO 与 IO 的主要区别 IO: NIO: 三、缓冲区(Buffer)...

爱码者的博客 443
上一篇: Java-NIO详解-(1)通道(Channel)与缓冲区(Buffer)
下一篇: 安装IntelliJ IDEA后必做的配置
suixinghero
博客等级 码龄7年 10粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值