BIO与NIO学习

news2024/11/24 8:28:24

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() {
                @Override
                public 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();
        //监听9090
        serverSocketChannel.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);
                }
            }

            //执行为客户端提供的服务,以接收消息为例
            //创建buffer
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            for (SocketChannel client : clients) {
                //非阻塞的读
                int read = client.read(buffer);//有消息时read>0, 无消息read=0, 异常事件read=-1
                if(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,{客户列表});//由多路复用器来监听客户列表中是否需要执行读写操作并告知thread
	if(cnt>0) {//有事件发生才处理
		recv(cnt);
	}
}

当selector连接多个channel时,它会监听每一个channel看是否有读写事件发生,然后再由selector通知thread哪个channel上需要执行什么事件由thread执行。

图片来自这位大佬的博客:BIO、NIO_bio nio-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

郑光荣参加老年春节联欢晚会团长会议现场采访

郑光荣作为北京正明圣达叫卖团的业务团长&#xff0c;他不仅在多个春节联欢晚会中展现了 自己的才华&#xff0c;还在团长会议现场接受了采访。在2024年参加了多个电视台的 春节联欢晚会录制。 郑光荣曾经参与了包括北京广播电视台、海南卫视&#xff0c;中国国际教育电视台…

c++基础-去掉空格

#include <algorithm> #include <string> #include <cctype> // 用于std::isspace std::string removeSpaces(std::string str) {str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());return str; }int main() {string str &quo…

腾讯云视立方Flutter 相关

两台手机同时运行 Demo&#xff0c;为什么看不到彼此的画面&#xff1f; 请确保两台手机在运行 Demo 时使用的是不同的 UserID&#xff0c;TRTC 不支持同一个 UserID &#xff08;除非 SDKAppID 不同&#xff09;在两个终端同时使用。 防火墙有什么限制&#xff1f; 由于 SDK…

visual studio使用ssh连接linux虚拟机运行程序

1.vs安装linux组件 2.安装后新建项目 新建后会有一个使用指南 设置网络为桥接网卡后打开虚拟机 使用vs提升的那句话安装工具 sudo apt-get install openssh-server g gdb gdbserver 重启ssh服务 sudo service ssh restart 接着进去打开ssh端口 sudo vi /etc/ssh/sshd_config …

安装rstudio-server

主要教步骤参考https://posit.co/download/rstudio-server/ 1&#xff0c;首先是linux发行版版本要求&#xff1a;符合 2&#xff0c;预装R&#xff1a;符合 3&#xff0c;安装rstudio-server 4&#xff0c;但是发现web上8787端口打不开&#xff1a; RStudio Server 可能没有在…

不会大模型不要紧!只需5分钟!你也可以微调大模型!如何快速微调Llama3.1-8B

AI浪潮席卷全球并发展至今已有近2年的时间了&#xff0c;大模型技术作为AI发展的底座和基石&#xff0c;更是作为AI从业者必须掌握的技能。但是作为非技术人员&#xff0c;相信大家也有一颗想要训练或微调一个大模型的心&#xff0c;但是苦于技术门槛太高&#xff0c;无从下手。…

Chromium 如何查找V8 引擎中JavaScript 标准内置对象

JavaScript 标准内置对象 - JavaScript | MDN (mozilla.org) 一、JavaScript 标准内置对象 本章介绍和说明了 JavaScript 中所有的标准内置对象、以及它们的方法和属性。 这里的术语“全局对象”&#xff08;或标准内置对象&#xff09;不应与 global 对象混淆。这里的“全局…

【Canvas与标牌】内凹圆角矩形排列组合标牌

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>内凹圆角矩形Draft3排列组合标牌</title><style type"…

云轴科技ZStack邀您参加迪拜GITEX 2024,10月14日不见不散

云轴科技ZStack期待在GITEX GLOBAL 2024与您相遇&#xff0c;共同探索科技的未来。 10月14日至18日&#xff0c;ZStack将携最新的云计算解决方案与AIOS智塔平台&#xff0c;亮相全球顶尖科技盛会——GITEX GLOBAL 2024 展览会&#xff0c;展位Hall 8-C20&#xff0c;向全球观众…

Git客户端使用之TortoiseGit和Git

git客户端有两个分别是TortoiseGit和Git Git用于命令行TortoiseGit用于图形界面。无论是Git还是TortoisGit都需要生成公/私钥与github/gitlab建立加密才能使用。 一、先介绍Git的安装与使用 1、下载与安装 安装Git-2.21.0-64-bit.exe(去官网下载最新版64位的)&#xff0c;安…

阿里P8面试官推荐学习的11大专题:java面试精讲框架文档

本篇文章给大家分享一波&#xff0c;阿里P8面试官推荐学习的11大专题&#xff1a;java面试精讲框架文档&#xff0c;主要包含11大块的内容&#xff1a;spring、springcloud、netty、zookeeper、kafka、Hadoop、HBASE、Cassandra、elasticsearch、spark、flink&#xff1b;希望大…

抢先体验上海交大最新大模型Agent心理诊所!论文一作深度解读角色扮演Agent前沿进展

在当今社会的快节奏生活下&#xff0c;人们对于心理健康的关注度也在持续提升。然而&#xff0c;如今的心理健康医疗资源明显不足&#xff0c;尤其是在低收入和中等收入国家。同时&#xff0c;相关医疗资源的分布也主要集中在城市和大型机构&#xff0c;这种分配不平衡导致大量…

如何下载、安装并激活 Paragon NTFS for Mac 17,paragon ntfs for mac怎么用

Paragon NTFS for Mac是一款非常不错的Mac读写工具&#xff0c;解决了大部分Mac电脑用户无法读取移动硬盘的困扰&#xff0c;但是很多用户在购买了正版Paragon后不会激活。本篇将为各位小伙伴们讲解一下NTFS读写工具Paragon NTFS for Mac是如何进行下载、安装与激活的。 注&am…

双向广搜 Solitaire——hdu1401

目录 前言 字符数字的转换 bfs or double dfs 棋局的编号 Solitaire 问题描述 输入 输出 问题分析 判重 棋子走动逻辑 单向搜索代码 双向搜索退出条件 双向广搜代码 前言 交代一下我写这题的感受&#xff0c;被自己气笑了&#xff0c;本来以为是我字符串没弄好&#xff0c;…

JAVA——File类

目录 1.概述 2.构造方法 a.根据文件路径创建文件对象 b.根据父级路径和子级路径创建对象 c.根据File表示的路径和String表示路径进行拼接 3.常见方法 a.判断文件是否存在 b.判断文件是否为文件夹 c.判断是否为文件 d.获取文件大小 e.获取文件的绝对路径 f.获取定义…

Apache Kafka基础认知-Part1

微信公众号&#xff1a;阿俊的学习记录空间小红书&#xff1a;ArnoZhangwordpress&#xff1a;arnozhang1994博客园&#xff1a;arnozhangCSDN&#xff1a;ArnoZhang1994 Apache Kafka 是一个分布式流处理平台&#xff0c;具备以下三大核心功能&#xff1a; 记录流的发布和订…

Java项目: 基于SpringBoot+mybatis+maven+vue共享汽车管理系统(含源码+数据库+开题报告+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismavenvue共享汽车管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操…

持续领先,从IDC报告看联想企业级全栈能力如何加速智能化转型

作者 | 曾响铃 文 | 响铃说 如果问智能化转型浪潮中&#xff0c;哪个行业受到的关注最多&#xff1f;毫无疑问&#xff0c;与产业升级、宏观导向密切相关的制造业一定会是答案之一&#xff0c;智能制造已经成为普遍共识。 这其中&#xff0c;面向制造业的智能化基础设施承担…

PHP 学生成绩在线发布系统-计算机毕业设计源码81780

摘 要 计算机科学技术的飞速发展也更好地促进了高校信息化建设。为了适应新形势下更好地培养人才&#xff0c;高校在发展的过程中开始推进信息系统的建设。随着我国教育模式的不断改革和发展&#xff0c;越来越多的高校正在开展校园信息工程建设&#xff0c;以更好地提高高校…

dy弹幕 新版abogus 180+长度 signature分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…