网络编程基础-IO模型深入理解
一、IO的基本概念
什么是IO?
I/O就是计算机内存与外部设备之间拷贝数据的过程
什么是网络IO?
网络IO是指在计算机网络环境中进行的输入和输出操作,涉及数据在网络设备之间的传输。

网络IO操作可以是发送请求、接收响应、下载文件、传输数据等。在Java中,网络IO通过java.net包提供的类(如Socket、ServerSocket等)来实现网络通信。
二、Java的IO模型
在I/O操作中有这么两组概念,同步/异步、阻塞/非阻塞
同步/异步:
什么意思?指的是数据就绪后,我收不到通知,需要自己每隔一段时间就询问尝试读一下,靠自己专门去读取数据,叫做同步;而数据就绪准备可读了之后,由某些程序回调(理解为通知)给我们的接收程序,这称为异步。
阻塞/非阻塞:
阻塞:现在有一个读取数据的操作,在没有数据传过来时,读操作会一直阻塞等待,直到有数据过来;其次,缓冲区满时,对于写操作也会一直阻塞等待直到缓冲区有空间可以写入为止。
非阻塞:非阻塞可以理解为无需等待,都是直接返回。比如读操作中,没有数据可读时,那我就不读了,直接返回,程序结束,不会阻塞等待。写操作在缓冲区已满时,我就不写了,直接程序结束。
常见的IO模型


一种很重要的IO模型叫做IO多路复用,在多路复用IO模型中,操作系统提供了一种机制(如select、poll或epoll)来监控多个IO流的状态,只有当其中某个IO操作可以执行时,程序才会进行实际的读写操作。在网络IO中呢,就是监控多个socket连接嘛,同时去定时检查多个socket,哪个要读要写了,就通知哪个线程进行IO操作

三、Java的网络IO模型
BIO
BIO是blocking I/O的简称,它是同步阻塞型IO,其相关的类和接口在java.io下
BIO模型简单来讲,就是服务端为每一个请求都分配一个线程进行处理,I/O操作都是基于流Stream的操作

示例代码,一定要仔细阅读!
import java.io.*;
import java.net.*;public class BIOServer {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8080)) {System.out.println("服务器启动,等待客户端连接...");while (true) {// 1. 接受客户端连接(阻塞式)Socket socket = serverSocket.accept(); // 阻塞,直到客户端连接System.out.println("客户端连接成功");// 2. 为每个连接创建一个新线程处理new Thread(new ClientHandler(socket)).start();}} catch (IOException e) {e.printStackTrace();}}
}class ClientHandler implements Runnable {private Socket socket;public ClientHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {// 2. 获取输入流并读取客户端消息InputStream inputStream = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String clientMessage = reader.readLine();System.out.println("收到客户端消息: " + clientMessage);// 3. 获取输出流并向客户端发送响应OutputStream outputStream = socket.getOutputStream();PrintWriter writer = new PrintWriter(outputStream, true);writer.println("你好,客户端!服务器已收到你的消息。");// 4. 关闭客户端连接socket.close();} catch (IOException e) {e.printStackTrace();}}
}
其中主要有两个缺点:
线程开销:客户端的并发数与后端的线程数成1:1的比例,线程的创建、销毁是非常消耗系统资源的,随着并发量增大,服务端性能将显著下降,甚至会发生线程堆栈溢出等错误
线程阻塞:当连接创建后,如果该线程没有操作时,会进行阻塞操作,这样极大的浪费了服务器资源(这就是同步阻塞的缺点!)
NIO
java当中的NIO就是我们的同步非阻塞模型,代码非常简单,只有一个配置项,这样就能实现非阻塞。

我们主要来讲解Java NIO当中实现的IO多路复用这种同步非阻塞IO模型
其核心就是在轮询检测中,引入Select替我们去同时检测多个连接(否则就要每一个连接上的read单独去做轮询),哪一个连接有IO事件发生,就通知哪一个进行数据读写。
接下来详细介绍NIO
NIO的三大核心组件:Buffer(缓冲区)、Channel(通道)、Selector(选择器/多路复用器)
Buffer(缓冲区):
Buffer是一个对象,包含一些要写入或者读出的数据,体现了与原I/O的一个重要区别,在面向流的I/O中,数据读写是直接进入到Stream中,而在NIO中,所有数据都是用缓冲区处理的,读数据直接从缓冲区读,写数据直接写入到缓冲区。
缓冲区的本质是一个数组,通常是一个字节数组(ByteBuffer),也可以使用其他类型,但缓冲区又不仅仅是一个数组,它还提供了对数据结构化访问以及维护读写位置等操作。
所以Buffer就是NIO当中的数据容器,网络IO中读写的数据都是存放在Buffer中,写数据是写入到Buffer,读数据是从Buffer中读。
Channel(通道):
Channel 是一个通道,管道,网络数据通过Channel读取和写入,Channel和流Stream的不同之处在于Channel是双向的,流只在一个方向上移动(InputStream/OutputStream),而Channel可以用于读写同时进行,即Channel是全双工的。
所以有了Channel之后,我们就不从Stream中读写数据,而是通过Channel从Buffer容器里读数据或写数据。
接下来要简单讲一个SocketChannel和ServerSocketChannel,可以把他们都理解为连接对象


Selector(选择器/多路复用器):
Selector会不断轮询注册在其上的Channel,如果某个Channel上面发生读或者写事件,即该Channel处于就绪状态,它就会被Selector轮询出来,然后通过selectedKeys可以获取就绪Channel的集合,进行后续的I/O操作。

代码示例,一定要看!
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;public class NIOServerWithThread {public static void main(String[] args) {try {// 1. 创建 ServerSocketChannel,绑定端口ServerSocketChannel serverChannel = ServerSocketChannel.open();serverChannel.bind(new InetSocketAddress(8080));serverChannel.configureBlocking(false); // 设置为非阻塞模式// 2. 创建 Selector 并注册 ServerSocketChannelSelector selector = Selector.open();serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 监听连接请求System.out.println("服务器启动,等待客户端连接...");// 3. 事件循环,监听 Selectorwhile (true) {// 3.1 阻塞等待事件,返回事件数量int readyChannels = selector.select();if (readyChannels == 0) continue;// 3.2 获取可用的通道(即有事件发生的通道)Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();// 3.3 处理每个事件while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {// 处理新的客户端连接ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel clientChannel = server.accept();clientChannel.configureBlocking(false);System.out.println("客户端连接成功: " + clientChannel.getRemoteAddress());// 注册客户端通道,监听可读事件clientChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {// 创建一个新的线程来处理客户端发送的数据new Thread(() -> handleClient(key)).start();}// 3.4 处理完当前事件后,需要将它从 selectedKeys 集合中移除keyIterator.remove();}}} catch (IOException e) {e.printStackTrace();}}// 处理客户端的逻辑private static void handleClient(SelectionKey key) {try {// 处理客户端发送的数据SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead > 0) {buffer.flip();String clientMessage = new String(buffer.array(), 0, bytesRead).trim();System.out.println("收到客户端消息: " + clientMessage);// 响应客户端buffer.clear();buffer.put("你好,客户端!服务器已收到你的消息。".getBytes());buffer.flip();clientChannel.write(buffer);} else if (bytesRead == -1) {// 客户端关闭连接System.out.println("客户端断开连接: " + clientChannel.getRemoteAddress());clientChannel.close();}} catch (IOException e) {e.printStackTrace();}}
}
非阻塞性的体现:
1、在设置 ServerSocketChannel 和 SocketChannel 时,我们调用了 configureBlocking(false),这意味着在进行 I/O 操作时(如连接、读取和写入),这些操作不会阻塞线程。如果没有数据可读或连接不可用,线程不会被挂起,而是继续执行后面的代码。
2、Selector 是基于事件驱动的,主线程调用 selector.select() 方法后,会阻塞等待有事件发生(例如客户端连接或可读事件)。如果没有事件发生,主线程会继续等待,这个过程是非阻塞的,因为它不会强制执行任何 I/O 操作。
3、在上面的代码演示中,主线程在 while (true) 循环中不断调用 selector.select(),在没有事件发生时不会被阻塞(即使 selector.select() 方法是阻塞的,但它并不会影响处理其他已注册的事件的能力)。
AIO
aio就是异步模型,由于在一些操作系统上的支持不同,用的也不多,技术还不够成熟,因此不做介绍。
相关文章:
网络编程基础-IO模型深入理解
一、IO的基本概念 什么是IO? I/O就是计算机内存与外部设备之间拷贝数据的过程 什么是网络IO? 网络IO是指在计算机网络环境中进行的输入和输出操作,涉及数据在网络设备之间的传输。 网络IO操作可以是发送请求、接收响应、下载文件、传输数…...
go 语言学习路线图(一)
1. Go语言简介 Go语言的历史背景和设计理念Go的优势:简洁、高效、并发支持强Go的应用场景:微服务、云计算、系统编程 2. 开发环境设置 安装Go语言开发环境 在Windows、macOS、Linux系统上的安装方法 配置环境变量:GOROOT 和 GOPATH验证安装…...
前端自动化部署,Netlify免费满足你
1 Netlify 介绍 为什么推荐 Netliy , 主要还是穷,Netlify 免费太香了 Netlify you优势100GB 内免费 ,满足个人日常 需求,操作,兼容性绑定代码仓库,提交代码自动部署 支持 github , gitlab 等 大多常用代码仓库易操作只…...
Linux的开发工具gcc Makefile gdb的学习
一:gcc/g 1. 1 背景知识 1. 预处理(进行宏替换) 预处理 ( 进行宏替换 ) 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作用是让 gcc 在预处理结…...
基于SSM出租车管理系统的设计
管理员账户功能包括:系统首页,个人中心,车辆管理,驾驶员管理,基础数据管理,公告管理 驾驶员账号功能包括:系统首页,学生管理,车辆管理,公告管理 开发系统&a…...
iPhone照片内存怎么清理,参考这些方法
随着拍摄数量的增加,许多iPhone用户常常发现自己的手机存储空间不足,而照片无疑是占用空间的罪魁祸首之一。清理这些照片不仅能释放存储空间,还能提升设备的运行速度。小编将分享一些iPhone照片内存怎么清理的高效策略,助你告别冗…...
【Triton教程】向量相加
Triton 是一种用于并行编程的语言和编译器。它旨在提供一个基于 Python 的编程环境,以高效编写自定义 DNN 计算内核,并能够在现代 GPU 硬件上以最大吞吐量运行。 更多 Triton 中文文档可访问 →https://triton.hyper.ai/ 在本教程中,你将使…...
关于CSS中毛玻璃和滤镜使用总结
【1】毛玻璃 毛玻璃效果(也称为磨砂玻璃效果)可以通过 CSS 的 backdrop-filter 属性来实现。这个属性允许你在背景上应用各种滤镜效果,从而创建出类似磨砂玻璃的效果。这种效果通常用于创建半透明背景下的模糊效果,使得背景图像或…...
陷入产出危机的我聊聊近况
文章目录 前言我的多重身份作为IT网管作为运维人员作为Web开发人员作为游戏开发人员 总结 前言 在总结文章时,我把自己当做一个内容产出者,当这样一个身份进入每天按部就班的平稳状态时会陷入一种焦虑,产生一种居然没有什么可写的感觉&#…...
HarmonyOS 开发知识总结
1. HarmonyOS 开发知识总结 1.1. resources->base->media中不可以新建文件夹? 项目图片路径resources->base->media中不可以新建文件夹,图片全平级放里面,查找图片不方便,有没有什么其他的办法解决这个难点ÿ…...
[WPF初学到大神] 1. 什么是WPF, MVVM框架, XAML?
什么是WPF? WPF(Windows Presentation Foundation) 包含XAML标记语言和后端代码来开发桌面应用程序的. 用VS新建项目有WPF(.Net Framework和.Net应用程序), 该怎么选? 首选 .NET 应用程序(.NET Core 或 .NET 5/6/7/8新版本)拥有更好的性能、跨平台Windows, Linux, Mac支…...
matlab怎样自动搜索文件夹中的所有txt文件,并将每个txt文件中的数据存放到一个cell数组中——MATLAB批量处理数据
在使用MATLAB批量处理数据时,有时候需要自动搜索文件夹中的所有txt文件,并将每个txt文件中的数据存放到一个以一定规律命名的变量中,以便于后续通过循环处理每个变量数据。 然而,MATLAB并不支持在变量名中直接使用i来动态生成变量…...
LabVIEW智能可变温循环PCT测试系统
随着全球能源危机的加剧和环境保护需求的提升,开发和利用清洁能源已成为全球必然趋势。氢能作为一种高效的替代能源,正逐步受到关注。然而,储氢技术的研究至关重要,尤其是储氢材料的PCT(Pressure-Composition-Temperat…...
SparkSQL整合Hive
spark-sql可以直接使用hive的元数据 1、环境搭建如下: ## 1、启动hive的元数据服务shell # 1、修改hive的配置文件 cd /usr/local/soft/hive-3.1.3/conf# 2、增加配置 vim hive-site.xml<property> <name>hive.metastore.uris</name> <value…...
Vue 3 和 Vue 2区别
Vue 3 是 Vue 2 的全新升级版本,引入了诸多新的特性,并在性能、开发体验、响应式系统等多个方面进行了改进。以下是 Vue 2 和 Vue 3 的详细对比: 1. 生命周期钩子差异 Vue 3 保留了大部分 Vue 2 的生命周期钩子,但部分名称有所调…...
React.memo和useMemo
React.memo和usememo React.memo React.memo是一个高阶组件,对组件进行性能优化,主要用于优化函数组件的性能,如果一个组件在相同的props下渲染出相同的结果,但是又不需要在组件更新的时候重新渲染,就可以使用react.…...
Android中实现网络请求的方式有哪些?
在Android开发中,实现网络请求是开发过程中不可避免的一部分。随着技术的不断发展,Android中出现了多种实现网络请求的方式,每种方式都有其独特的优缺点。 一、HttpURLConnection HttpURLConnection是Java提供的用于发送HTTP请求的标准类&a…...
安卓13usb触摸唤醒系统 android13触摸唤醒
总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 android13在待机后,需要能够使用触摸屏去唤醒我们的系统,这就需要我们修改系统的相关配置了。 2.问题分析 对于这个问题,我们需要知道安卓的事件分发,通过事件分发,…...
c++常用库函数
一.sort排序 快排的改进算法,评价复杂度为(nlogn). 1.用法 sort(起始地址,结束地址下一位,*比较函数) [起始地址,结束地址) (左开右闭) #include<bits/stdc.h> using namespace std; int main() {//sortvector<int&g…...
CSS 网格布局
网格布局是一个二维布局系统,允许开发者以行和列的形式创建灵活的网络,并将内容放置在网络的单元格中。有些元素可能只占据网络的一个单元,另一些元素则可能占据多行或多列。 网格的大小既可以精确定义,也可以根据自身内容自动计…...
论文AI率80%+的紧急处理方案,答辩前用得上
距离答辩3天,AI率检出80%——这是最糟糕的时间点碰到最糟糕的问题。 不要慌,这个情况有成熟的处理方案,我见过很多人在这个时间节点成功降下来的。下面是紧急情况下的处理方法,按照时间紧迫程度分了几个场景。 先做一个判断&…...
SMU Debug Tool完全指南:AMD Ryzen硬件调试的终极解决方案
SMU Debug Tool完全指南:AMD Ryzen硬件调试的终极解决方案 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https:…...
别再乱接光纤了!手把手教你用华为SNS2224交换机配置SAN Zone(附实战命令)
华为SNS2224光纤交换机SAN Zone配置实战指南 第一次接触企业级存储网络的新手,往往会被那些闪烁的光纤端口和复杂的命令行界面吓到。记得我刚入行时,就因为接错了一根光纤线,导致整个存储集群的性能下降了70%,那次事故让我深刻理解…...
脉冲注入法与电感法无刷电机BLDC控制器方案
脉冲注入法,持续注入,启动低速运行过程中注入,电感法,ipd,力矩保持,无霍尔无感方案,媲美有霍尔效果。 bldc控制器方案,无刷电机。 提供源码,原理图。一、文档引言 本文基…...
uniapp组件-Card卡片:从基础到高级应用全解析
1. 初识uni-app Card卡片组件 第一次接触uni-app的Card卡片组件时,我正为一个电商项目发愁。产品经理要求实现商品列表的卡片式布局,既要有图片展示,又要有价格和购买按钮。当时尝试自己写CSS实现,结果各种兼容性问题让我头疼不已…...
基于两相交错并联技术的Buck-Boost变换器仿真研究:采用双向DCDC及多环控制策略实现高...
两相交错并联buck/boost变换器仿真 采用双向DCDC,管子均为双向管 模型内包含开环,电压单环,电压电流双闭环三种控制方式 两个电感的电流均流控制效果好可见下图电流细节 matlab/simulink/两相交错并联buck/boost变换器的仿真总能让工程师又爱…...
商道融绿ESG评级实战指南:从数据获取到企业绿色转型效果验证
商道融绿ESG评级实战指南:从数据获取到企业绿色转型效果验证 当某制造业上市公司ESG负责人张总监第一次向董事会汇报绿色转型方案时,遭遇的质疑声至今记忆犹新:"这些环保投入真能带来实际效益吗?"直到他们运用商道融绿E…...
如何用QtScrcpy突破手机操控局限?三大创新方案让多场景效率提升300%
如何用QtScrcpy突破手机操控局限?三大创新方案让多场景效率提升300% 【免费下载链接】QtScrcpy Android real-time display control software 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy 手机屏幕太小导致操作失误?多设备管理切…...
水下珍品目标检测数据集海胆(sea urchin),海参(sea cucumber),扇贝(scallop)总计796张图像,图像大小是1920×1080数据集是YOLO格式和VOC格式可直接
水下珍品目标检测数据集 海胆(sea urchin),海参(sea cucumber),扇贝(scallop) 总计796张图像,图像大小是19201080 数据集是YOLO格式和VOC格式 可直接进行YOLO检测,目前yolov5检测map高达0.91 图像是原始图像,未做清晰化…...
利用快马平台快速构建winner1300高性能计算原型:三步实现并行矩阵乘法
今天想和大家分享一个利用高性能计算框架winner1300快速构建并行矩阵乘法原型的实践过程。这个案例特别适合需要验证算法性能的场景,而借助InsCode(快马)平台的便利性,整个过程变得异常高效。 winner1300框架简介与环境搭建 winner1300是一个专为高性能…...
