简述 BIO 、NIO 模型

  • BIO : 同步阻塞I/O(Block IO)

         服务器实现模式为每一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,此处可以通过线程池机制进行优化。

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;/*** 多人聊天室 - 服务端*/
public class BioServer {static List<Socket> clientList = new ArrayList<>();public static void main(String[] args) throws Exception {int port = 8080;ServerSocket serverSocket = new ServerSocket(port);while (true) {Socket client = serverSocket.accept();System.out.println("客户端: " + client.getPort() + " 连接成功!");clientList.add(client);forwardProcess(client);}}/*** 转发处理*/public static void forwardProcess(Socket socket) {new Thread(new Runnable() {@Overridepublic void run() {while (true) {forwardMsg(socket);}}}).start();}/*** 转发消息*/public static void forwardMsg(Socket socket) {try {String msg = readMsg(socket);System.out.println(msg);for (Socket client : clientList) {if (client != socket) {writeMsg(client, msg);}}} catch (IOException e) {throw new RuntimeException(e);}}/*** 写入消息*/public static void writeMsg(Socket socket, String msg) throws IOException {PrintStream ps = new PrintStream(socket.getOutputStream());ps.println(msg);ps.flush();}/*** 读取消息*/public static String readMsg(Socket socket) throws IOException {InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));String msg;if ((msg = br.readLine()) != null) {msg = socket.getPort() + " 说: " + msg;}return msg;}}

import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class BilClient {public static void main(String[] args) throws IOException {String ip = "127.0.0.1";int port = 8080;Socket client = new Socket(ip, port);readProcess(client);OutputStream os = client.getOutputStream();PrintStream ps = new PrintStream(os);Scanner scanner = new Scanner(System.in);while (true) {String input = scanner.nextLine();ps.println(input);ps.flush();}}/*** 读取处理*/public static void readProcess(Socket socket) {new Thread(() -> {while (true) {try {System.out.println(readMsg(socket));} catch (IOException e) {throw new RuntimeException(e);}}}).start();}/*** 读取消息*/public static String readMsg(Socket socket) throws IOException {InputStream inputStream = socket.getInputStream();BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));String msg;if ((msg = br.readLine()) != null) {}return msg;}
}

  • ​NIO: 同步非阻塞式IO,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求会被注册到多路复用器上,多路复用器轮询到有 I/O 请求就会进行处理。
  • Channel,翻译过来就是“通道”,就是数据传输的管道,类似于“流”,但是与“流”又有着区别。
    • 既可以从Channel中读取数据,又可以写数据到Channel,但流的读写通常是单向的——输入输出流
    • 通道可以异步读写
    • 通道中的数据总是先读取到buffer(缓冲区),或者总是需要从一个buffer写入,不能直接访问数据
    • 非阻塞特性:Channel在设计上采用了非阻塞的特性,它不会像传统的流一样在读写操作上阻塞线程,而是立即返回结果,告诉调用者当前的状态。这使得程序可以在等待数据准备的过程中同时进行其他操作,实现了非阻塞IO。
    • 事件通知机制:Channel通常搭配选择器(Selector)来使用,选择器能够检测多个Channel的就绪状态,如是否可读、可写等,并通过事件通知(例如轮询或回调)及时地通知程序哪些Channel处于就绪状态,从而可以进行相应的读写操作。这种机制支持程序实现异步IO模型。
    • 操作系统底层支持:Channel的异步读写也依赖于操作系统底层的异步IO支持。Java NIO中的Channel实际上是对操作系统底层异步IO的封装和抽象,利用了操作系统提供的异步IO机制来实现其自身的异步读写功能。
  • Buffer是一个对象,里面是要写入或者读出的数据,在java.nio库中,所有的数据都是用缓冲区处理的。
    • 在读取数据时,它是直接读到缓冲区中的;在写入数据时,也是直接写到缓冲区中,任何时候访问Channel中的数据,都是通过缓冲区进行操作的。
    • 缓冲区实质上是一个数组,通常是一个字节数组ByteBuffer,当然也有其他类型的:
  • Selector被称为选择器,Selector会不断地轮询注册在其上的Channel,如果某个Channel上发生读或写事件,这个Channel就被判定处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取到就绪Channel的集合,进行后续的I/O操作。
    • 一个多路复用器Selector可以同时轮询多个Channel,JDK使用了epoll()代替了传统的select实现,所以并没有最大连接句柄的限制,这意味着只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端。


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Set;/*** NIO 聊天室 服务端*/
public class NioServer {private Integer port;ByteBuffer readBuffer = ByteBuffer.allocate(1024);ByteBuffer writerBuffer = ByteBuffer.allocate(1024);private Charset charset = Charset.forName("UTF-8");public NioServer(Integer port) {this.port = port;}public static void main(String[] args) {NioServer nioServer = new NioServer(8080);nioServer.start();}private void start() {try {// 开启socketServerSocketChannel server = ServerSocketChannel.open();// 设置非阻塞server.configureBlocking(false);// 绑定端口server.socket().bind(new InetSocketAddress(port));// 开启通道, 得到 Selector (选择器)Selector selector = Selector.open();//  注册 selector 监听事件server.register(selector, SelectionKey.OP_ACCEPT);System.out.println("启动服务器, 监听端口:" + port + "...");while (true) {// 阻塞监控所有注册的通道,当有对应的事件操作时, 会将SelectionKey放入 集合内部并返回事件数量selector.select();// 返回存有SelectionKey的集合Set<SelectionKey> selectionKeys = selector.selectedKeys();for (SelectionKey selectionKey : selectionKeys) {handle(selectionKey, selector);}//  处理后清理 selectionKeysselectionKeys.clear();}} catch (Exception e) {e.printStackTrace();}}/*** 事件处理*/private void handle(SelectionKey key, Selector selector) throws IOException {//  SelectionKey 常用方法//isAcceptable()	是否是连接继续事件//isConnectable()	是否是连接就绪事件//isReadable()	是否是读就绪事件//isWritable()	是否是写就绪事件// SelectionKey 常用事件//SelectionKey.OP_ACCEPT	接收连接继续事件,表示服务器监听到了客户连接,服务器可以接收这个连接了//SelectionKey.OP_CONNECT	连接就绪事件,表示客户端与服务器的连接已经建立成功//SelectionKey.OP_READ	读就绪事件,表示通道中已经有了可读的数据,可以执行读操作了(通道目前有数据,可以进行读操作了)//SelectionKey.OP_WRITE	写就绪事件,表示已经可以向通道写数据了(通道目前可以用于写操作)//处理连接if (key.isAcceptable()) {ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel client = server.accept();client.configureBlocking(false);client.register(selector, SelectionKey.OP_READ);System.out.println(client.socket().getPort() + " 已建立连接 ...");}//  读取消息else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();String msg = client.socket().getPort() + " 说: " + readMsg(client);System.out.println(msg);forwardMsg(msg, client, selector);}}/*** 读取通道消息*/private String readMsg(SocketChannel client) throws IOException {readBuffer.clear();while (client.read(readBuffer) > 0) ;readBuffer.flip();return String.valueOf(charset.decode(readBuffer));}/*** 转发*/private void forwardMsg(String msg, SocketChannel client, Selector selector) throws IOException {for (SelectionKey key : selector.keys()) {Channel connectedClient = key.channel();if (connectedClient instanceof ServerSocketChannel) {continue;}if (key.isValid() && !client.equals(connectedClient)) {writerBuffer.clear();writerBuffer.put(charset.encode(msg));writerBuffer.flip();while (writerBuffer.hasRemaining())((SocketChannel) connectedClient).write(writerBuffer);}}}
}


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;
import java.util.Set;/*** NIO 聊天室 客户端*/
public class NioClient {private String ip;private Integer port;private ByteBuffer writerBuffer = ByteBuffer.allocate(1024);private ByteBuffer readBuffer = ByteBuffer.allocate(1024);private Charset charset = Charset.forName("UTF-8");public NioClient(String ip, Integer port) {this.ip = ip;this.port = port;}public static void main(String[] args) {NioClient nioClient = new NioClient("127.0.0.1", 8080);nioClient.start();}public void start() {try {// 开启通道SocketChannel client = SocketChannel.open();// 设置非阻塞client.configureBlocking(false);Selector selector = Selector.open();client.register(selector, SelectionKey.OP_CONNECT);client.connect(new InetSocketAddress(ip, port));while (true) {selector.select();Set<SelectionKey> selectionKeys = selector.selectedKeys();for (SelectionKey selectionKey : selectionKeys) {handle(selectionKey, selector);}selectionKeys.clear();}} catch (Exception e) {e.printStackTrace();}}private void handle(SelectionKey key, Selector selector) throws IOException {// 处理连接事件if (key.isConnectable()) {SocketChannel client = (SocketChannel) key.channel();if (client.isConnectionPending()) {client.finishConnect();// 处理用户输入new Thread(() -> {Scanner scanner = new Scanner(System.in);while (true) {String msg = scanner.nextLine();writerBuffer.clear();writerBuffer.put(charset.encode(msg));writerBuffer.flip();while (writerBuffer.hasRemaining()) {try {client.write(writerBuffer);} catch (IOException e) {throw new RuntimeException(e);}}}}).start();}client.register(selector, SelectionKey.OP_READ);}// 读取消息信息else if (key.isReadable()) {SocketChannel client = (SocketChannel) key.channel();String s = readMsg(client);System.out.println(s);}}private String readMsg(SocketChannel client) throws IOException {readBuffer.clear();while (client.read(readBuffer) > 0) ;readBuffer.flip();return String.valueOf(charset.decode(readBuffer));}
}

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

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

相关文章

工业光源环形系列一高均匀条形光源特点

产品特点 ◆可以根据检测需求随意调整照射角度&#xff1a; ◆可以根据检测需求选择光源颜色&#xff1a; ◆多个条形光源可以自由组合&#xff1a; ◆使用贴片灯珠&#xff0c;均匀性更好。

VMP 简单源码分析(.net)

虚拟机 获取CPU的型号 实现了一个指令集解释器&#xff0c;每个操作码对应一个特定的处理函数&#xff0c;用于执行相应的指令操作。在执行字节码时&#xff0c;解释器会根据操作码查找并调用相应的处理函数来执行指令。 截获异常 先由虚拟机处理 处理不了再抛出异常 priva…

第五节 内联框架强化练习

建立左右常用框架结构说明 1、添加动态面板如下&#xff1a; 2、添加树元件 3、添加树节点&#xff08;右键->添加子节点 右键->点添加节点&#xff09; 4、添加交互页面 5、添加单击交互跳转事件到内联框架中(注意当前内联框架与当前面板要处在同级目录) 6、添加交互跳…

外贸尾货全新变现玩法,冷门暴利项目,单月轻松3W+

有些朋友可能不太了解什么是外贸尾货。实际上&#xff0c;当我们国内的厂家进行外贸出口业务时&#xff0c;生产的商品并不总是能够完全销售到国外。为了避免出现瑕疵品&#xff0c;厂家通常会生产超出订单数量的产品&#xff0c;以确保产品质量和满足出口需求。例如&#xff0…

uniapp实现下拉刷新效果-uniapp原生接口

onPullDownRefresh | uni-app官网 1、需要在 pages.json 里&#xff0c;找到的当前页面的pages节点&#xff0c;并在 style 选项中开启 enablePullDownRefresh 2、生命周期中添加onPullDownRefresh&#xff0c;下拉时获取数据 3、处理完数据后&#xff0c;停止下拉效果stopPul…

web前端学习笔记7-iconfont使用

7. iconfont的使用流程 字体图标使用较多的是阿里巴巴iconfont图标库,它是阿里巴巴体验团队推出的图标库和图标管理平台,提供了大量免费和可定制的矢量图标,以满足网页设计、平面设计、UI设计、应用程序开发和其他创意项目的需求。 官方网站:https://www.iconfont.cn/ 使用…

MYSQL RR隔离级别下无索引更新是否表锁?

最近在MYSQL菜鸟群有群友提问,说他看了某个公众号里面文章说 "MYSQL RR隔离级别下无索引更新会导致表锁! " 他表示疑惑,而且不仅是他,还有很多个她在不同的群里同样表示疑惑! 下面是群友的截图 是啊 MYSQL 以及进化到了8.3.0版本了,普遍都使用5.7和8.0版本.而且还…

Navicat for MySQL Mac:数据库管理与开发的理想工具

Navicat for MySQL Mac是一款功能强大的数据库管理与开发工具&#xff0c;专为Mac用户设计&#xff0c;旨在提供高效、便捷的数据库操作体验。 它支持创建、管理和维护MySQL和MariaDB数据库&#xff0c;通过直观的图形界面&#xff0c;用户可以轻松进行数据库连接、查询、编辑和…

提升开发者效率的必备工具

目录 前言1. Git2. Docker3. Postman4. Apipost5. PyCharm6. IntelliJ IDEA7. Everything8. Sublime Text9. 截图工具&#xff08;Snipaste&#xff09;10. Markdown 在线编辑器11. Xmind 思维导图12. 在线流程图制作工具&#xff08;如 ProcessOn&#xff09;结语 前言 在快节…

MambaMOS:基于激光雷达的三维运动物体分割与运动感知状态空间模型

MambaMOS:基于激光雷达的三维运动物体分割与运动感知状态空间模型 摘要INTRODUCTIONRelated WorkMethod MambaMOS: LiDAR-based 3D Moving Object Segmentation with Motion-aware State Space Model 摘要 激光雷达基于的运动目标分割&#xff08;MOS&#xff09;旨在利用之前…

106短信群发平台:拓客拉新、商品促销,效果究竟如何?一试便知!

106短信群发平台在拓客拉新和商品促销方面的效果是非常显著的。 首先&#xff0c;从发送速度和到达率来看&#xff0c;106短信平台表现优秀。无论是节假日还是平日&#xff0c;其发送速度都能保持在一个较快的水平&#xff0c;这对于需要及时到达的营销信息尤为重要。同时&…

STM32学习笔记--疑问篇

STM32学习笔记–疑问篇 GPIO是什么的缩写通用寄存器的缩写和全程 3.、这是什么的缩写 不同输出模式之间的差异 PB是GPIOB的缩写&#xff1f; 怎样知道端口应该设置成输入模式还是设置成输出模式

【强训笔记】day11

NO.1 思路&#xff1a;枚举&#xff0c;设一号大礼包的数量为x&#xff0c;二号大礼包的数量为y&#xff0c;用循环枚举一号大礼包的个数得到二号大礼包的数量&#xff0c;使得某一时刻axby的值最大。 代码实现&#xff1a; #include<iostream>using namespace std;lo…

Node.js里面 Path 模块的介绍和使用

Node.js path 模块提供了一些用于处理文件路径的小工具&#xff0c;我们可以通过以下方式引入该模块&#xff1a; var path require("path") 方法描述 序号方法 & 描述1path.normalize(p) 规范化路径&#xff0c;注意.. 和 .。2path.join([path1][, path2][,…

Web开发小知识点(一)

1.input不支持自动换行解决办法 input不支持换行&#xff1b; textarea&#xff1a;支持换行&#xff1b; 设置提示文案的css 用&#xff1a;&#xff1a;placeHolder 2.textarea禁止拖拽、去掉右下角三角&#xff08;css下&#xff09; textarea{resize:none; } 3.用户对访…

中学数学重大错误:射线A沿其正向平移非0距离就变为其真子集了

黄小宁 射线A沿其射出的方向平移非0距离变为B≌A&#xff0c;中学数学一直认定B是A的一部分&#xff0c;其实这是将两异射线&#xff08;函数&#xff09;误为同一射线&#xff08;函数&#xff09;的肉眼直观错觉。设“点集A&#xff5b;点p&#xff5d;”表示A的元素是点p&a…

【分享】基于集成成像的悬浮光场3D显示系统

摘要: 悬浮显示技术是一种非常具有发展前景的显示技术&#xff0c;它可以将图像显示在空中&#xff0c;给观看者带来沉浸感和临场感的体验。目前国内悬浮3D显示技术研究还处于初级阶段。文章提出基于集成成像的悬浮3D显示系统&#xff0c;系统由集成成像3D显示器、半透半反镜和…

Cordova 12 Android 不支持 http 原因探索

最近在升级 Cordova 到最新版本&#xff0c;升级完成后发现无法请求网络&#xff0c;研究了两次最终发现解决方案。 发现控制台中有日志输出&#xff0c;提示当前是 https &#xff0c;无法直接访问 http。 [INFO:CONSOLE(225)] "Mixed Content: The page at https://lo…

第11篇:创建Nios II工程之控制多个七段数码管

Q&#xff1a;DE2-115开发板上有8个七段数码管&#xff0c;如何用PIO IP并设计Nios II工程控制呢&#xff1f; A&#xff1a;基本思路&#xff1a;DE2-115上有8个7位七段数码管&#xff0c;而一个PIO最多可配置为32位&#xff0c;如此就可以添加2个PIO都配置为28位output。 Ni…

大数据掌控秘籍:一步步教你安装和驾驭Cloudera的无限潜力

Cloudera是一家提供大数据解决方案的公司&#xff0c;主要产品是Cloudera Enterprise&#xff0c;它是一个基于Apache Hadoop、Apache Spark和其他开源技术的大数据平台。Cloudera Enterprise提供了一个完整的大数据生态系统&#xff0c;包括数据存储、数据处理、数据分析和数据…