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

简述 BIO 、NIO 模型

  • BIO : 同步阻塞I/O(Block IO)

         服务器实现模式为每一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,此处可以通过线程池机制进行优化。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;/*** 多人聊天室 - 服务端*/
public class BioServer {static List<Socket> clientList = new ArrayList<>();public static void main(String[] args) throws Exception {int port = 8080;ServerSocket serverSocket = new ServerSocket(port);while (true) {Socket client = serverSocket.accept();System.out.println("客户端: " + client.getPort() + " 连接成功!");clientList.add(client);forwardProcess(client);}}/*** 转发处理*/public static void forwardProcess(Socket socket) {new Thread(new Runnable() {@Overridepublic void run() {while (true) {forwardMsg(socket);}}}).start();}/*** 转发消息*/public static void forwardMsg(Socket socket) {try {String msg = readMsg(socket);System.out.println(msg);for (Socket client : clientList) {if (client != socket) {writeMsg(client, msg);}}} catch (IOException e) {throw new RuntimeException(e);}}/*** 写入消息*/public static void writeMsg(Socket socket, String msg) throws IOException {PrintStream ps = new PrintStream(socket.getOutputStream());ps.println(msg);ps.flush();}/*** 读取消息*/public static String readMsg(Socket socket) throws IOException {InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));String msg;if ((msg = br.readLine()) != null) {msg = socket.getPort() + " 说: " + msg;}return msg;}}

import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class BilClient {public static void main(String[] args) throws IOException {String ip = "127.0.0.1";int port = 8080;Socket client = new Socket(ip, port);readProcess(client);OutputStream os = client.getOutputStream();PrintStream ps = new PrintStream(os);Scanner scanner = new Scanner(System.in);while (true) {String input = scanner.nextLine();ps.println(input);ps.flush();}}/*** 读取处理*/public static void readProcess(Socket socket) {new Thread(() -> {while (true) {try {System.out.println(readMsg(socket));} catch (IOException e) {throw new RuntimeException(e);}}}).start();}/*** 读取消息*/public static String readMsg(Socket socket) throws IOException {InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));String msg;if ((msg = br.readLine()) != null) {}return msg;}
}

  • ​NIO: 同步非阻塞式IO,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求会被注册到多路复用器上,多路复用器轮询到有 I/O 请求就会进行处理。
  • Channel,翻译过来就是“通道”,就是数据传输的管道,类似于“流”,但是与“流”又有着区别。
    • 既可以从Channel中读取数据,又可以写数据到Channel,但流的读写通常是单向的——输入输出流
    • 通道可以异步读写
    • 通道中的数据总是先读取到buffer(缓冲区),或者总是需要从一个buffer写入,不能直接访问数据
    • 非阻塞特性:Channel在设计上采用了非阻塞的特性,它不会像传统的流一样在读写操作上阻塞线程,而是立即返回结果,告诉调用者当前的状态。这使得程序可以在等待数据准备的过程中同时进行其他操作,实现了非阻塞IO。
    • 事件通知机制:Channel通常搭配选择器(Selector)来使用,选择器能够检测多个Channel的就绪状态,如是否可读、可写等,并通过事件通知(例如轮询或回调)及时地通知程序哪些Channel处于就绪状态,从而可以进行相应的读写操作。这种机制支持程序实现异步IO模型。
    • 操作系统底层支持:Channel的异步读写也依赖于操作系统底层的异步IO支持。Java NIO中的Channel实际上是对操作系统底层异步IO的封装和抽象,利用了操作系统提供的异步IO机制来实现其自身的异步读写功能。
  • Buffer是一个对象,里面是要写入或者读出的数据,在java.nio库中,所有的数据都是用缓冲区处理的。
    • 在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是直接写到缓冲区中,任何时候访问Channel中的数据,都是通过缓冲区进行操作的。
    • 缓冲区实质上是一个数组,通常是一个字节数组ByteBuffer,当然也有其他类型的:
  • Selector被称为选择器,Selector会不断地轮询注册在其上的Channel,如果某个Channel上发生读或写事件,这个Channel就被判定处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取到就绪Channel的集合,进行后续的I/O操作。
    • 一个多路复用器Selector可以同时轮询多个Channel,JDK使用了epoll()代替了传统的select实现,所以并没有最大连接句柄的限制,这意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Set;/*** NIO 聊天室 服务端*/
public class NioServer {private Integer port;ByteBuffer readBuffer = ByteBuffer.allocate(1024);ByteBuffer writerBuffer = ByteBuffer.allocate(1024);private Charset charset = Charset.forName("UTF-8");public NioServer(Integer port) {this.port = port;}public static void main(String[] args) {NioServer nioServer = new NioServer(8080);nioServer.start();}private void start() {try {// 开启socketServerSocketChannel server = ServerSocketChannel.open();// 设置非阻塞server.configureBlocking(false);// 绑定端口server.socket().bind(new InetSocketAddress(port));// 开启通道, 得到 Selector (选择器)Selector selector = Selector.open();//  注册 selector 监听事件server.register(selector, SelectionKey.OP_ACCEPT);System.out.println("启动服务器, 监听端口:" + port + "...");while (true) {// 阻塞监控所有注册的通道,当有对应的事件操作时, 会将SelectionKey放入 集合内部并返回事件数量selector.select();// 返回存有SelectionKey的集合Set<SelectionKey> selectionKeys = selector.selectedKeys();for (SelectionKey selectionKey : selectionKeys) {handle(selectionKey, selector);}//  处理后清理 selectionKeysselectionKeys.clear();}} catch (Exception e) {e.printStackTrace();}}/*** 事件处理*/private void handle(SelectionKey key, Selector selector) throws IOException {//  SelectionKey 常用方法//isAcceptable()	是否是连接继续事件//isConnectable()	是否是连接就绪事件//isReadable()	是否是读就绪事件//isWritable()	是否是写就绪事件// SelectionKey 常用事件//SelectionKey.OP_ACCEPT	接收连接继续事件,表示服务器监听到了客户连接,服务器可以接收这个连接了//SelectionKey.OP_CONNECT	连接就绪事件,表示客户端与服务器的连接已经建立成功//SelectionKey.OP_READ	读就绪事件,表示通道中已经有了可读的数据,可以执行读操作了(通道目前有数据,可以进行读操作了)//SelectionKey.OP_WRITE	写就绪事件,表示已经可以向通道写数据了(通道目前可以用于写操作)//处理连接if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);System.out.println(client.socket().getPort() + " 已建立连接 ...");}//  读取消息else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();String msg = client.socket().getPort() + " 说: " + readMsg(client);System.out.println(msg);forwardMsg(msg, client, selector);}}/*** 读取通道消息*/private String readMsg(SocketChannel client) throws IOException {readBuffer.clear();while (client.read(readBuffer) > 0) ;readBuffer.flip();return String.valueOf(charset.decode(readBuffer));}/*** 转发*/private void forwardMsg(String msg, SocketChannel client, Selector selector) throws IOException {for (SelectionKey key : selector.keys()) {Channel connectedClient = key.channel();if (connectedClient instanceof ServerSocketChannel) {continue;}if (key.isValid() && !client.equals(connectedClient)) {writerBuffer.clear();writerBuffer.put(charset.encode(msg));writerBuffer.flip();while (writerBuffer.hasRemaining())((SocketChannel) connectedClient).write(writerBuffer);}}}
}


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.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;
import java.util.Set;/*** NIO 聊天室 客户端*/
public class NioClient {private String ip;private Integer port;private ByteBuffer writerBuffer = ByteBuffer.allocate(1024);private ByteBuffer readBuffer = ByteBuffer.allocate(1024);private Charset charset = Charset.forName("UTF-8");public NioClient(String ip, Integer port) {this.ip = ip;this.port = port;}public static void main(String[] args) {NioClient nioClient = new NioClient("127.0.0.1", 8080);nioClient.start();}public void start() {try {// 开启通道SocketChannel client = SocketChannel.open();// 设置非阻塞client.configureBlocking(false);Selector selector = Selector.open();client.register(selector, SelectionKey.OP_CONNECT);client.connect(new InetSocketAddress(ip, port));while (true) {selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();for (SelectionKey selectionKey : selectionKeys) {handle(selectionKey, selector);}selectionKeys.clear();}} catch (Exception e) {e.printStackTrace();}}private void handle(SelectionKey key, Selector selector) throws IOException {// 处理连接事件if (key.isConnectable()) {SocketChannel client = (SocketChannel) key.channel();if (client.isConnectionPending()) {client.finishConnect();// 处理用户输入new Thread(() -> {Scanner scanner = new Scanner(System.in);while (true) {String msg = scanner.nextLine();writerBuffer.clear();writerBuffer.put(charset.encode(msg));writerBuffer.flip();while (writerBuffer.hasRemaining()) {try {client.write(writerBuffer);} catch (IOException e) {throw new RuntimeException(e);}}}}).start();}client.register(selector, SelectionKey.OP_READ);}// 读取消息信息else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();String s = readMsg(client);System.out.println(s);}}private String readMsg(SocketChannel client) throws IOException {readBuffer.clear();while (client.read(readBuffer) > 0) ;readBuffer.flip();return String.valueOf(charset.decode(readBuffer));}
}

相关文章:

简述 BIO 、NIO 模型

BIO : 同步阻塞I/O&#xff08;Block IO&#xff09; 服务器实现模式为每一个连接一个线程&#xff0c;即客户端有连接请求时服务器就需要启动一个线程进行处理&#xff0c;如果这个连接不做任何事情会造成不必要的线程开销&#xff0c;此处可以通过线程池机制进行优化。 impo…...

【Python小练】随机验证码

题目 提示输出含数字、字母的四位随机数&#xff0c;输入提示的验证码进行验证&#xff0c;验证码正确结束程序&#xff0c;验证码错误继续输入。 分析 我们可以通过random模块生成0到9的随机数&#xff0c;也可以通过生成65到90的随机数&#xff0c;将65到90的随机ASCLL码转换…...

《1w实盘and大盘基金预测 day30》

今日预测&#xff1a; 3123-3150-3177 探底回升&#xff0c;震荡上涨&#xff0c;收小红小绿 双创指数后期上涨的幅度也是会大于上证的&#xff0c;四月底的时候就提醒建仓。 关注板块&#xff1a;医疗、地产、电力、证券 这周预测 这周上证指数最高看到3200 继续看涨&#…...

软件工程案例学习-图书管理系统-面向对象方法

文档编号&#xff1a;LMS_1 版 本 号&#xff1a;V1.0 ** ** ** ** ** ** 文档名称&#xff1a;需求分析规格说明书 项目名称&#xff1a;图书管理系统 项目负责人&#xff1a;计敏 胡杰 ** ** …...

python:机器学习特征优选(过滤法)

作者:CSDN @ _养乐多_ 本文将介绍如何使用 python 语言使用过滤法进行机器学习特征优选。分别有F值、互信息(Mutual Information,MI)、方差阈值(Variance Threshold,VT)、相关性方法。 文章目录 一、特征数据1.1 将用于分析的数据从GEE下载到本地1.2 从其他方法获取二、…...

CH32V 系列 MCU IAP 使用函数形式通过传参形式灵活指定APP跳转地址

参考: CH32V 系列 MCU IAP 升级跳转方法 CH32V103 的 IAP 问题&#xff08;跳转及中断向量表重定位&#xff09; 1. 沁恒的RISC-V内核MCU的IAP跳转示例程序简要分析 沁恒的RISC-V内核的MCU比如CH32V203、CH32V307等系列的EVT包中IAP升级的示例程序中都是通过使能软件中断之后&…...

教程分享:如何为跨境电商、外贸、国际展会制作二维码?

不论是做跨境电商、在全球做产品推广&#xff0c;还是国外的餐厅运营、参加国际展会&#xff0c;或者是做创意户外广告、制作个性化的个人名片、有趣的产品包装……只要是在国外使用二维码&#xff0c;你都可以在QR Tiger去制作您需要的二维码&#xff01; 一、认识QR Tiger 二…...

ComfyUI 基础教程(十三):ComfyUI-Impact-Pack 面部修复

SD的WebUI 中的面部修复神器 ADetailer,无法在ComfyUI 中使用。那么如何在ComfyUI中进行面部处理呢?ComfyUI 中也有几个面部修复功能,比如ComfyUI Impact Pack(FaceDetailer),以及换脸插件Reactor和IPAdapter。 ComfyUI-Impact-Pack 是一个功能强大的插件,专为 ComfyUI …...

专题五_位运算(2)

目录 面试题 01.01. 判定字符是否唯一 解析 题解 268. 丢失的数字 解析 题解 371. 两整数之和 解析 题解 面试题 01.01. 判定字符是否唯一 面试题 01.01. 判定字符是否唯一 - 力扣&#xff08;LeetCode&#xff09; 解析 题解 class Solution { public:bool isUnique…...

ZCC5503 18V 1A 6uA低静态功耗 同步降压控制器

1. 概要 ZCC5503R 是一款基准电压源、振荡电路、 比较器 PWM/PFM 控制器构成的 CMOS 降压电路调整器&#xff0c;利用 PWM/PFM 自动切换控制电路达到可调占空比&#xff0c;具有全输入电压范围&#xff08;3~18V &#xff09;内的低纹波、高效率及大电流输出等特点. 2. 产…...

python操作minio中常见错误

因为我参考minio的文档操作&#xff0c;当时文档并不是很详细&#xff0c;这篇博文会统一记录自己所遇到的问题。以下的每个标题都是具体的错误信息。 minio-py文档 错误1:SSL: WRONG_VERSION_NUMBER 这个错误的原因是在创建minio的客户端时候没有关闭SSL&#xff0c;请使用如…...

SpringCloud-Seata分布式事务的环境搭建搭建

目录 一、版本说明 二、建立Seata Server数据库&#xff08;TC-带头大哥的数据库&#xff09; 三、业务库建表 四、安装Seata-Server 4.1 虚拟机里新建一个/opt/seate/seata-server文件夹&#xff0c;在seate文件夹下新建一个docker-compose.yml 文件 4.2 运行容器 4.3 在na…...

ChatGPT4 Turbo 如何升级体验?官网如何使用最新版GPT-4 Turbo?

本文会教大家如何教大家升级自己的GPT4到GPT4 Turbo&#xff0c;同时检验自己的GPT4 Turbo是否是最新版本的GPT-4-Turbo-2024-04-09 说明 新版GPT-4 Turbo再次重夺大模型排行榜王座&#xff0c;超越了Claude 3 Opus。 最新版本的GPT-4 Turbo被命名为GPT-4-Turbo-2024-04-09。…...

如何利用工作流自定义一个AI智能体

选择平台 目前已经有不少大模型平台都提供自定义智能体的功能&#xff0c;比如 百度的文心 https://agents.baidu.com/ 阿里的百炼平台 https://bailian.console.aliyun.com/。 今天再来介绍一个平台扣子&#xff08;https://www.coze.cn/&#xff09;&#xff0c;扣子是…...

嵌入式学习day12

每日面试题 static 关键字在 全局变量、局部变量、函数的区别&#xff1f; ①全局变量static&#xff1a;改变作用域&#xff0c;改变&#xff08;限制&#xff09;其使用范围。 只初始化一次&#xff0c;防止在其他文件单元中被引用。全局变量的作用域是整个源程序&#xff…...

【Leetcode 42】 接雨水-单调栈解法

基础思路&#xff1a; 维持栈单调递减&#xff0c;一旦出现元素大于栈顶元素&#xff0c;就可以计算雨水量&#xff0c;同时填坑&#xff08;弹出栈顶元素&#xff09; 需要注意&#xff1a; 单调栈通常保存的是下标&#xff0c;用于计算距离 public static int trap2(int[…...

Python 贪吃蛇

文章目录 效果图&#xff1a;项目目录结构main.pygame/apple.pygame/base.pygame/snake.pyconstant.py 效果图&#xff1a; 项目目录结构 main.py from snake.game.apple import Apple # 导入苹果类 from snake.game.base import * # 导入游戏基类 from snake.game.snake im…...

计算机网络 2.4差错检验与校正

第四节 差错检验与校正 一、认识检验与校正 1.差错形成原因 内部因素&#xff08;随机错&#xff09;&#xff1a;噪声脉冲、脉动噪声、衰减、延迟失真等。 外部因素&#xff08;突发错&#xff09;&#xff1a;电磁干扰、太阳噪声、工业噪声等。 2.差错控制编码分类&#…...

uniapp遍历数组对象的常见方法

在 UniApp 中&#xff0c;遍历数组对象的方法与在普通 JavaScript 中是相同的。UniApp 是一个使用 Vue.js 开发所有前端应用的框架&#xff0c;因此你可以使用 Vue.js 和 JavaScript 的语法来遍历数组对象。 以下是一些常见的遍历数组对象的方法&#xff1a; 使用 for 循环 …...

Milvus向量数据库(一)Milvus存储byte[]类型源向量数据

两种路线&#xff1a; 第一种是把byte[]转换为List< float >&#xff0c;然后存储到Milvus的floatVector中第二种是把byte[]转换为ByteBuffer&#xff0c;然后存储到Milvus的BinaryVector中 步骤&#xff1a; 我先用的是第一种&#xff0c;但是在转换float过程中&…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象&#xff1a;mysql已经安装&#xff0c;但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时&#xff0c;可能是因为以下几个原因&#xff1a;1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...