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

网络编程基础-IO模型深入理解

一、IO的基本概念

什么是IO?

I/O就是计算机内存与外部设备之间拷贝数据的过程

什么是网络IO?

网络IO是指在计算机网络环境中进行的输入和输出操作,涉及数据在网络设备之间的传输。

网络IO操作可以是发送请求、接收响应、下载文件、传输数据等。在Java中,网络IO通过java.net包提供的类(如SocketServerSocket等)来实现网络通信。

二、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&#xff1f; I/O就是计算机内存与外部设备之间拷贝数据的过程 什么是网络IO&#xff1f; 网络IO是指在计算机网络环境中进行的输入和输出操作&#xff0c;涉及数据在网络设备之间的传输。 网络IO操作可以是发送请求、接收响应、下载文件、传输数…...

go 语言学习路线图(一)

1. Go语言简介 Go语言的历史背景和设计理念Go的优势&#xff1a;简洁、高效、并发支持强Go的应用场景&#xff1a;微服务、云计算、系统编程 2. 开发环境设置 安装Go语言开发环境 在Windows、macOS、Linux系统上的安装方法 配置环境变量&#xff1a;GOROOT 和 GOPATH验证安装…...

前端自动化部署,Netlify免费满足你

1 Netlify 介绍 为什么推荐 Netliy &#xff0c; 主要还是穷&#xff0c;Netlify 免费太香了 Netlify you优势100GB 内免费 &#xff0c;满足个人日常 需求&#xff0c;操作,兼容性绑定代码仓库&#xff0c;提交代码自动部署 支持 github , gitlab 等 大多常用代码仓库易操作只…...

Linux的开发工具gcc Makefile gdb的学习

一&#xff1a;gcc/g 1. 1 背景知识 1. 预处理&#xff08;进行宏替换) 预处理 ( 进行宏替换 ) 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作用是让 gcc 在预处理结…...

基于SSM出租车管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;车辆管理&#xff0c;驾驶员管理&#xff0c;基础数据管理&#xff0c;公告管理 驾驶员账号功能包括&#xff1a;系统首页&#xff0c;学生管理&#xff0c;车辆管理&#xff0c;公告管理 开发系统&a…...

iPhone照片内存怎么清理,参考这些方法

随着拍摄数量的增加&#xff0c;许多iPhone用户常常发现自己的手机存储空间不足&#xff0c;而照片无疑是占用空间的罪魁祸首之一。清理这些照片不仅能释放存储空间&#xff0c;还能提升设备的运行速度。小编将分享一些iPhone照片内存怎么清理的高效策略&#xff0c;助你告别冗…...

【Triton教程】向量相加

Triton 是一种用于并行编程的语言和编译器。它旨在提供一个基于 Python 的编程环境&#xff0c;以高效编写自定义 DNN 计算内核&#xff0c;并能够在现代 GPU 硬件上以最大吞吐量运行。 更多 Triton 中文文档可访问 →https://triton.hyper.ai/ 在本教程中&#xff0c;你将使…...

关于CSS中毛玻璃和滤镜使用总结

【1】毛玻璃 毛玻璃效果&#xff08;也称为磨砂玻璃效果&#xff09;可以通过 CSS 的 backdrop-filter 属性来实现。这个属性允许你在背景上应用各种滤镜效果&#xff0c;从而创建出类似磨砂玻璃的效果。这种效果通常用于创建半透明背景下的模糊效果&#xff0c;使得背景图像或…...

陷入产出危机的我聊聊近况

文章目录 前言我的多重身份作为IT网管作为运维人员作为Web开发人员作为游戏开发人员 总结 前言 在总结文章时&#xff0c;我把自己当做一个内容产出者&#xff0c;当这样一个身份进入每天按部就班的平稳状态时会陷入一种焦虑&#xff0c;产生一种居然没有什么可写的感觉&#…...

HarmonyOS 开发知识总结

1. HarmonyOS 开发知识总结 1.1. resources->base->media中不可以新建文件夹&#xff1f; 项目图片路径resources->base->media中不可以新建文件夹&#xff0c;图片全平级放里面&#xff0c;查找图片不方便&#xff0c;有没有什么其他的办法解决这个难点&#xff…...

[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批量处理数据时&#xff0c;有时候需要自动搜索文件夹中的所有txt文件&#xff0c;并将每个txt文件中的数据存放到一个以一定规律命名的变量中&#xff0c;以便于后续通过循环处理每个变量数据。 然而&#xff0c;MATLAB并不支持在变量名中直接使用i来动态生成变量…...

LabVIEW智能可变温循环PCT测试系统

随着全球能源危机的加剧和环境保护需求的提升&#xff0c;开发和利用清洁能源已成为全球必然趋势。氢能作为一种高效的替代能源&#xff0c;正逐步受到关注。然而&#xff0c;储氢技术的研究至关重要&#xff0c;尤其是储氢材料的PCT&#xff08;Pressure-Composition-Temperat…...

SparkSQL整合Hive

spark-sql可以直接使用hive的元数据 1、环境搭建如下&#xff1a; ## 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 的全新升级版本&#xff0c;引入了诸多新的特性&#xff0c;并在性能、开发体验、响应式系统等多个方面进行了改进。以下是 Vue 2 和 Vue 3 的详细对比&#xff1a; 1. 生命周期钩子差异 Vue 3 保留了大部分 Vue 2 的生命周期钩子&#xff0c;但部分名称有所调…...

React.memo和useMemo

React.memo和usememo React.memo React.memo是一个高阶组件&#xff0c;对组件进行性能优化&#xff0c;主要用于优化函数组件的性能&#xff0c;如果一个组件在相同的props下渲染出相同的结果&#xff0c;但是又不需要在组件更新的时候重新渲染&#xff0c;就可以使用react.…...

Android中实现网络请求的方式有哪些?

在Android开发中&#xff0c;实现网络请求是开发过程中不可避免的一部分。随着技术的不断发展&#xff0c;Android中出现了多种实现网络请求的方式&#xff0c;每种方式都有其独特的优缺点。 一、HttpURLConnection HttpURLConnection是Java提供的用于发送HTTP请求的标准类&a…...

安卓13usb触摸唤醒系统 android13触摸唤醒

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 android13在待机后,需要能够使用触摸屏去唤醒我们的系统,这就需要我们修改系统的相关配置了。 2.问题分析 对于这个问题,我们需要知道安卓的事件分发,通过事件分发,…...

c++常用库函数

一.sort排序 快排的改进算法&#xff0c;评价复杂度为(nlogn). 1.用法 sort(起始地址&#xff0c;结束地址下一位&#xff0c;*比较函数) [起始地址&#xff0c;结束地址) (左开右闭) #include<bits/stdc.h> using namespace std; int main() {//sortvector<int&g…...

CSS 网格布局

网格布局是一个二维布局系统&#xff0c;允许开发者以行和列的形式创建灵活的网络&#xff0c;并将内容放置在网络的单元格中。有些元素可能只占据网络的一个单元&#xff0c;另一些元素则可能占据多行或多列。 网格的大小既可以精确定义&#xff0c;也可以根据自身内容自动计…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论

路径问题的革命性重构&#xff1a;基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中&#xff08;图1&#xff09;&#xff1a; mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...