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

article/2025/11/8 10:11:09

1、BIO介绍

1.1、BIO的概念

BIO(Blocking IO)同步阻塞IO模型,在JDK 1.4之前,建立网络链接采用的只有BIO的模型

需要服务端首先启动建立一个ServerSocket实例,然后客户端启动Socket实例对服务端进行连接通信,服务端通过调用accept方法等待接收客户端的连接请求,一旦接收到连接请求,就可以进行读写操作

在BIO编程中,相应的方法会产生阻塞:accept()、read()、write()、connect(),直至相关的操作等待完成之后才能继续后续代码处理,比如read操作,整个IO操作的过程都会阻塞,直至读取到数据之后才能继续执行(阻塞IO)

1.2、BIO支持高并发解决措施

如果BIO来考虑高并发问题,同时处理多个客户端的连接,就必须要使用多线程,即每次accept阻塞等待来自客户端的连接请求,一旦收到连接请求就将获取的套接字socket通过创建一个新的线程来处理IO操作,然后又继续通过accept接收客户端的连接

2、BIO编程

实现echo命令,客户端输入任何信息,服务端接收到信息并返回给客户端

2.1、只有一个客户端连接

服务端代码:

public class SingleServer {public static void main(String[] args) {ServerSocket serverSocket = null;Socket socket = null;InputStream inputStream = null;OutputStream outputStream = null;try {//创建ServerSocket实例并绑定端口serverSocket = new ServerSocket(7777);System.out.println("服务端绑定端口7777并启动啦");//等待并接受客户端连接socket = serverSocket.accept();//getRemoteSocketAddress() 获取连接的对方的IP和端口System.out.println("有新的客户端连接:" + socket.getRemoteSocketAddress());//进行读写操作inputStream = socket.getInputStream(); //读取客户端数据outputStream = socket.getOutputStream();//给客户端发送数据byte[] bytes = new byte[100];//可多次接受数据int len = 0;//判断当前的一个消息是否结束String recv = null;while ((len = inputStream.read(bytes)) != -1) {recv = new String(bytes, 0, len);System.out.println("客户端发送消息:" + recv);//封装返回给客户端outputStream.write(("[echo]" + recv + "\n").getBytes());outputStream.flush();//判断当前业务结束标识:客户端发送exitif (recv != null && "exit".equals(recv.trim())) {System.out.println("客户端断开即将断开连接");break;}}} catch (IOException e) {e.printStackTrace();} finally {try {//关闭资源if (serverSocket != null) serverSocket.close();if (socket != null) socket.close();if (inputStream != null) inputStream.close();if (outputStream != null) outputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

客户端代码:

public class Client {public static void main(String[] args) {Socket socket = null;InputStream inputStream = null;OutputStream outputStream = null;//获取从键盘输入的内容Scanner scanner = new Scanner(System.in);scanner.useDelimiter("\n");try {//创建socket实例socket = new Socket();//连接服务端socket.connect(new InetSocketAddress("127.0.0.1",7777));System.out.println("客户端连接服务端成功");//读写操作outputStream = socket.getOutputStream();inputStream = socket.getInputStream();byte[] bytes = new byte[100];while (scanner.hasNext()) {//获取键盘内容String msg = scanner.next();if (msg == null || "".equals(msg.trim())) continue;//发给服务端outputStream.write(msg.getBytes());outputStream.flush();//接收服务端返回的数据int num = inputStream.read(bytes);System.out.println("服务端返回:"+new String(bytes,0,num));if ("exit".equals(msg.trim())) {//特定结束System.out.println("客户端主动断开连接啦");break;}}} catch (IOException e) {e.printStackTrace();} finally {//关闭资源try {if (socket != null) socket.close();if (outputStream != null) outputStream.close();if (inputStream != null) inputStream.close();} catch (Exception e) {}}}
}

2.2、BIO支持高并发

/*** desc:服务端* BIO+ 多线程方案:解决高并发问题*  主线程主要职责:监听客户端的连接,每有一个新客户端的连接获取到连接实例socket,新创建子线程来处理读写IO操作*  子线程职责:处理IO读写操作*/public class MultiThreadServer {public static void main(String[] args) {ServerSocket serverSocket = null;try {//创建ServerSocket实例serverSocket = new ServerSocket(9999);System.out.println("服务端绑定端口9999并启动啦");//等待多客户端的连接,不断循环等待客户端的连接while (true) {Socket socket = serverSocket.accept();System.out.println("有新用户连接啦:"+socket.getRemoteSocketAddress());//每一个新用户连接都交给一个新线程来处理,重点:将Socket交给子线程new Thread(new RunableHandler(socket)).start();}} catch (IOException e) {}}
}
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;public class RunableHandler implements Runnable {private Socket socket;//socket实例,每一个线程单独处理一个socketpublic RunableHandler(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//进行读写操作InputStream inputStream = socket.getInputStream(); //读取客户端数据OutputStream outputStream = socket.getOutputStream();//给客户端发送数据byte[] bytes = new byte[100];//可多次接受数据int len = 0;//判断当前的一个消息是否结束String recv = null;while ((len = inputStream.read(bytes)) != -1) {recv = new String(bytes, 0, len);System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 发送消息:" + recv);//封装返回给客户端outputStream.write(("[echo]" + recv + "\n").getBytes());outputStream.flush();//判断当前业务结束标识:客户端发送exitif (recv != null && "exit".equals(recv.trim())) {System.out.println("客户端:"+socket.getRemoteSocketAddress()+" 断开即将断开连接");break;}}//关闭资源socket.close();inputStream.close();outputStream.close();} catch (Exception e) {}}
}

通过对BIO的高并发的实现可知:在BIO实现的过程中,为了支持多客户端请求,每一个客户端的连接请求都会新分配一个线程来做处理。并不意味着线程创建的越多越好,每创建一个线程,需要消耗的内存资源,而内存资源是有限的,另线程越多,在系统进行调度的过程中上下文的切换也会消耗性能, 通过BIO来实现高并发,创建的线程越多反而会是性能大打折扣。


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

相关文章

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

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

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

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

Quartus II 上手攻略

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

完全卸载quartus ii 9.0

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

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卫士,注意安装路径不能有中文,安装包路径也不要有中文。 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, 或https://fpgasoftware.intel.com/ 进入如下图所示界面。 2、在版本类型和版本中输入Quartus II所对应的版本 3、输入完版本后&#…

Quartus II软件的使用

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

QuartusII中LPM_COUNTER的使用

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

quartus II 18.1 下载

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

Quartus II14.1安装教程

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

quartus ii matlab,基於Quartus II和MATLAB的FIR濾波器設計與仿真(二)

接上文 基於Quartus II和MATLAB的FIR濾波器設計與仿真(一): 3 QuartusII 調用 IP 核生成 FIR 濾波器模塊 在 Quartus II 中, Altera 提供了一系列可供用戶免費使用的 IP 核, FIR濾波器就包含其中,所以只需要在 Quartus II 中調用…

安装Quartus II教程

下载Quartus安装包,给大家一个11.3版本的安装包 链接:https://pan.baidu.com/s/1eXtjL2JZVGV1RBC0VozqVQ?pwdhmnv 提取码:hmnv 1.打开安装程序,点击next 2.点击接受,下一步 3.选择安装路径,这里最好选择…

Quartus II 仿真

Quartus II 使用university program VWF仿真 1.File->new->university program VWF->OK打开仿真页面 2.edit->insert->insert node or bus或者直接双击左边空白地方弹出insert node or bus对话框。 3.node finder->list-> >> ->OK->OK 4.设…

QuartusII9.0--项目文件的新建

第一步:打开QuartusII软件,界面如下: 第二步:选择File->New Project Wizard菜单项,则弹出New Project Wizard:Indroduction对话框,如下图所示: 单击Next按钮,则进入项目工程的目…

Quartus II报错

使用如下电路语句创建异步时序实现D触发器时 一直报错 Error (10200): Verilog HDL Conditional Statement error at flip_flop.v(9): cannot match operand(s) in the condition to the corresponding edges in the enclosing event control of the always construct 在网上…

【QuartusII】0-创建工程模板

一、创建工程 1、激活安装quartus II软件后,打开即见如下界面 2、在菜单栏 “File -> New Project Wizard…”中,进入创建工程流程 3、第一部分,如下图,配置路径、项目名称、以及顶层文件(类似C语言的main&#xf…

quartus II 18.1 Qsys简单操作步骤

1.建立工程 2.选择芯片时,在界面device and pin options中的unused pins选择as input tri-stated ; 3.创建NiOS II软核处理系统 ,18.1在tools->platform designer 4.出现该界面,选择file->save->nios2_small 保存成功后找到下面nio…

Quartus II18.0安装教程

试装系统:win10 64bit 安装包路径和安装路径最好都不要出现中文,一般选择默认安装在C盘。 1. 解压安装包。 2. 在安装软件前,请确认你需要安装的器件,根据安装包中器件库下载地址.txt中的地址进行器件库下载,器件库下载…

Quartus ii 软件的使用

一、开发工程 1.新建工程 选择一个路径作为工程存放位置,然后在工程文件夹创建4个子文件夹,分别命名为: doc、par、rtl和sim。 doc文件夹用于存放项目相关的文档, par文件夹用于存放Quartus软件的工程文件,rtl文件夹…