2.BIO与NIO区别

【README】

  • 1.本文总结自B站《netty-尚硅谷》,很不错;
  • 2.本文介绍 BIO, NIO的知识;

【1】BIO(传统java IO模型)

1)BIO-Blocking IO:同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理;

2)原理图如下:

【图解】

  • 1.client: 可以使用 telnet 作为客户端连接服务器;
  • 2.BIO:每当有一个客户端连接时,服务器就启动一个新线程与之通讯(当然可以复用线程池)

 【代码实现】

/*** @Description 阻塞式IO服务器* @author xiao tang* @version 1.0.0* @createTime 2022年08月13日*/
public class BIOServer {public static void main(String[] args) throws IOException {// 创建一个线程池ExecutorService threadPool = Executors.newCachedThreadPool();int order = 0;// 创建 服务器 套接字ServerSocket serverSocket = new ServerSocket(6666);System.out.println("服务器启动成功.");while(true) {System.out.println("等待客户端请求");Socket socket = serverSocket.accept(); // 没有客户端请求,accept阻塞System.out.printf("客户端[%d]请求建立连接\n", ++order);final int orderCopy = order;threadPool.execute(()->{handler(socket, orderCopy);});}}/*** @description 与客户端通讯* @param socket 连接套接字* @author xiao tang* @date 2022/8/13*/public static void handler(Socket socket, int order) {byte[] byteArr = new byte[1024];try {// 读取客户端发送的数据InputStream inputStream = socket.getInputStream();int length = 0;// 客户端没有数据,read阻塞
//            while( ( length = inputStream.read(byteArr))!= -1) {
//                System.out.println(new String(byteArr, 0, length));
//            }while(true) {System.out.printf("线程id[%s],等待客户端[%d]发送数据\n", Thread.currentThread().getId(), order);length = inputStream.read(byteArr);if (length == -1) break;System.out.printf("线程id[%s],客户端[%d]:" + new String(byteArr, 0, length) + "\n",  Thread.currentThread().getId(), order);}} catch (IOException e) {e.printStackTrace();} finally {// 关闭与客户端的连接try {socket.close();System.out.printf("关闭与客户端[%d]的连接\n", order);} catch (IOException e) {}}}
}


【2】NIO (同步非阻塞IO)

【2.0】NIO概述

  • 1)Java NIO 全称 java non-blocking IO,是指 JDK 提供的新API。从 JDK1.4 开始,Java 提供了一系列改进的输入/输出的新特性,被统称为 NIO(即 New IO),是同步非阻塞的;
  • 2)NIO 相关类都被放在 java.nio 包及子包下,并且对原java.io 包中的很多类进行改写。
  • 3)NIO 有三大核心部分: Channel(通道),Buffer(缓冲区), Selector(选择器)
  • 4)NIO是 面向缓冲区 ,或者面向块编程的。数据读取到缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络;

5)NIO非阻塞IO处理架构:

【图解】

  • 1.使用NIO,服务器启动一个线程可以处理多个客户端请求。假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。不像之前的阻塞IO那样,非得分配10000个。
  • 2.通道Channel 是封装在  java输入输出流中的对象;

【小结】

  • NIO 有三大核心部分: Channel(通道),Buffer(缓冲区), Selector(选择器)

【比较】NIO 与 BIO的比较

  • 1)BIO 以流的方式处理数据,而 NIO 以块的方式处理数据, 块I/O 的效率比流I/O高很多
  • 2) BIO 是阻塞的,NIO 则是非阻塞的;
  • 3) BIO基于字节流和字符流进行操作,而 NIO 基于Channel(通道)和Buffer(缓冲区)进行操作;磁盘数据借助通道读入到缓冲区,或者从缓冲区写出到磁盘。

补充:NIO中,Selector(选择器) 用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道;


【3】NIO3大核心部分

1)NIO 有三大核心部分: Buffer(缓冲区),  Channel(通道),Selector(选择器) ;

 2)3个模块关联关系如下:

【图解】

  • 1)一个服务器线程对应一个选择器;一个选择器对应多个通道(因为多个通道可以注册到同一个选择器);
  • 2)一个通道对应一个缓冲区 buffer;
  • 4)cpu切换到哪个channel运行 ,是由事件决定的;事件 event 是一个很重要的概念(如 ACCEPT, READ 事件);
  • 5)Selector 会根据不同事件,在各个通道上切换;
  • 6)Buffer 本质上就是一个内存块,底层是由一个数组实现;
  • 7)数据读取或写入,是通过buffer来完成,这个和 BIO 是有本质不同的;此外,BIO要么是输入流,要么是输出流,不能双向;但NIO的buffer是可读可写的,需要flip方法进行切换
  • 8)Channel 是双向的,可以反应底层操作系统的情况,如 linux底层的操作系统通道就是双向的;

【3.1】NIO中的Buffer缓冲 

【3.1.1】buffer缓冲概述

1)缓冲区(Buffer):

  • 缓冲区本质上是一个可以读写数据的内存块(如字节数组),可以更轻松地使用内存块;
  • 缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况。

2)Channel 提供读写文件的接口、都必须经由Buffer,如下图所示。

参见 FileChannel读写文件代码( NIOFileChannel015.java ,下文有)

【代码】NIO中缓冲区的使用

/*** @Description 缓冲区使用* @author xiao tang* @version 1.0.0* @createTime 2022年08月13日*/
public class BasicBuffer {/*** @description Buffer的使用*/public static void main(String[] args) {// 创建一个bufferIntBuffer intBuffer = IntBuffer.allocate(5);// 向buffer存放数据for (int i = 0; i < intBuffer.capacity(); i++) {intBuffer.put(i*2);}// 从buffer 读取数据// 需要先把 buffer 转换,读写切换(写模式切换到读模式)intBuffer.flip();intBuffer.position(1);while(intBuffer.hasRemaining()) {System.out.println(intBuffer.get());}}
}

【3.1.2】buffer子类及属性

1)子类

【图解】

  • ByteBuffer,存储字节数据到缓冲区(常用)-字节缓冲区
  • ShortBuffer,存储短整型数据到缓冲区;
  • CharBuffer,存储字符数据到缓冲区;
  • IntBuffer,存储整数数据到缓冲区;
  • LongBuffer,存储长整型数据到缓冲区;
  • DoubleBuffer,存储双精度到缓冲区;
  • FloatBuffer,存储单精度到缓冲区;

2)buffer的4个属性

public abstract class Buffer {private int mark = -1;private int position = 0;private int limit;private int capacity;

序号

属性

描述

1

Capacity

容量,即缓冲区大小,定长不能改变。

2

Position

当前位置;表示下一个要被读写的元素的下标(索引)

3

limit

表示缓冲区最大可用位置,读写时不能超过极限位置

4

Mark

标记,不修改。

【3.1.3】只读buffer

/*** @Description 只读 buffer* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOReadOnly017 {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(64);for (int i = 0; i < 4; i++) {buffer.put((byte) i);}// 读取buffer.flip();// 得到一个只读bufferByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();System.out.println(readOnlyBuffer.getClass()); // java.nio.HeapByteBufferR// 读取while (readOnlyBuffer.hasRemaining()) {System.out.println(readOnlyBuffer.get());}readOnlyBuffer.flip();readOnlyBuffer.put((byte)0); // 抛出异常-ReadOnlyBufferException}
}

【3.1.4】 get与put() 方法操作 数据类型要一致

buffer缓冲中 get与put() 方法操作 数据类型要一致 :

/*** @Description buffer put 与 get 操作的数据类型要一致* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOByteBufferPugGet017 {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(64);// 类型化方式放入数据buffer.putInt(100);buffer.putLong(4);buffer.putChar('中');buffer.putShort((short)4);// 取出buffer.flip();System.out.println();System.out.println(buffer.getInt());System.out.println(buffer.getChar());System.out.println(buffer.getLong());System.out.println(buffer.getLong()); // 抛出异常}
}

【3.1.5】 Buffer的分散与聚集(buffer数组读写数据)

前面我们讲的读写操作,都是通过一个Buffer 完成的,NIO还支持通过多个Buffer (即 Buffer 数组) 完成读写操作,即 Scattering 和Gathering;

2)buffer的分散与聚集( Scattering 与 Gathering )

  • Scattering: 将数据写入到buffer时,可以采用buffer数组,依次写入。
  • Gathering: 从buffer读取数据时, 可以采用buffer数组,依次读取。
/*** @Description buffer的分散与聚集( Scattering 与 Gathering )*              Scattering: 将数据写入到buffer时,可以采用buffer数组,依次写入。*              Gathering: 从buffer读取数据时, 可以采用buffer数组,依次读取。* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class ScatterAndGatherBuffer019 {public static void main(String[] args) throws Exception {// 使用 ServerSocketChannel 和 SocketChannelServerSocketChannel serverSocketChannel = ServerSocketChannel.open();InetSocketAddress inetSocketAddress = new InetSocketAddress(7000);// 绑定端口到socket 并启动serverSocketChannel.socket().bind(inetSocketAddress);// 创建buffer数组ByteBuffer[] byteBuffers = new ByteBuffer[2];byteBuffers[0] = ByteBuffer.allocate(5);byteBuffers[1] = ByteBuffer.allocate(3);// 等待客户端连接(telnet)SocketChannel socketChannel = serverSocketChannel.accept();// 循环读取int msgLength = 8;  // 假定从客户端接收8个字节int byteRead = 0;while (byteRead < msgLength) {long singleLength = socketChannel.read(byteBuffers);byteRead += singleLength;System.out.println("byteRead = " + byteRead);// 流打印,查看当前buffer的position 和 limitArrays.asList(byteBuffers).stream().map(buffer -> "position = " + buffer.position() + ", limit=" + buffer.limit()).forEach(System.out::println);}// 将所有buffer反转-flipArrays.asList(byteBuffers).forEach(x -> x.flip());// 将数据读出显示到客户端long byteWrite = 0;while (byteWrite < msgLength) {long length = socketChannel.write(byteBuffers);byteWrite += length;}// 将所有buffer 清空Arrays.asList(byteBuffers).forEach(x -> x.clear());System.out.println("byteRead = " + byteRead + ", byteWrite = " + byteWrite);}
}

 【3.2】channel 通道的代码示例

1)写出到文件

/*** @Description nio文件通道读文件* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOFileChannel013 {public static void main(String[] args) throws Exception {String text = "hello 世界";// 创建一个输出流try (FileOutputStream fos = new FileOutputStream(new File("D://temp/netty/nio_file_channel01.txt"))) {// 获取对应 FileChannel,FileChannel 是抽象类,具体类型是FileChannelImplFileChannel fileChannel = fos.getChannel();// 创建一个缓冲区ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 把文本写入 ByteBuffer, 并把 ByteBuffer 反转-flipbyteBuffer.put(text.getBytes(StandardCharsets.UTF_8));byteBuffer.flip();// 把 byteBuffer 写入到 FileChannelfileChannel.write(byteBuffer);} catch (Exception e) {System.out.println("异常");throw e;}}
}

2)从文件读入数据

/*** @Description FileChannel读文件* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOFileChannel014 {public static void main(String[] args) throws Exception {// 创建一个输入流try (FileInputStream fis = new FileInputStream(new File("D://temp/netty/nio_file_channel01.txt"))) {// 获取对应 FileChannel,FileChannel 是抽象类,具体类型是FileChannelImplFileChannel fileChannel = fis.getChannel();// 创建一个缓冲区ByteBuffer byteBuffer = ByteBuffer.allocate(1024);// 从文件读入内容到缓冲区fileChannel.read(byteBuffer);// 显示System.out.println(new String(byteBuffer.array(), StandardCharsets.UTF_8));} catch (Exception e) {System.out.println("异常");throw e;}}
}

3)读写文件(拷贝)

/*** @Description FileChannel读写文件* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOFileChannel015 {public static void main(String[] args) throws Exception {// 创建一个输入流try (FileInputStream fis = new FileInputStream("D://temp/netty/nio_file_channel01.txt");FileOutputStream fos = new FileOutputStream("D://temp/netty/nio_file_channel02.txt")) {// 获取对应 FileChannelFileChannel fileChannel01 = fis.getChannel();FileChannel fileChannel02 = fos.getChannel();// 创建一个缓冲区ByteBuffer byteBuffer = ByteBuffer.allocate(4);// 循环读取while(fileChannel01.read(byteBuffer) != -1) {// 反转byteBuffer.flip();// 将buffer 中的数据写入到 02.txtfileChannel02.write(byteBuffer);// 清空 bufferbyteBuffer.clear();}// 显示System.out.println("拷贝成功.");} catch (Exception e) {System.out.println("异常");throw e;}}
}

补充: Buffer.flip() 切换读写模式(如写模式切换为读模式)

4)用  transferFrom 拷贝文件

/*** @Description 采用 transferFrom 拷贝图片* @author xiao tang* @version 1.0.0* @createTime 2022年08月16日*/
public class NIOFileChannel016 {public static void main(String[] args) throws Exception {// 创建一个输入流try (FileInputStream fis = new FileInputStream("D://temp/netty/image/1.jpg");FileOutputStream fos = new FileOutputStream("D://temp/netty/image/2.jpg")) {// 获取对应 FileChannelFileChannel srcChannel = fis.getChannel();FileChannel destChannel = fos.getChannel();// 创建一个缓冲区ByteBuffer byteBuffer = ByteBuffer.allocate(4);// 使用 transferFrom 完成拷贝destChannel.transferFrom(srcChannel, 0, srcChannel.size());// 显示System.out.println("拷贝成功.");} catch (Exception e) {System.out.println("异常");throw e;}}
}

【3.3】选择器(Selector)

refer2

3.NIO选择器(基于NIO的服务器与客户端通讯)_PacosonSWJTU的博客-CSDN博客

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

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

相关文章

k8s往secret里导入证书_K8S之Secret

简介secret顾名思义&#xff0c;用于存储一些敏感的需要加密的数据。这些数据可能是要保存在pod的定义文件或者docker的镜像中。把这些数据通过加密的方式存放到secrets对象中&#xff0c;可以降低信息泄露的风险。在secret中存储的数据都需要通过base64进行转换加密后存放。创…

Oracle入门(十四G)之PL / SQL中检索数据

一、PL / SQL中检索数据 &#xff08;1&#xff09;PL / SQL中的SQL语句可以在PL / SQL中使用以下几种SQL语句&#xff1a;•SELECT从数据库检索数据。•DML语句&#xff0c;例如INSERT&#xff0c;UPDATE和DELETE&#xff0c;以更改数据库中的行。•事务控制语句&#xff0c;例…

.NET Core 1.0 CentOS7 尝试

昨天宣布 ASP.NET Core RC2&#xff0c;据说差不多稳定了&#xff0c;以后不会有大改了。 参考:https://blogs.msdn.microsoft.com/webdev/2016/05/16/announcing-asp-net-core-rc2/ 一、环境装备 等待很久了&#xff0c;高兴之余昨晚安装一个CentOS系统&#xff0c;版本如下&a…

6.netty线程模型-Reactor

【README】 1..本文部分内容翻译自&#xff1a; [Netty] Nettys thread model and simple usage 2.netty模型是以 Reactor模式为基础的&#xff0c;具体的&#xff0c;netty使用的是 主从Reactor多线程模型&#xff1b; 3.先介绍了 Reactor线程模型&#xff1b;后介绍了 Ne…

python mac读取 文件属性_从Python获取和设置mac文件和文件夹查找器标签

macfile模块是^{}模块的一部分&#xff0c;在"2006-11-20 0.2.0"中被重命名为mactypes使用此模块&#xff0c;以下两个函数可用于获取和设置appscript 1.0版的查找器标签&#xff1a;from appscript import appfrom mactypes import File as MacFile# Note these lab…

Oracle入门(十四.1)之PL / SQL简介

一、PL / SQL描述程序语言扩展到SQL&#xff1a; •允许将基本程序逻辑和控制流与SQL语句组合在一起。 •是Oracle专有编程语言。- 它只能用于Oracle数据库或工具。二、程序语言扩展到SQL•是一种程序语言。 - 当遵循一系列指令时会产生结果。 •是3GL&#xff08;第三代编程语…

构建高性能.NET应用之配置高可用IIS服务器-第三篇 IIS中三个核心组件的讲解(上)

今天的文章的比较的容易&#xff0c;主要讲述IIS中三个比较重要的组件&#xff1a;协议监听者(Protocol Listeners)&#xff0c;WWW服务(World Wide Web Publishing Service)和WAS(Windows Process Activation Service)&#xff0c;理解这三个组件的功能&#xff0c;是理解IIS…

7.netty服务器中提交任务到NioEventLoop(Nio事件循环执行线程)

【README】 1.本文总结自 B站 《尚硅谷-netty》; 2.NioEventLoop实际上是一个提交到线程池的Runnable任务&#xff0c;在while无限循环中运行 taskQueue中的任务&#xff08;串行&#xff09;&#xff1b; 【1】提交任务到NioEventLoop 1&#xff09;NioEventLoop&#xff1…

Oracle入门(十四.2)之PL / SQL的好处

一、PL / SQL的好处在Oracle数据库中使用PL / SQL编程语言有很多好处。 1.将过程构造与SQL集成 2.模块化程序开发 3.改进的性能 4.与Oracle工具集成 5.便携性6.异常处理二、优点 优点1&#xff1a;使用SQL集成程序化结构PL / SQL的首要优势是程序结构与SQL的集成。 SQL是一种非…

炒菜机器人的弊端_机器人炒菜真不是你想的那样!

7月8日下午&#xff0c;爱餐全产业链模式发布会在张家口进行&#xff0c;会上&#xff0c;张家口文旅投集团与上海爱餐机器人有限公司签订了3000台智能机器人设备合作协议&#xff0c;这些机器人可是身手不凡&#xff0c;清一色的都是会厨艺的炒菜机器人&#xff0c;未来他们还…

构建高性能.NET应用之配置高可用IIS服务器-第四篇 IIS常见问题之:工作进程回收机制(上)

通过三篇文章的普及&#xff0c;相信大家对IIS应该有了一个基本的了解。那么从本篇文章开始&#xff0c;我们就开始进入IIS一些比较实际的话题&#xff1a;如何配置IIS&#xff0c;使得其性能尽可能的高。 我们在本篇中主要讲述的就是“工作进程回收机制”&#xff0c;下面我们…

8.基于netty实现群聊,心跳检测

【README】 1.本文总结自B站《netty-尚硅谷》&#xff0c;很不错&#xff1b; 2.本文po出了 Unpooled创建缓冲区的 代码示例&#xff1b; 3.本文示例代码基于netty实现以下功能&#xff1a; 群聊客户端及服务器&#xff1b;心跳检测&#xff1b;【1】Unpooled创建缓冲区 U…

Oracle入门(十四.3)之创建PL / SQL块

一、PL / SQL块结构 一个PL / SQL块由三部分组成。PL / SQL块结构部分二、PL / SQL编译器用高级编程语言&#xff08;C&#xff0c;Java&#xff0c;PL / SQL等&#xff09;编写的每个程序都必须经过检查并转换为二进制代码&#xff08;1和0&#xff09;&#xff0c;然后才能执…

[.NET Core].NET Core R2安装及示例教程

前言 前几天.NET Core发布了.NET Core 1.0.1 R2 预览版&#xff0c;之前想着有时间尝试下.NET Core。由于各种原因&#xff0c;就没有初试。刚好&#xff0c;前几天看到.NET Core发布新版本了&#xff0c;决定要去一探究竟。于是乎&#xff0c;就立马去官网查找相关的信息&…

Oracle入门(十四.4)之在PL / SQL中使用变量

一、变量的使用 &#xff08;1&#xff09;使用变量的原因•临时存储数据 •储存值的操作 •可重用性&#xff08;2&#xff09;处理PL / SQL中的变量变量是&#xff1a; •在声明部分声明并初始化 •在可执行部分中使用并分配新值 变量可以是&#xff1a; •作为参数传递给PL …

dismiss的词组_法律英语常用词必记:Dismiss

Dismiss英[dɪsmɪs] 美[dɪsmɪs]【英文释义】v.to refuse to give further hearing to a case in court. If a judge dismisses a court case, they officially decide that the case should not continue【中文释义】v. (1)解雇&#xff1b;免职&#xff1b;开除(2)驳回(起诉…

构建高性能.NET应用之配高可用IIS服务器-第五篇 IIS常见问题之:工作进程回收机制(中)

我们在本篇中接着讲述“工作进程回收机制”。 本篇文章的议题如下&#xff1a; 工作进程回收机制讲解 基于时间的回收机制 基于请求数的回收机制 基于内存使用的回收机制 基于活动状态的回收机制 基于请求数的回收机制 这种基于请求数量回收的机制非常的好理解&#xff1a;当我…

10.netty客户端与服务器使用protobuf传输报文

【README】 本文总结自B站《尚硅谷-netty》&#xff0c;很不错&#xff1b; 内容如下&#xff1a; netty的编码器与解码器&#xff1b;netty客户端与服务器通过 protobuf 传输报文的开发方式&#xff1b;文末po出了所有代码&#xff1b;【1】netty的编码器与解码器 codec 1&…

Oracle入门(十四.5)之识别数据类型

一、PL / SQL数据类型 数据类型指定存储格式&#xff0c;约束和有效的值范围。 PL / SQL支持五类数据类型&#xff1a;二、标量数据类型&#xff08;Scalar&#xff09; &#xff08;1&#xff09;标量数据类型•保持一个值 •没有内部组件 •可以分为四类&#xff1a; - 性格…

TFS2015的CI集成

这篇应该是这个系列的最后一篇了 配置生成代理 配置dotnet cli环境 这步&#xff0c;需要在生成代理的机器上配置cli环境&#xff0c;与本地配置方法一致&#xff0c;可以自行Google 下载及参考地址&#xff1a; https://www.microsoft.com/net/core#windows 配置环境变量 在生…