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允许程序员在块级作用域内声明变量,这意味着变量只在其定义的代码块(由大括号包围…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...