网络编程基础-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 网格布局
网格布局是一个二维布局系统,允许开发者以行和列的形式创建灵活的网络,并将内容放置在网络的单元格中。有些元素可能只占据网络的一个单元,另一些元素则可能占据多行或多列。 网格的大小既可以精确定义,也可以根据自身内容自动计…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
