Java基础知识——BIO模式

article/2025/11/8 9:11:45

文章目录

  • 一、Java的I/O总述
        • 1、I/O模型
        • 2、应用
  • 二、BIO模式
        • 1、传统的服务器、客户端通信(一对一):
        • 2、服务器和客户端的通信(一对多)
        • 3、伪异步IO编程
        • 4、BIO模式下的文件上传


一、Java的I/O总述

I/O模型:就是用什么样的通道或者通信模式和架构进行数据的传输和接收,很大程度上决定了程序通信的性能,包括BIO、NIO、AIO

1、I/O模型

BIO: 同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即用户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情就会造成不必要的线程开销

在这里插入图片描述
NIO: 同步非阻塞,服务器实现模式为一个线程处理多个请求连接,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询连接有I/O请求就进行处理
在这里插入图片描述

AIO: 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS完成了再通知服务器应用去启动线程进行处理,一般适用于连接数较多且连接市场较长的应用

2、应用

BIO: 适用于连接数目较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中
NIO: 连接数目多且连接比较短(轻操作)架构,比如聊天服务器等
AIO: 用于连接数目多连接比较长(重操作)的架构,比如相册服务器

二、BIO模式

1、传统的服务器、客户端通信(一对一):

package 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 Server {public static void main(String[] args){System.out.println("服务端启动");try{//定义一个ServerSocket对象进行服务器端口注册ServerSocket ss = new ServerSocket(9999);//监听客户端的连接请求Socket socket = ss.accept();//从socket管道中得到一个字节输入流对象InputStream is = socket.getInputStream();//把字节输入流包装秤一个缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));String msg;while((msg = br.readLine())!=null){System.out.println("服务器接收到:"+msg);}} catch (Exception e) {e.printStackTrace();}}
}
package BIO;import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {//创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//从socket对象中获取一个字节输出流OutputStream os = socket.getOutputStream();//把字节输出流包装成一个打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while(true){System.out.println("请说");String msg = sc.nextLine();ps.println(msg);ps.flush();}}
}

运行结果:
在这里插入图片描述
原因:while((msg = br.readLine())!=null){System.out.println(“服务器接到:”+msg); }服务器中要求接受到一行的数据,而客户端 ps.print(“hello world 服务器”);只是输出一堆文字而没有换行,所以服务器还在继续等待,但是客户端发完之后就挂掉了,因此服务端认为还没有接受到一行消息结果客户端就没了,所以才报错

结论:在以上通信中,服务端会一直等待客户端的消息,如果客户端没有进行消息的发送,服务端将一直进入阻塞状态。同时服务端是按照行获取消息的,这就意味着客户端也必须按照行进行消息发送,否则服务端将进入等待消息的阻塞状态

2、服务器和客户端的通信(一对多)

引入线程,一个线程处理一个客户端的请求

package BIO;import javax.print.DocFlavor;
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 Server {public static void main(String[] args){try{//注册端口ServerSocket ss = new ServerSocket(9999);//定义一个死循环,负责不断地接收客户端的socket请求while(true){Socket socket = ss.accept();//注册一个独立的线程来处理这个客户端的请求new ServerThreadReader(socket).start();}}catch (IOException e){e.printStackTrace();}}
}class ServerThreadReader extends Thread {private Socket socket;public ServerThreadReader(Socket socket){this.socket = socket;}public void run(){try{//从socket对象中得到一个字节输入流InputStream is = socket.getInputStream();//使用缓冲字符输入流包装字节输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));String msg;while((msg = br.readLine())!=null){System.out.println(msg);}}catch (Exception e){e.printStackTrace();}}
}
package BIO;import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;  //创建socket对象请求服务器的连接import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {try{//创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//从socket对象中获取一个字节输出流OutputStream os = socket.getOutputStream();//把字节输出流包装成一个打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while(true){System.out.println("请说");String msg = sc.nextLine();ps.println(msg);ps.flush();}}catch(IOException e){e.printStackTrace();}}
}

3、伪异步IO编程

在上述案例中:客户端的并发访问增加时。服务器将呈现1:1的线程开销,访问量越大,系统将发生线程栈溢出,线程创建失败,最终导致进程宕机或者僵死,从而不能对外提供服务。

可以采用伪异步IO通信框架,采用线程池的任务队列实现,当客户端接入时,将客户端的Socket封装成一个Task(该任务实现java.lang.Runnable线程任务接口)交给后端的线程池中进行处理。JDK的线程池维护一个消息队列和N个活跃的线程,对消息队列中的Socket任务进行处理,由于线程池可以设置消息队列的大小和最大线程数。因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。

服务器端:

package BIO;import jdk.internal.util.xml.impl.Input;
import sun.reflect.annotation.ExceptionProxy;import javax.print.DocFlavor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.Buffer;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;public class Server {public static void main(String[] args){try{ServerSocket ss = new ServerSocket(9999);//初始化一个线程池对象HandlerSocketServerPool pool = new HandlerSocketServerPool(6,10);while(true){Socket socket = ss.accept();//把socket封装成一个任务对象交给线程池处理Runnable target = new ServerRunnableTarget(socket);pool.execute(target);}}catch(Exception e){e.printStackTrace();}}}class HandlerSocketServerPool {//创建一个线程池的成员变量用于存储一个线程池对象private ExecutorService executorService;//初始线程池对象public HandlerSocketServerPool(int maxThreadNum, int queueSize){executorService = new ThreadPoolExecutor(3,maxThreadNum,120, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(queueSize));}//提供一个方法来提交任务给线程池的任务队列来暂存,等着线程池来处理public void execute(Runnable target){executorService.execute(target);}
}class ServerRunnableTarget implements Runnable {private Socket socket;public ServerRunnableTarget(Socket socket){this.socket = socket;}public void run(){try{InputStream is = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(is));String msg;if((msg = br.readLine())!=null){System.out.println("服务端接收到:"+msg);}}catch(Exception e){e.printStackTrace();}}
}
package BIO;import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;  //创建socket对象请求服务器的连接import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {try{//创建socket对象请求服务器的连接Socket socket = new Socket("127.0.0.1",9999);//从socket对象中获取一个字节输出流OutputStream os = socket.getOutputStream();//把字节输出流包装成一个打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while(true){System.out.println("请说");String msg = sc.nextLine();ps.println(msg);ps.flush();}}catch(IOException e){e.printStackTrace();}}
}

4、BIO模式下的文件上传

客户端:

package BIO;import java.io.*;
import java.net.Socket;  //创建socket对象请求服务器的连接import java.util.Scanner;
/*目标:实现客户端上传任意类型的文件数据给服务端保存起来*/
public class Client {public static void main(String[] args) throws IOException {try{//1、请求与服务器的Socket进行连接Socket socket = new Socket("127.0.0.1",8888);//2、把字节输出流包装成一个数据输出流DataOutputStream dos = new DataOutputStream(socket.getOutputStream());//3、先发送上传文件的后缀给服务端dos.writeUTF(".png");//4、把文件数据发送给服务器进行接收InputStream is = new FileInputStream("c:\\d.txt");byte[] buffer = new byte[1024];int len;while((len = is.read(buffer))>0)dos.write(buffer,0,len);dos.flush();socket.shutdownOutput();//通知服务端数据发送完毕}catch(IOException e){e.printStackTrace();}}
}

服务器端:

package BIO;import jdk.internal.util.xml.impl.Input;
import sun.reflect.annotation.ExceptionProxy;import javax.print.DocFlavor;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.Buffer;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Handler;public class Server {public static void main(String[] args){try{ServerSocket ss = new ServerSocket(8888);while(true){Socket socket = ss.accept();new ServerReaderThread(socket).start();}}catch(Exception e){e.printStackTrace();}}}class ServerReaderThread extends Thread {private Socket socket;public ServerReaderThread(Socket socket){this.socket = socket;}public void run(){try{//1、得到一个数据输入流读取客户端发送过来的数据DataInputStream dis = new DataInputStream(socket.getInputStream());//2、读取客户端发送过来的文件类型String suffix = dis.readUTF();//3、定义一个字节输出管道负责把客户端发来的文件数据写出去OutputStream os = new FileOutputStream("c:\\d.txt"+ UUID.randomUUID().toString()+suffix);//4、从数据输入流中读取文件数据,写出到字节输出流中取byte[] buffer = new byte[1024];int len;while((len = dis.read(buffer))>0)os.write(buffer,0,len);}catch(Exception e){e.printStackTrace();}}
}

http://chatgpt.dhexx.cn/article/FfnACDr0.shtml

相关文章

块设备驱动、bio理解

别人写过的内容&#xff0c;我就不写了。贴一下大佬的博客&#xff0c;写的非常好&#xff1a; 块设备驱动实战基础篇一 &#xff08;170行代码构建一个逻辑块设备驱动&#xff09; 块设备驱动实战基础篇二 &#xff08;继续完善170行过滤驱动代码至200行&#xff09; 块设备…

Java Bio编程

IO模型 基本说明 io模型就是数据的发送与接收&#xff0c;这个直接决定了程序之间通信的效率Java的网络编程常见三种Io分别是&#xff1a;bio&#xff0c;nio&#xff0c;aioBio&#xff1a;阻塞并且同步&#xff0c;服务器实现一个连接对应一个线程&#xff0c;如果这个连接…

JAVA BIO 编程

1. JAVA BIO基本介绍 Java BIO 就是传统的 java io 编程&#xff0c;其相关的类和接口在 java.io;BIO(blocking I/O) &#xff1a; 同步阻塞&#xff0c;服务器实现模式为一个连接一个线程&#xff0c;即客户端有连接请求时服务器端就需要启动一个线程进行处理&#xff0c;如果…

Java BIO

BIO通信模型 BIO通信服务端&#xff0c;通常有一个独立的Acceptor线程负责监听客户端的连接。接收到客户端连接请求后会为每个客户端创建一个新的线程进行链路处理&#xff0c;处理完成后返回应答给客户端&#xff0c;也就是经典的请求&#xff0d;应答通信模型。但是随着客户端…

BIO和NIO

两种通信模式BIO和NIO ​ io是指计算机的输入输出操作&#xff0c;广义的讲就是数据在的一种传输&#xff0c;可分为磁盘io&#xff08;硬盘的读写&#xff09;和网络io&#xff08;socket的读写&#xff09;&#xff0c;这里的两种模式都是基于网络io的。 io的分类 阻塞I/O…

BIO、NIO、AIO详解

一、Java的I/O演进之路 Java共支持3种网络编程的I/O模型&#xff1a;BIO、NIO、AIO BIO&#xff1a; 同步并阻塞&#xff08;传统阻塞型&#xff09;&#xff0c;服务器实现模式为一个连接一个线程&#xff0c;即客户端有连接请求时服务器端就需要启动一个线程进行处理&…

OpenSSL BIO源码简析

文章目录 1. BIO简介BIO chainBIO数据结构BIO_METHOD数据结构 2. Base64示例分析初始化构造BIO链写数据free 1. BIO简介 相关文档 /html/man7/bio.html /html/man3/BIO_*.htmlbio - Basic I/O abstraction&#xff0c;即IO抽象层。 BIO有两种: source/sink BIO&#xff0c;…

二、JAVA BIO

NIO 目录 文章目录 二、JAVA BIO1、 Java BIO基本介绍2、 java BIO工作机制3、传统的BIO编程实例回顾3.1、客户端案例如下3.2、服务端案例如下3.3、输出3.4、小结 4、BIO模式下多发和多收消息4.1、客户端代码如下4.2、服务端代码如下4.3、输出 5、BIO模式下接收多个客户端5.1、…

BIO和NIO的区别

1.BIO基本介绍 BIO是传统的Java IO编程&#xff0c;其基本的类和接口在java.io包中BIO(blocking I/O)&#xff1a;同步阻塞&#xff0c;服务器实现模式为一个连接一个线程&#xff0c;即客户端有连接请求时服务器端就需要启动一个线程进行处理&#xff0c;如果这个连接不做任何…

网络编程之中篇——BIO模型详述

1、BIO介绍 1.1、BIO的概念 BIO&#xff08;Blocking IO&#xff09;同步阻塞IO模型&#xff0c;在JDK 1.4之前&#xff0c;建立网络链接采用的只有BIO的模型 需要服务端首先启动建立一个ServerSocket实例&#xff0c;然后客户端启动Socket实例对服务端进行连接通信&#xf…

BIO,NIO,AIO分别是什么?他们有什么区别?

1、BIO 概念&#xff1a; BIO是一种同步阻塞I/O模式&#xff0c;服务实现模式为一个连接对应一个线程&#xff0c;即客户端发送一个连接&#xff0c;服务端要有一个线程来处理。 存在的问题&#xff1a; 一旦有高并发的大量请求,就会有如下问题&#xff1a; 1&#xff09;线程…

JAVA BIO与NIO、AIO的区别(这个容易理解)

IO的方式通常分为几种&#xff0c;同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。 一、BIO 在JDK1.4出来之前&#xff0c;我们建立网络连接的时候采用BIO模式&#xff0c;需要先在服务端启动一个ServerSocket&#xff0c;然后在客户端启动Socket来对服务端进行通信&#…

Quartus II 上手攻略

第一次接触EDA实验&#xff0c;对这方面的相关操作并不熟悉。本篇文章结合上课内容和B站Quartus进行整理&#xff0c;总结一下Quartus 这款软件的基本使用。 参考的B站教学链接&#xff1a;《Quartus II 软件安装与入门教程》 Quartus 软件简介 Quartus II 是Altera公司为其FP…

完全卸载quartus ii 9.0

即将毕业了&#xff0c;把电脑一些不用的软件清清&#xff0c;发现quartus软件贼占空间&#xff0c;删除又貌似找不到卸载的exe&#xff0c;百度了好多都不靠谱 下面介绍一种方法&#xff0c;可以很好的卸载掉quartus&#xff0c;原先我的quartus是安装在D盘下&#xff0c;结果…

Quartus II与Modelsim软件安装教程

Quartus II与Modelsim软件安装教程 一、Quartus II软件安装1、Quartus II安装2、器件安装3、Quartus 破解4、USB Blaster 驱动安装 二、Modelsim软件安装1、modelsim安装2、modelsim注册 三、参考资料 一、Quartus II软件安装 本节主要讲述Quartus II13.1软件的安装使用&#x…

Quartus II13.1安装教程

安装前先关闭杀毒软件和360卫士&#xff0c;注意安装路径不能有中文&#xff0c;安装包路径也不要有中文。 1.鼠标右击【Quartus II 13.1】压缩包选择【解压到Quartus II 13.1】。 2.双击打开解压后的【Quartus II 13.1】文件夹。 3.双击打开【Quartus】文件夹。 4.鼠标右击【Q…

Quartus II下载器件库

Quartus II下载器件库 1、在浏览器中输入网址 https://fpgasoftware.intel.com/18.1/?editionstandard&platformwindows&#xff0c; 或https://fpgasoftware.intel.com/ 进入如下图所示界面。 2、在版本类型和版本中输入Quartus II所对应的版本 3、输入完版本后&#…

Quartus II软件的使用

在这里&#xff0c;我们只是简单的介绍了一下上述的流程图&#xff0c;让大家有个大致的了解&#xff0c;接下来我们就以流水灯实验的工程为例&#xff0c;对每个流程进行详细的操作演示&#xff0c;一步步、手把手带领大家学习使用Quartus II软件。 在创建工程之前&#xff0c…

QuartusII中LPM_COUNTER的使用

ALTERA建议&#xff0c;在设计时时序允许的情况下尽量使用Megafunction的资源&#xff0c;因为在多数情况下Megafunction的综合和实现结果更为优化。现在&#xff0c;就LPM_COUNTER的使用&#xff0c;浅谈一下。 Megafunction中LPM_COUNTER的参数设定主要是以下三部分&#xf…

quartus II 18.1 下载

quartus II 18.1 下载链接 以及解析 链接:https://pan.baidu.com/s/1warS-Vvv1maDmOKu8RsteQ 提取码&#xff1a;awxd 这个链接是已经下好的安装包 链接:https://pan.baidu.com/s/13HuyxUZvZ19vdYUmlLJujQ 提取码&#xff1a;gudn 第二个链接解压密码&#xff1a; wqlx.13542…