当前位置: 首页 > 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过程中&…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

更新 Docker 容器中的某一个文件

&#x1f504; 如何更新 Docker 容器中的某一个文件 以下是几种在 Docker 中更新单个文件的常用方法&#xff0c;适用于不同场景。 ✅ 方法一&#xff1a;使用 docker cp 拷贝文件到容器中&#xff08;最简单&#xff09; &#x1f9f0; 命令格式&#xff1a; docker cp <…...

[C++错误经验]case语句跳过变量初始化

标题&#xff1a;[C错误经验]case语句跳过变量初始化 水墨不写bug 文章目录 一、错误信息复现二、错误分析三、解决方法 一、错误信息复现 write.cc:80:14: error: jump to case label80 | case 2:| ^ write.cc:76:20: note: crosses initialization…...