java BIO深入学习

news2024/11/18 2:47:41

一、BIO的工作原理

传统Io(BIO)的本质就是面向字节流来进行数据传输的
在这里插入图片描述
①:当两个进程之间进行相互通信,我们需要建立一个用于传输数据的管道(输入流、输出流),原来我们传输数据面对的直接就是管道里面一个个字节数据的流动(我们弄了一个 byte 数组,来回进行数据传递),所以说原来的 IO 它面对的就是管道里面的一个数据流动,所以我们说原来的 IO 是面向流的
②:我们说传统的 IO 还有一个特点就是,它是单向的。解释一下就是:如果说我们想把目标地点的数据读取到程序中来,我们需要建立一个管道,这个管道我们称为输入流。相应的,如果如果我们程序中有数据想要写到目标地点去,我们也得再建立一个管道,这个管道我们称为输出流。所以我们说传统的 IO 流是单向的

二、传统的BIO编程实例回顾

网络编程的基本模型是C/S(客户端/服务器端)模型,也就是两个进程之间的通讯,其中服务端提供位置信(绑定ip地址和端口),客户端通过连接操作向服务器端监听的端口地址发起连接请求,基于TCP协议下进行三次握手连接,连接成功后,双方进行socket通讯。
传统的同步阻塞模型开发中,服务端ServerSocket负责绑定ip地址,启动监听端口;客户端Socket负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信。
基于BIO模式下的通讯,客户端-服务器端是完全同步,完全耦合的。
服务器端代码

public class Server {
    public static void main(String[] args) {
        try {
            System.out.append("服务器端启动。。。");
            //1.定义ServerSocket对象进行服务端的端口注册
            ServerSocket serverSocket = new ServerSocket(8080);
            //2.监听客户端的Socket连接程序
            Socket socket = serverSocket.accept();
            //3.从socket对象当中获取到一个字节输入流对象
            InputStream iStream = socket.getInputStream();
            //打印输出
            int len = 0;
            int ReviceLen = 0;
            //计算机网络数据是以8bit为一个单元进行发送,我们接收到发送方发送的byte数据
            //将其转化为utf-8的格式进行输出
            byte[] recvBuf = new byte[1024];
            while ((ReviceLen = iStream.read(recvBuf)) != -1) {
                System.out.println("  客户端说:"
                        + new String(recvBuf, 0, ReviceLen, "UTF-8"));
            }
        } catch (Exception e) {

        }
    }
}

客户端代码

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建socket对象请求服务器的连接
        Socket socket = new Socket("127.0.0.1",8080);
        //2.从socket对象中获取一个字节输出流、
        OutputStream oStream = socket.getOutputStream();
        oStream.write(("你好服务器").getBytes());//以字节流的形式发送数据
        //4.关闭
        oStream.flush();
    }
}

三、BIO模式下的多发和多收消息

服务器端不变,客户端:

public class Client {
    public static void main(String[] args) throws Exception {
        //1.创建socket对象请求服务器的连接
        Socket socket = new Socket("127.0.0.1",8080);
        //2.从socket对象中获取一个字节输出流、
        OutputStream oStream = socket.getOutputStream();
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请说....");
            String message = scanner.nextLine();
            oStream.write(message.getBytes());
            //4.关闭
            oStream.flush();
        }
    }
}

在这里插入图片描述
在这里插入图片描述

四、BIO模式下接收多个客户端

在上述的案例当中,一个服务端只能接收一个客户端的通信请求,那么如果服务端需要处理很多个客户端的消息通讯请求应该如何处理呢?

当我们启动两个客户端,分别去访问服务器端的时候,我们发现服务器端只连接了一个客户端,并且只能和一个客户端进行通信。
在这里插入图片描述
在这里插入图片描述

什么原因导致了我们服务器只能链接一个客户端

在这里插入图片描述

那如何解决呢?

此时就需要在服务端引入线程了,也就是说客户端发起一次请求,服务端就会创建一个新的线程来处理一个新的线程来处理这个客户端的请求,这样就实现了一个客户端一个线程的模型,图解如下:
在这里插入图片描述

服务器端改进代码

public class Server {
    public static void main(String[] args) {
        try {
            System.out.append("服务器端启动。。。");
            //1.定义ServerSocket对象进行服务端的端口注册
            ServerSocket serverSocket = new ServerSocket(8080);
            while (true){
                //2.监听客户端的Socket连接程序
                Socket socket = serverSocket.accept();
                //创建一个独立的线程来处理也客户端的Socket请求
                new ServerThreadReader(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class ServerThreadReader extends Thread {
    private Socket socket;

    public ServerThreadReader(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        //3.从socket对象当中获取到一个字节输入流对象
        try {
            InputStream iStream = socket.getInputStream();
            //打印输出
            int len = 0;
            int ReviceLen = 0;
            //计算机网络数据是以8bit为一个单元进行发送
            byte[] recvBuf = new byte[1024];
            while ((ReviceLen = iStream.read(recvBuf)) != -1) {
                System.out.println("  客户端说:"
                        + new String(recvBuf, 0, ReviceLen, "UTF-8"));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
小结

1.每个socket接受到,都会床架一个新的线程,线程的竞争、切换上下文影响性能。
2.每个线程都会占用栈空间和cpu资源
3.并不是每一个socket都进行IO操作,无意义的线程处理
4.客户端的并发访问增加时。服务端将呈现1:1的线程开销,访问量越大,系统将发生线程
   栈溢出,线程创建失败,最终导致进程宕机或僵死,从而不能对外提供服务

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

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

相关文章

靶机渗透之ConnectTheDots

对于vulnhub中的靶机,我们都需先下载镜像,然后导入VM,并将网络连接改为NAT模式。首先我们再来看一下靶机渗透的步骤:信息收集-漏洞分析-漏洞利用-提权。基本都是这个三个步骤,接下来开始我们今天的靶机渗透吧&#xff…

数据库系统实验

一、数据库管理系统软件的使用 1、实验概要 创建用于学生管理的数据库,数据库名为xsgl,包含学生的基本信息,课程信息和选课信息。数据库xsgl包含下列3个表: student:学生基本信息;course:课程…

流水账-20240229

目录 git本地回滚到到120bc409ee3b8f63a23d0060e55118bcce557acf提交记录本地提交到已有代码分支 IDEA批量导入快捷键无效更换背景主题快捷键快捷键可以设置eclipse模式,但是有些不生效,可能是冲突了Ctrl单击,Eclipse里面是可以跳转到代码内部…

计网 - 子网掩码的改变与内网之间通信的关系

文章目录 面试题A与B通信的全过程 面试题 想要弄清楚这个问题,必须了解数据包在网络上是如何传输的: 首先B想向A发送数据包,会根据双方IP来判断是否在同一子网: A的IP地址属于192.168.26.0/24这个网段。B的IP地址属于192.168.26.…

微信小程序构建npm失败解决方式

安装完所需要的依赖后,在微信开发者工具菜单栏中选择:“工具” -> “构建 npm”,但是失败。 解决方法:修改 project.config.json 开发者工具创建的项目,miniprogramRoot 默认为 miniprogram,package.js…

LVGL的基础知识总结

详细的内容可以参考正点原子的LVGL开发指南,本文只记录重点内容 正点原子后续的例程都是基于操作系统来写的 面向对象 在 LVGL 中,用户界面的基本构建成分是对象,也称为小部件,例如:按钮、标签、图片、列表、图表、文…

【Python_Zebra斑马打印机编程学习笔记(三)】解决ZPL指令无法显示中文的问题

解决ZPL指令无法显示中文的问题 解决ZPL指令无法显示中文的问题前言一、问题描述二、字符集、码表文件、字库文件1、字符集2、码表文件3、字库文件 三、两种设置中文字体的方式1、通过设置字符集、码表文件、字库文件改变默认字体2、通过^CF指令设置标准字体名称改变默认字体 解…

DOM 创建节点、添加节点和删除节点

创建元素节点 document.createElement(‘标签名’) 创建文本节点document.createTextNode ( 内容 ) 根据传入的标签名创建出一个空的元素对象创建出来的默认不显示,要成为别人的子元素才能显示,所以要结合appendChild使用 添加节点(后面&am…

【AI Agent系列】【MetaGPT多智能体学习】4. 基于MetaGPT的Team组件开发你的第一个智能体团队

本系列文章跟随《MetaGPT多智能体课程》(https://github.com/datawhalechina/hugging-multi-agent),深入理解并实践多智能体系统的开发。 本文为该课程的第四章(多智能体开发)的第二篇笔记。主要是对MetaGPT中Team组件…

每日一练:LeeCode-701、二叉搜索树中的插入操作【二叉搜索树+DFS+全搜】

本文是力扣 每日一练:LeeCode-701、二叉搜索树中的插入操作【二叉搜索树DFS全搜】学习与理解过程,本文仅做学习之用,对本题感兴趣的小伙伴可以出门左拐LeeCode。 给定二叉搜索树(BST)的根节点 root 和要插入树中的值 …

机器学习图像识别如何处理标签以外的图像?

机器学习图像识别技术是一种基于人工智能的图像处理方法,它通过训练大量的图像数据集来让计算机学习如何识别和分类图像。在图像识别任务中,我们通常需要对图像进行标注和分类,以便让计算机能够从中学习。但是,有时候我们可能会遇…

减少页面加载时间:提升用户体验的关键

✨✨ 祝屏幕前的您天天开心,每天都有好运相伴。我们一起加油!✨✨ 🎈🎈作者主页: 喔的嘛呀🎈🎈 目录 引言 一、为什么页面加载时间重要? 二、如何减少页面加载时间? …

集中和离散

数据分类&#xff1a;定性(分类&#xff0c;顺序)&#xff0c;定量(数值) 分类&#xff1a;男&#xff0c;女 顺序&#xff1a;高&#xff0c;中&#xff0c;低 数值&#xff1a;可计算的数字 数据等级&#xff1a;分类<顺序<数值。高级数据可以用低级数据&#xff0c…

day09_面向对象_构造方法_封装

今日内容 零、 复习昨日 一、构造方法 二、重载 三、封装 零、 复习昨日 1 类和对象是什么关系? 类是模板(原材料)对象是具体实例(成品)类创建出对象 2 类中有什么?(类的成员) 成员属性(成员变量), 成员方法 3 创建对象的语法? 类名 对象名 new 类名(); 4 调用对象属性,方法…

音频筑基:CD还是HiRes?高清音频分类一文说透

音频筑基&#xff1a;CD还是HiRes&#xff1f;高清音频分类一文说透 前言音乐品质分类相关资料 前言 音频信号中&#xff0c;经常遇到高清音乐、无损音质、CD、HiRes等说法&#xff0c;本文主要在纯数字信号级别&#xff0c;从音源分类和编码质量两个维度&#xff0c;做一个分析…

[AutoSar]BSW_Com06 CAN报文应用层到Can总线的函数调用

目录 关键词平台说明一、背景二、PDU转换三、函数调用 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c;芯片厂商TI 英飞凌编程语言C&#xff0c;C编译器HighTec (GCC)autosar版本4.3.X >>>>>回到总目…

《商用密码应用安全性评估管理办法》解读

根据《中华人民共和国密码法》&#xff08;以下简称《密码法》&#xff09;、《商用密码管理条例》&#xff08;以下简称《条例》&#xff09;等法律法规&#xff0c;国家密码管理局研究制定了《商用密码应用安全性评估管理办法》&#xff08;国家密码管理局令第3号&#xff09…

Vue页面更新后刷新页面不会渲染解决

小编今天犯了个很低级的错误&#xff0c;导致VUE页面刷新样式不会更新的问题&#xff01; 解决方法&#xff1a;查看你的路由路径大小写是否正确&#xff01;小编是犯了这种错误&#xff0c;特此分享下&#xff01;

Vite 构建的 Vue3 项目如何整合 Monaco Editor 代码编辑器

目录 &#x1f981; 一. 前言&#x1f981; 二. 探索过程2.1 安装2.2 配置 Monaco Editor2.3 编写 Monaco Editor 代码编辑器2.3.1 创建 Coding Editor 组件2.3.2 父组件使用 CodingEditor 组件 2.4 效果展示 三. 总结 &#x1f981; 一. 前言 各位好&#xff01;我是&#x1…

Unity 预制体与变体

预制体作用&#xff1a; 更改预制体&#xff0c;则更改全部的以预制体复制出的模型。 生成预制体&#xff1a; 当你建立好了一个模型&#xff0c;从层级拖动到项目中即可生成预制体。 预制体复制模型&#xff1a; 将项目中的预制体拖动到层级中即可复制。或者选择物体复制粘贴。…