NIO使用NIO传输图片

相比于传统的阻塞IO,NIO提供了一种更灵活和高效的 I/O 操作方式,NIO 提供的非阻塞式的 I/O 操作,使得一个单独的线程可以管理多个通道(Channel),从而更好地处理并发连接和大量的 I/O 操作。

1. 核心组件

NIO 的核心组件包括通道(Channel)、缓冲区(Buffer)和选择器(Selector)。

(1)通道(Channel)

  • 通道是 NIO 中用于读取和写入数据的抽象。它可以连接到文件、网络套接字等输入/输出设备。
  • Java NIO 提供了不同类型的通道,包括文件通道(FileChannel)、套接字通道(SocketChannel 和 ServerSocketChannel)、Datagram 通道(DatagramChannel)等。
  • 通道与传统的流(Stream)不同,通道可以双向传输数据,而流是单向的。

(2) 缓冲区(Buffer)

  • 缓冲区是用于暂存数据的对象,它是 NIO 操作数据的基本单位。所有的数据读取和写入都是通过缓冲区进行的。
  • 缓冲区具有固定的容量,可以通过 put() 和 get() 等方法向其中写入或读取数据。
  • Java NIO 提供了不同类型的缓冲区,包括 ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer 和 DoubleBuffer,每种缓冲区用于不同类型的数据。

(3) 选择器(Selector)

  • 选择器是 NIO 中用于多路复用的关键组件。它可以监听多个通道的事件,当一个或多个通道准备好进行读取或写入时,选择器将这些通道放入就绪集合(SelectionKey)中。
  • 选择器使得一个单独的线程可以有效地管理多个通道,提高了系统的性能和资源利用率。
  • 选择器是事件驱动模型的核心,它使得 NIO 可以实现非阻塞式的 I/O 操作。  

2. 与传统 IO 的区别 

(1)阻塞与非阻塞:

  • 传统的 IO 是阻塞式的,当一个 IO 操作开始后,线程会被阻塞,直到该操作完成。这意味着如果线程在进行 IO 操作时没有其他任务可执行,系统资源会被浪费。
  • NIO 使用非阻塞式 IO,意味着线程在进行 IO 操作时可以同时执行其他任务,从而提高了系统资源的利用率。

(2)通道与流: 

  • 传统的 IO 使用字节流和字符流进行数据传输,而 NIO 使用通道(Channel)和缓冲区(Buffer)。
  • 通道可以双向传输数据,而流是单向的。通道提供了更多的控制和灵活性。

(3)多路复用:

  • NIO 引入了选择器(Selector)的概念,可以同时监听多个通道的事件,当一个或多个通道准备好进行读取或写入时,选择器会通知程序。
  • 这使得一个线程可以有效地管理多个通道,处理并发连接和大量的 IO 操作,提高了系统的性能和可扩展性。

3. NIO 的优势

  • 高并发处理:NIO 可以通过较少的线程处理更多的连接,提高了系统的性能和资源利用率。

  • 灵活的数据操作:NIO 提供了更灵活和高效的数据操作方式,可以更好地处理大量的 IO 操作。

 使用NIO传输图片

客户端代码

import java.io.FileInputStream; // 导入文件输入流类,用于读取文件内容  
import java.io.IOException;     // 导入I/O异常类,用于处理可能的文件读取和网络通信异常  
import java.net.InetSocketAddress; // 导入网络地址类,用于指定服务器的IP地址和端口号  
import java.nio.ByteBuffer;       // 导入ByteBuffer类,用于在通道中传输数据  
import java.nio.channels.FileChannel; // 导入文件通道类,用于从文件中读取数据  
import java.nio.channels.SocketChannel; // 导入Socket通道类,用于网络通信  public class ImageClient {  // 主函数,程序的入口点  public static void main(String[] args) throws IOException {  // 创建一个SocketChannel实例,并准备连接到服务器  // SocketChannel是NIO(非阻塞I/O)中用于网络通信的通道  SocketChannel socketChannel = SocketChannel.open();  // 连接到指定的服务器地址和端口,这里连接到本地机器(localhost)的8080端口  // InetSocketAddress是一个网络地址的封装,包含了IP地址和端口号  socketChannel.connect(new InetSocketAddress("localhost", 8080));  // 读取图片文件到ByteBuffer中  // 使用FileInputStream来读取文件,然后通过getChannel()方法获取到文件的通道(FileChannel)  FileInputStream fis = new FileInputStream("src/main/java/images/userAvatar.jpg");  FileChannel fileChannel = fis.getChannel();  // 分配一个ByteBuffer,大小为1024字节,用于临时存储从文件中读取的数据  // ByteBuffer是一个字节容器,可以通过它读取或写入数据到通道  ByteBuffer buffer = ByteBuffer.allocate(1024);  // 循环读取文件内容,直到文件结束  while (fileChannel.read(buffer) > 0) {  // 调用flip()方法,将ByteBuffer从写模式切换到读模式  // 在调用write()方法之前,必须先调用flip()方法  buffer.flip();  // 将ByteBuffer中的数据写入到SocketChannel中,发送到服务器  socketChannel.write(buffer);  // 调用clear()方法,清空ByteBuffer,准备下一次读取  // clear()方法会将position设置为0,limit设置为capacity,为下一次读取或写入做准备  buffer.clear();  }  // 关闭FileInputStream和SocketChannel,释放资源  fis.close();  socketChannel.close();  }  
}

服务端代码

import java.io.FileOutputStream; // 导入文件输出流类,用于将接收到的数据写入文件  
import java.io.IOException;     // 导入I/O异常类,用于处理可能的文件写入和网络通信异常  
import java.net.InetSocketAddress; // 导入网络地址类,用于指定服务器的IP地址和端口号  
import java.nio.ByteBuffer;       // 导入ByteBuffer类,用于在通道中传输数据  
import java.nio.channels.FileChannel; // 导入文件通道类,用于向文件中写入数据  
import java.nio.channels.ServerSocketChannel; // 导入服务器套接字通道类,用于监听和接受连接  
import java.nio.channels.SocketChannel; // 导入Socket通道类,用于网络通信  public class ImageServer {  public static void main(String[] args) throws IOException {  // 创建一个ServerSocketChannel实例,用于监听连接请求  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  // 将ServerSocketChannel绑定到特定的端口,这里使用8080端口  serverSocketChannel.bind(new InetSocketAddress(8080));  // 配置ServerSocketChannel为非阻塞模式,这允许服务器同时处理多个连接  serverSocketChannel.configureBlocking(false);  // 无限循环,持续监听新的连接请求  while (true) {  // 尝试接受一个新的连接请求  // 因为设置了非阻塞模式,如果当前没有连接请求,accept()会立即返回null  SocketChannel socketChannel = serverSocketChannel.accept();  // 如果成功接受了一个连接请求,则进行以下操作  if (socketChannel != null) {  // 分配一个ByteBuffer,大小为1024字节,用于临时存储从SocketChannel中读取的数据  ByteBuffer buffer = ByteBuffer.allocate(1024);  // 创建一个FileOutputStream,用于将接收到的数据写入到文件中  // 这里假设文件名为"D:\\ltsServer\\text.jpg"  FileOutputStream fos = new FileOutputStream("D:\\ltsServer\\text.jpg");  // 获取FileOutputStream对应的FileChannel  FileChannel fileChannel = fos.getChannel();  // 读取SocketChannel中的数据,并写入到文件中,直到SocketChannel中没有更多数据可读  int bytesRead;  while ((bytesRead = socketChannel.read(buffer)) > 0) {  // 打印从SocketChannel中读取的字节数  System.out.println(bytesRead);  // 调用flip()方法,将ByteBuffer从读模式切换到写模式  buffer.flip();  // 将ByteBuffer中的数据写入到FileChannel中,即将数据写入到文件中  fileChannel.write(buffer);  // 调用clear()方法,清空ByteBuffer,准备下一次读取  buffer.clear();  }  // 关闭FileOutputStream和SocketChannel,释放资源  fos.close();  socketChannel.close();  }  // 在实际应用中,对于非阻塞模式,通常需要使用选择器(Selector)来同时处理多个通道  // 这里的代码只是简单示例,没有使用选择器  }  }  
}

这里再补充一段在服务端使用 选择器(Selector)监听通道的代码

private static void start() throws IOException {// 创建ServerSocketChannel,并设置为非阻塞模式ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.socket().bind(new InetSocketAddress(PORT));// 创建Selector,用于监听通道事件Selector selector = Selector.open();// 将ServerSocketChannel注册到Selector上,监听连接事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 不断循环,处理通道事件while (true) {selector.select(); // 阻塞,等待通道事件发生for (SelectionKey key : selector.selectedKeys()) {if (key.isAcceptable()) { // 客户端发起连接事件acceptClient(selector, serverSocketChannel);} else if (key.isReadable()) { // 客户端发送数据事件readMessageFromClient(key);}}selector.selectedKeys().clear(); // 清空已处理的事件集合}}

 

 

 

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

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

相关文章

高级个人主页

高级个人主页 效果图部分代码领取源码下期更新预报 效果图 部分代码 <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" name"viewport" content"widthdevice-width, initial-scale1, maximum-scale1, use…

ESP32重要库示例详解(四):获取NTP时间之time库

在物联网项目中&#xff0c;时间同步和管理是至关重要的功能之一&#xff0c;特别是在需要执行定时任务或记录事件时间戳的场景下。Arduino平台通过其内置的<time.h>库提供了强大的时间处理能力&#xff0c;使得开发者能够方便地与网络时间协议&#xff08;NTP&#xff0…

PDF文件转换为CAD的方法

有时候我们收到一个PDF格式的设计图纸&#xff0c;但还需要进行编辑或修改时&#xff0c;就必须先将PDF文件转换回CAD格式。分享两个将PDF转换回CAD的方法&#xff0c;一个用到在线网站&#xff0c;一个用到PC软件&#xff0c;大家根据情况选择就可以了。 ☞在线CAD网站转换 …

css超出部分省略(单行、多行,多种方法实现)

HTML <p class"text">这是一行测试数据,这是一行测试数据,这是二行测试数据,这是一行测试数据,这是三行测试数据,这是四行测试数据</p>1.单行 .text{width: 200px;border: 1px solid #000000;white-space: nowrap; /* 控制元素不换行 */overflow: hi…

单链表与双链表

实现一个单链表,链表初始为空,支持三种操作: 向链表头插入一个数;删除第 k 个插入的数后面的一个数;在第 𝑘 个插入的数后插入一个数。现在要对该链表进行 M 次操作,进行完所有操作后,从头到尾输出整个链表。 注意:题目中第 k 个插入的数并不是指当前链表的第 k 个数…

fuel无人机自主探索代码解读1——map_ros.cpp【地图ros接口】

一、概述 map_ros.cpp订阅深度图/雷达点云、世界坐标下传感器pose&#xff0c;每0.05s启动esdf地图更新&#xff0c;每0.05s进行全局地图和局部地图可视化。主要功能为&#xff1a;接受传感器数据、调用sdf_map.cpp文件内部膨胀地图及esdf地图更新接口、地图可视化等。涉及传感…

Python笔记:比较运算符

比较运算符也叫关系运算符。 Python的比较运算符及用法&#xff1a; 比较运算符描述写法等于x y!不等于x ! y>大于x > y<小于x < y>大于等于x > y<小于等于x < y 1、比较运算符会返回布尔类型的结果。&#xff08;True / False&#xff09; num1 …

数电发票、全电发票为什么不是连号的?Node.js发票查验接口集成

全电发票号码为全国统一赋码&#xff0c;采用的是20位发票号码&#xff0c;其实是连续的。只是在实际开票过程中&#xff0c;不止一位纳税人在开&#xff0c;有其他纳税人也在开&#xff0c;所以会出现对某一个纳税人来说号码没有连续的情况。那么&#xff0c;全电发票如何进行…

Django图书馆综合项目-学习(2)

接下来我们来实现一下图书管理系统的一些相关功能 1.在书籍的book_index.html中有一个"查看所有书毂"的超链接按钮&#xff0c;点击进入书籍列表book_list.html页面. 这边我们使用之前创建的命名空间去创建超连接 这里的book 是在根路由创建的namespacelist是在bo…

6. RedHat认证-基于公钥的认证方式

6. RedHat认证-基于公钥的认证方式 主要学习客户端访问服务端的时候&#xff0c;免密登录这一方式 注意: 免密登录只是基于公钥认证的一个附带属性(基于公钥认证的方式更加安全&#xff0c;防止黑客暴力破解) 第一步&#xff1a;将客户端生成的秘钥传送到服务器 在客户端通过…

2024中国(厦门)国际医用消毒及感控设备展览会

2024中国&#xff08;厦门&#xff09;国际医用消毒及感控设备展览会 2024 China (Xiamen) International Medical Disinfection And Infection Control Exhibition 致力于打造医用消毒及感控设备产业采购一站式平台 时 间&#xff1a;2024年11月1-3日 November 1-3, 2024 …

一文扫盲(13):电商管理系统的功能模块和设计要点

电商管理系统是一种用于管理和运营电子商务平台的软件系统。它提供了一系列功能模块&#xff0c;帮助企业进行商品管理、订单管理、会员管理、营销推广、数据分析等工作。本文将从以下四个方面介绍电商管理系统。 一、什么是电商管理系统 电商管理系统是一种集成了各种功能模块…

免费的集成组件有哪些?

集成组件是指将多个软件或系统进行整合&#xff0c;以实现更高效、更可靠的数据处理和管理。在数据管理和分析领域&#xff0c;集成组件是不可或缺的工具之一。 在当今高度信息化的时代&#xff0c;集成组件在各行各业的应用中扮演着举足轻重的角色。集成组件能够将不同来源的…

更正:vue3升级nuxt3,server怎么修改

先给结论&#xff1a;放在nuxt.config.ts的vite中 在Nuxt配置中&#xff0c;nitro和vite的proxy配置虽然都可以用来处理代理&#xff0c;但它们的用途和作用范围有所不同。以下是它们的主要区别&#xff1a; nitro.devServer.proxy nitro 是 Nuxt 3 的服务器引擎&#xff0c…

【halcon踩坑】由于引用dll不一致导致的大坑。

背景 由于引用dll不一致导致的大坑,差点没跳出来。我们知道,halcon 有两个dll: halcondotnet和halcondotnetxl。 平时用的都是halcondotnet,halcondotnetxl时为了应付大图。 比如线扫相机扫出的大图。 踩坑 我的主项目中用到的halcondotnet,子项目中使用的halcondotne…

企业安全必备利器:专业级加密软件介绍

随着信息技术的迅猛发展&#xff0c;数据安全问题日益凸显&#xff0c;专业级加密软件应运而生&#xff0c;成为保护数据安全的重要工具。本文将对专业级加密软件进行概述&#xff0c;分析其特点、应用场景及分享。 一、专业级加密软件概述 专业级加密软件是指那些采用高级加密…

LLaMA-Factory环境安装-重点总结

问题&#xff1a;在使用官网介绍的博客&#xff0c;进行安装&#xff0c;比较顺利。只不过&#xff0c;在需要推理加速时&#xff0c;UI界面上&#xff0c;给出的选项所支持的FlashAttention-2和Unsloth&#xff0c;不好实现。在进行一系列的调整&#xff0c;总结如下&#xff…

三分钟了解计算机网络核心概念-数据链路层和物理层

计算机网络数据链路层和物理层 节点&#xff1a;一般指链路层协议中的设备。 链路&#xff1a;一般把沿着通信路径连接相邻节点的通信信道称为链路。 MAC 协议&#xff1a;媒体访问控制协议&#xff0c;它规定了帧在链路上传输的规则。 奇偶校验位&#xff1a;一种差错检测方…

uniapp怎么使用jsx

安装vitejs/plugin-vue-jsx npm install vitejs/plugin-vue-jsx -Dvite.config.js配置 import { defineConfig } from "vite"; import uni from "dcloudio/vite-plugin-uni"; import vueJsx from vitejs/plugin-vue-jsxexport default defineConfig({plu…

upload-labs靶场通关详解(1-15)

1.pass-01 查看源代码 是js&#xff0c;属于前端校验 可以通过禁用js来上传文件 2.pass-02 根据提示是MIME绕过 MIME&#xff1a;是设定某种扩展名的文件 用一种应用程序来打开的方式类型&#xff0c;当该扩展名文件被访问的时候&#xff0c;浏览器会自动使用指定应用程序来…