BIO与NIO学习
BIO:同步阻塞IO,客户端一个连接请求(socket)对应一个线程。阻塞体现在: 程序在执行I/O操作时会阻塞当前线程,直到I/O操作完成。在线程空闲的时候也无法释放用于别的服务只能等当前绑定的客户端的消息。

BIO的代码实现 :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Main {public static void main(String[] args) throws IOException {int id = 0;ServerSocket socket = new ServerSocket(9090);System.out.println("服务器成功启动...");while (true) {System.out.println("等待客户端连接...");//监听等待客户端连接 这是阻塞操作Socket client = socket.accept();System.out.println("客户" + ++id + "成功连接到:" + client.getInetAddress().getHostAddress());//需要为该客户分配线程执行任务new Thread(new Runnable() {@Overridepublic void run() {try {InputStream is = client.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));while (true) {//阻塞等待客户端消息String line = br.readLine();if (line == null) {System.out.println("客户端断开...");clinet.close();break;}System.out.println(line);}} catch (IOException e) {throw new RuntimeException(e);}}});}}
}
bio一个客户端对应一个线程所以每有一个客户接入服务器都会创建一个新的线程(创建新线程是通过调用内核的clone()指令来实现的)。
想必大家一定发现bio的明显的弊端了吧,随着接入的客户端越来越多服务器创建的线程数也就越多,在提供服务时在不同线程间的切换(需要保护当前现场,恢复下个线程运行的环境)也会越频繁,这会造成cpu利用的极大浪费,且这种模式的接入量存在明显的上限。
我们可以思考一下造成这一问题的原因是什么:因为是阻塞IO-->在系统调用时缺少参数(需要等待连接或等待消息传递)会被中断等待-->所以当前线程会被阻塞在原地无法提供别的服务-->此时若有新客户端接入我们不得不创建新线程为新客户端服务-->导致线程数越来越多。所以根本问题就在阻塞上,阻塞导致原线程无法提供服务。
**以上的系统调用过程**/*
在类Unix操作系统中,文件描述符(File Descriptor)是一个非负整数,它是一个指向内核中打开文件的指针。每个打开的文件(无论是常规文件、目录、套接字、管道等)都会被分配一个文件描述符。文件描述符通常用于后续的系统调用
标准输入(stdin):通常分配文件描述符 0。
标准输出(stdout):通常分配文件描述符 1。
标准错误(stderr):通常分配文件描述符 2。
打开一个文件可能会返回文件描述符 3。
创建一个套接字可能会返回文件描述符 4。
创建一个管道可能会返回文件描述符 5 和 6(一个用于读,一个用于写)。
*///以下两步对应的就是java代码中的"ServerSocket socket = new ServerSocket(9090);"
socket()=3;//这个函数请求内核创建一个新的套接字,系统调用执行成功并返回了一个文件描述符3
bind(3,9090);//socke绑定9090端口//监听这个socket
listen(3);
while(true) { accept(3, )=5;//没有客户端连接时会阻塞,当有客户端连接时括号内空的参数就是客户端的一些信息,系统调用执行成功并返回了一个文件描述符5(代表客户端)//接下来需要为客户端分配线程 clone(一些共享参数)=线程号;//通过系统调用clone()指令实现,执行成功会返回线程号
}
对于那个新创建的线程有如下步骤
//创建InputStream
while(true){recv(5, //阻塞等待客户端的消息
}
所以为了解决bio在高连接数的情况下性能急速下降的问题nio就应运而生。
NIO:同步非阻塞IO,是Java 1.4版本开始引入的一个新IO API,支持面向缓冲区、基于通道的IO操作,以更加高效的方式进行文件读写。

Buffer和通道可以相互读写,程序和Buffer交互,所以NIO是面向缓冲区的编程

//nio示例代码import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;public class Main {public static void main(String[] args) throws IOException {//客户链LinkedList<SocketChannel> clients = new LinkedList<>();//开启服务器ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();//监听9090serverSocketChannel.bind(new InetSocketAddress(9090));//监听线程设置非阻塞serverSocketChannel.configureBlocking(false);while (true) {//等待客户端连接但是不会阻塞等待,由连接时返回连接对象,无连接时返回null(系统调用层面返回-1)while (true) {SocketChannel client= serverSocketChannel.accept();if(client!=null){break;} else {//连接线程设置非阻塞client.configureBlocking(false);int port = client.socket().getPort();System.out.println("当前客户端port:" + port);clients.add(client);}}//执行为客户端提供的服务,以接收消息为例//创建bufferByteBuffer buffer = ByteBuffer.allocate(1024);for (SocketChannel client : clients) {//非阻塞的读int read = client.read(buffer);//有消息时read>0, 无消息read=0, 异常事件read=-1if(read==-1) {//断开连接释放资源client.close();clients.remove(client);break;}if(read > 0) {buffer.flip();byte[] bytes = new byte[buffer.limit()];buffer.get(bytes);String s = new String(bytes);System.out.println(client.socket().getPort() + ":" + s);}}}}
}
**系统层面流程**//对应的就是java代码中的"ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();"
socket()=4;//这个函数请求内核创建一个新的套接字,系统调用执行成功并返回了一个文件描述符4
//对应的就是java代码中的"serverSocketChannel.bind(new InetSocketAddress(9090));"
bind(4,9090);//socke绑定9090端口
//监听这个socket
listen(4);
//多了一步设置非阻塞
fcntl(4,0_NONBLOCK)=0;
while(true){accept(4,)=?;//返回具体客户端或-1,-1代表没有连接fcntl(?, 0_NONBLOCK);//clients.add(?);for(client : clients) {recv(?);//接收消息}
}
但是需要thread去不断轮询clients,当clients非常大的时候循环的事件开销就会很大,并且对于客户链来说需要执行读写操作的时间和数量只占很小的一部分,所以对于轮询操作不仅耗时而且大部分操作是无效的。
为了解决这个问题又引出了多路复用器的概念,由多路复用器来监测并通知thread,再由thread执行相应操作。
//对应的就是java代码中的"ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();"
socket()=4;//这个函数请求内核创建一个新的套接字,系统调用执行成功并返回了一个文件描述符4
//对应的就是java代码中的"serverSocketChannel.bind(new InetSocketAddress(9090));"
bind(4,9090);//socke绑定9090端口
//监听这个socket
listen(4);
//多了一步设置非阻塞
fcntl(4,0_NONBLOCK)=0;
while(true){accept(4,)=?;//返回具体客户端或-1,-1代表没有连接clients.add(?);int cnt = select(4,{客户列表});//由多路复用器来监听客户列表中是否需要执行读写操作并告知threadif(cnt>0) {//有事件发生才处理recv(cnt);}
}
当selector连接多个channel时,它会监听每一个channel看是否有读写事件发生,然后再由selector通知thread哪个channel上需要执行什么事件由thread执行。
图片来自这位大佬的博客:BIO、NIO_bio nio-CSDN博客
相关文章:
BIO与NIO学习
BIO:同步阻塞IO,客户端一个连接请求(socket)对应一个线程。阻塞体现在: 程序在执行I/O操作时会阻塞当前线程,直到I/O操作完成。在线程空闲的时候也无法释放用于别的服务只能等当前绑定的客户端的消息。 BIO的代码实现 …...
麒麟操作系统:解决umount命令卸载USB存储设备时报“device is busy”错误
麒麟操作系统:解决umount命令卸载USB存储设备时报“device is busy”错误 1、问题描述2、问题解决方法步骤1:尝试强制卸载步骤2:查找占用设备的进程步骤3:终止占用进程步骤4:卸载USB设备 💐The Begin&#…...
Git客户端使用之TortoiseGit和Git
git客户端有两个分别是TortoiseGit和Git Git用于命令行TortoiseGit用于图形界面。无论是Git还是TortoisGit都需要生成公/私钥与github/gitlab建立加密才能使用。 一、先介绍Git的安装与使用 1、下载与安装 安装Git-2.21.0-64-bit.exe(去官网下载最新版64位的),安…...
regionprops函数详解及应用
一、regionprops函数及应用 regionprops 函数在 MATLAB 中是一个强大的工具,用于计算和分析二值图像(或更一般地说,标注矩阵)中连通区域的属性。当处理二值图像时,连通区域通常对应于图像中的前景对象,而背…...
FPAG学习(5)-三种方法实现LED流水灯
目录 1.移位实现LED流水灯 1.1创建工程及源文件代码 1.1.1源代码 1.1.2仿真代码 1.1.3仿真 1.2实验结果 1.2.1总结 2.循环移位实现LED流水灯 3.38译码器实现LED流水灯 3.1原理 3.2源程序 1.移位实现LED流水灯 1.1创建工程及源文件代码 1.1.1源代码 利用计数器计数到…...
科迅网络阅卷系统存在存储型XSS漏洞
漏洞描述 科迅网络阅卷系统存在存储型XSS漏洞,在项目列表添加项目的地方没有过滤用户的输入 漏洞复现 FOFA "科迅网络阅卷系统" POC <script>alert(/xss/)</script> <h1>1</h1>...
【AAOS】Android Automotive 11模拟器源码下载及编译
源码下载 repo init -u https://android.googlesource.com/platform/manifest -b android-11.0.0_r48 repo sync -c --no-tags --no-clone-bundle 源码编译 source build/envsetup.sh lunch car_x86_64-userdebug make -j12 运行效果 emualtor Home Map All apps Setting…...
鹏哥C语言74---第12次作业:OJ题练习
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> //---------------------------------------------------------------------------- 编程题 1:小乐乐走台阶 小乐乐上课需要走n阶台阶,因为她腿比较长࿰…...
Light灯光组件+组件的相关操作+游戏资源的加载
Light灯光组件 Type: Directional:平行光,模仿的是太阳光 Spot:聚光灯 Area:区域光 Color: 颜色值 Mode: RealTime:实时 Mix:混合 Baked:烘焙 Intersity: 光照强度 Indirect Multiplier:光照强度乘数 Shadow Type:影子设置:…...
离岗睡岗预警系统 值班室离岗识别系统Python 结合 OpenCV 库
在众多工作场景中,存在着一些特殊岗位,这些岗位对于人员的专注度和警觉性有着极高的要求。然而,离岗睡岗现象却时有发生,给工作的正常开展和安全保障带来了严重的威胁。本文将深入探讨特殊岗位离岗睡岗的危害,以及如何…...
在Centos中安装、配置与使用atop监控工具
目录 前言1. atop工具的安装1.1 atop简介1.2 atop的安装步骤 2. 安装并配置netatop模块2.1 安装内核开发包2.2 安装所需依赖2.3 下载netatop2.4 解压并安装netatop2.5 启动netatop 3. atop的配置与使用3.1 配置监控周期与日志保留时间3.2 设置定时任务生成日志3.3 启动与查看at…...
前端框架对比与选择:详尽分析
1. 引言 随着互联网技术的飞速发展,前端开发技术也得到了迅猛提升。无论是大型企业还是中小型开发团队,使用前端框架来简化开发过程、提升开发效率已成为一种普遍现象。如今,市场上有众多的前端框架可供选择,如React、Vue.js、Angular等,如何在这些框架中进行选择成为了开…...
FLINK SQL时区问题
SQL时区问题 在Flink SQL中,时区问题是一个需要特别关注的点,因为时区的不一致可能会导致数据的不一致性。以下是对Flink SQL时区问题的详细解释和解决方案: 一、时区问题背景 时间类型与时区: 在Flink SQL中,时间类…...
LibreOffice SDK是LibreOffice软件的开发工具包
LibreOffice SDK是LibreOffice软件的开发工具包,它提供了一系列工具和库,使得开发者可以基于LibreOffice进行扩展或开发新的应用程序。以下是对LibreOffice SDK的详细介绍: 一、下载与安装 下载地址: 可以在LibreOffice的官方网站…...
第十五届蓝桥杯C/C++学B组(解)
1.握手问题 解题思路一 数学方法 50个人互相握手 (491)*49/2 ,减去7个人没有互相握手(61)*6/2 答案:1024 解题思路二 package 十五届;public class Min {public static void main(String[] args) {i…...
在docker的容器内如何查看Ubuntu系统版本
文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境: docker 一、问题描述 由于 lsb_release -a 只能查看自己电脑(宿主机)的系统版本,如果在docker的容器内又应该如何查看Ubuntu系统版本呢ÿ…...
Google Play服务端获取订单和核销订单
官方文档地址:https://developers.google.cn/android-publisher/api-ref/rest/v3/purchases.products?hlzh-cn java依赖 <!-- google play --><dependency><groupId>com.google.apis</groupId><artifactId>google-api-services-and…...
Spring Security 与 OAuth 2.0 登录实现指南
文章目录 一、项目概述二、环境准备三、创建GitHub OAuth应用四、项目依赖配置五、配置OAuth 2.0六、创建控制器七、创建视图八、运行应用九、用户界面展示十、总结 在现代的Web应用中,安全性是一个不可忽视的因素。OAuth 2.0作为一种流行的授权框架,提供…...
02 django管理系统 - base.html模板的搭建
下面,我们正式开始XX市第X医院员工信息管理系统的开发 首先,我们项目的目录结构如下: 然后,先把模板【base.html】界面的框架搭起来 {% load static %}<!DOCTYPE html> <html lang"en"><head><m…...
ES6语法有哪些
ES6语法包括let和const声明、箭头函数、模板字符串、解构赋值、扩展运算符、类和模块化等。以下是这些特性的具体介绍: let和const声明 let声明:let允许程序员在块级作用域内声明变量,这意味着变量只在其定义的代码块(由大括号包围…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
