Java详解I/O
前言:
小弟能力不足,认知有限,难免考虑不全面,希望大佬能给出更好的建议,指出存在的问题和不足,在此跪谢。
IO发展史
Java中对于I/O能力的支持主要分为三个比较关键的阶段:
BIO
第一个阶段是起步阶段JDK1.0 ~ JDK1.3,这个阶段JDK是处于BIO阶段的,也就是同步阻塞模式,该阶段的类库还非常的初级,对系统层面的一些网络编程的API都没有进行实现,因此这个阶段的很多大型应用服务器都采用C或者C++语言来进行开发的,因为C或者C++可以直接调用操作系统提供的非阻塞I/O能力;
NIO
第二个阶段从JDK1.4开始的,从JDK1.4开始,Java新增了java.nio的包,正式支持的NIO,提供了许多非阻塞I/O开发的API和类库;
AIO
第三个阶段是从JDK1.7开始的,这一次是对原来的NIO类库进行了升级,官方称为NIO 2.0,该版本不但强化了原来的基于I/O多路复用模型的NIO模式,同时新增了异步的AIO功能,所以也有很多人称之为AIO。
各个IO介绍
BIO
在Java中,BIO(Blocking I/O)指的是阻塞式I/O,是一种基本的I/O模型。它的实现原理相对简单,但在高并发场景下性能较差。下面我将详细介绍BIO的实现原理。
-
阻塞式I/O:
在BIO中,当一个线程在进行I/O操作时,如果数据没有准备好,该线程会被阻塞,直到数据准备好并被读取或写入。这意味着一个线程只能处理一个连接,如果有大量连接同时到来,就需要大量线程来处理,这会导致资源消耗过大。 -
实现原理:
- 服务端:服务端通过ServerSocket监听客户端的连接请求。当有连接请求到来时,服务端会创建一个新的线程来处理该连接。
- 客户端:客户端通过Socket向服务端发起连接请求。一旦连接建立,客户端和服务端之间可以进行数据的读取和写入。
-
服务端示例代码:
思路:在服务端的代码中,我们创建了一个固定大小的线程池,用于处理客户端的连接请求。每当有客户端连接时,就会将连接交给线程池中的一个线程来处理,这样可以提高并发处理能力。同时,我们定义了一个
ClientHandler类来处理客户端的请求,这样可以更好地组织代码逻辑。这样的设计可以更好地满足企业级生产环境的要求,提高了系统的并发处理能力和稳定性。当然你还可以加入日志打印,更好的排查问题,但是因为这种已经过时,所以只是简单示例。
import java.io.*; import java.net.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class Server {public static void main(String[] args) {ServerSocket serverSocket = null;ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个固定大小的线程池try {serverSocket = new ServerSocket(8080);System.out.println("Server started. Waiting for client...");while (true) {// 等待客户端连接Socket clientSocket = serverSocket.accept();System.out.println("Client connected: " + clientSocket.getRemoteSocketAddress());// 使用线程池处理客户端请求executor.execute(new ClientHandler(clientSocket));}} catch (IOException e) {e.printStackTrace();} finally {try {if (serverSocket != null) {serverSocket.close();}executor.shutdown(); // 关闭线程池} catch (IOException e) {e.printStackTrace();}}}private static class ClientHandler implements Runnable {private Socket clientSocket;public ClientHandler(Socket clientSocket) {this.clientSocket = clientSocket;}@Overridepublic void run() {try {// 获取输入流BufferedReader input = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));// 获取输出流PrintWriter output = new PrintWriter(clientSocket.getOutputStream(), true);// 读取客户端发送的数据String clientMessage = input.readLine();System.out.println("Received from client: " + clientMessage);// 向客户端发送数据output.println("Hello, client!");// 关闭流和连接input.close();output.close();clientSocket.close();} catch (IOException e) {e.printStackTrace();}}} } -
客户端实例代码实现:
import java.io.*; import java.net.*;public class Client {public static void main(String[] args) {Socket socket = null;try {socket = new Socket("localhost", 8080);System.out.println("Connected to server.");// 获取输入流BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 获取输出流PrintWriter output = new PrintWriter(socket.getOutputStream(), true);// 向服务端发送数据output.println("Hello, server!");// 读取服务端发送的数据String serverMessage = input.readLine();System.out.println("Received from server: " + serverMessage);// 关闭流和连接input.close();output.close();socket.close();} catch (IOException e) {e.printStackTrace();} finally {try {if (socket != null) {socket.close();}} catch (IOException e) {e.printStackTrace();}}} } -
适用场景:
BIO适用于连接数较少且吞吐量要求不高的场景,例如传统的Socket通信应用。 -
局限性:
由于BIO的阻塞特性,它在高并发场景下表现较差,因为大量线程会因为I/O阻塞而处于等待状态,导致资源浪费。
总的来说,BIO是一种简单直观的I/O模型,但在高并发场景下存在性能瓶颈。随着业务的发展,通常会选择更高效的NIO(Non-blocking I/O)或者AIO(Asynchronous I/O)来替代BIO。
NIO
在Java中,NIO(New I/O)是一种非阻塞I/O模型,相比于传统的BIO(Blocking I/O),NIO具有更高的并发处理能力。下面我将详细介绍NIO的实现原理。
-
非阻塞I/O:
NIO的核心是非阻塞I/O,它允许一个线程处理多个连接,当一个连接上的I/O操作不可立即完成时,线程可以去处理其他连接,而不是被阻塞。 -
核心组件:
- 通道(Channel):用于读取和写入数据,可以是文件、套接字等。
- 缓冲区(Buffer):用于临时存储数据,读取数据到缓冲区或将缓冲区中的数据写入通道。
- 选择器(Selector):用于监听多个通道的事件,例如连接就绪、读就绪、写就绪等。
-
实现原理:
- 服务端:服务端通过ServerSocketChannel监听连接请求,一旦有连接到来,会将该连接注册到Selector上,并监听连接就绪事件。
- 客户端:客户端通过SocketChannel向服务端发起连接请求,连接建立后也会注册到Selector上。
-
NIO服务器端示例代码:
实现思路:在以下代码中,我们引入了日志打印服务,使用了Java自带的Logger类来记录日志。同时,我们使用了线程池来处理客户端的连接请求和数据读写操作,以提高并发处理能力。对于各种可能遇到的问题,比如连接超时、网络异常、数据读写异常等,我们在相应的位置进行了异常处理,并记录了相应的日志,以便于排查和解决问题。
这样的设计更加符合企业级生产规范,提高了系统的并发处理能力和稳定性,并且对各种异常情况进行了处理,使得系统更加健壮可靠。
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.*; import java.util.Iterator; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class NIOServer {private static final Logger logger = Logger.getLogger(NIOServer.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {Selector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);while (true) {selector.select();Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();keyIterator.remove();if (key.isAcceptable()) {executor.execute(() -> handleAccept(key, selector));} else if (key.isReadable()) {executor.execute(() -> handleRead(key));}}}} catch (IOException e) {logger.severe("Error in NIO server: " + e.getMessage());}}private static void handleAccept(SelectionKey key, Selector selector) {try {ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverSocketChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} catch (IOException e) {logger.severe("Error in handleAccept: " + e.getMessage());}}private static void handleRead(SelectionKey key) {try {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = clientChannel.read(buffer);if (bytesRead == -1) {clientChannel.close();key.cancel();} else if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from client: " + new String(data));// 可以在这里处理接收到的数据}} catch (IOException e) {logger.severe("Error in handleRead: " + e.getMessage());}} } -
NIO客户端的代码:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class NIOClient {private static final Logger logger = Logger.getLogger(NIOClient.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {SocketChannel socketChannel = SocketChannel.open();socketChannel.configureBlocking(false);socketChannel.connect(new InetSocketAddress("localhost", 8080));while (!socketChannel.finishConnect()) {// 等待连接完成}executor.execute(() -> {try {String message = "Hello, server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());socketChannel.write(buffer);buffer.clear();int bytesRead = socketChannel.read(buffer);if (bytesRead > 0) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from server: " + new String(data));// 可以在这里处理接收到的数据}} catch (IOException e) {logger.severe("Error in NIO client: " + e.getMessage());} finally {try {socketChannel.close();} catch (IOException e) {logger.severe("Error in closing socket channel: " + e.getMessage());}}});} catch (IOException e) {logger.severe("Error in NIO client: " + e.getMessage());}} } -
适用场景:
NIO适用于高并发的网络应用,例如Web服务器、聊天服务器等,能够更高效地处理大量连接。
总的来说,NIO通过Selector、Channel和Buffer的组合,实现了非阻塞I/O,提高了系统的并发处理能力。然而,NIO编程相对复杂,需要处理事件的就绪状态,因此在实际应用中通常会使用NIO框架或者基于NIO的高级框架,如Netty。
AIO
在Java中,AIO(Asynchronous I/O)是一种基于事件和回调机制的I/O模型,相比于传统的BIO(Blocking I/O)和NIO(Non-blocking I/O),AIO更加适用于处理大量并发连接。下面我将详细介绍AIO的实现原理。
-
异步I/O:
AIO的核心是异步I/O,它允许一个线程在等待数据就绪的同时继续做其他事情,当数据就绪后通过回调机制来处理数据。这种模型相比于NIO更加灵活,因为不需要手动检查就绪状态,而是通过事件通知来处理。 -
核心组件:
- 异步通道(AsynchronousChannel):用于进行异步I/O操作,包括文件和套接字等。
- 异步操作结果(AsynchronousResult):用于存储异步操作的结果,可以通过回调方式获取结果。
- 异步处理器(AsynchronousHandler):用于处理异步操作完成后的回调。
-
实现原理:
- 服务端:服务端通过AsynchronousServerSocketChannel监听连接请求,一旦有连接到来,会调用accept方法,并通过回调方式处理连接就绪事件。
- 客户端:客户端通过AsynchronousSocketChannel向服务端发起连接请求,连接建立后也可以通过回调方式处理后续的读写操作。
-
简单的AIO服务器示例代码:
实现思路:针对企业级生产环境中高可用的通信需求,以下是一个更完善的AIO服务端和客户端的Java代码。该代码考虑了各种可能遇到的问题,并给出了切实可行的异常解决方案。同时,引入了日志打印服务,使用了Java自带的Logger类来记录日志,并使用了线程池来处理客户端的连接请求和数据读写操作,以提高并发处理能力。import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Logger;public class AIOServer {private static final Logger logger = Logger.getLogger(AIOServer.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {AsynchronousServerSocketChannel serverSocketChannel = AsynchronousServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {@Overridepublic void completed(AsynchronousSocketChannel clientChannel, Void attachment) {serverSocketChannel.accept(null, this); // 接受下一个连接executor.execute(() -> handleRead(clientChannel));}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in accepting connection: " + exc.getMessage());}});// 阻止主线程退出Thread.currentThread().join();} catch (IOException | InterruptedException e) {logger.severe("Error in AIO server: " + e.getMessage());}}private static void handleRead(AsynchronousSocketChannel clientChannel) {ByteBuffer buffer = ByteBuffer.allocate(1024);clientChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {if (bytesRead == -1) {try {clientChannel.close();} catch (IOException e) {logger.severe("Error in closing client channel: " + e.getMessage());}return;}buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from client: " + new String(data));// 可以在这里处理接收到的数据buffer.clear();clientChannel.read(buffer, null, this); // 继续读取数据}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in reading from client: " + exc.getMessage());}});} } -
简单的AIO客户端示例代码:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Logger;public class AIOClient {private static final Logger logger = Logger.getLogger(AIOClient.class.getName());private static final ExecutorService executor = Executors.newFixedThreadPool(10);public static void main(String[] args) {try {AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 8080), null, new CompletionHandler<Void, Void>() {@Overridepublic void completed(Void result, Void attachment) {String message = "Hello, server!";ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());socketChannel.write(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesWritten, Void attachment) {if (buffer.hasRemaining()) {socketChannel.write(buffer, null, this); // 继续写入数据} else {buffer.clear();socketChannel.read(buffer, null, new CompletionHandler<Integer, Void>() {@Overridepublic void completed(Integer bytesRead, Void attachment) {buffer.flip();byte[] data = new byte[bytesRead];buffer.get(data);logger.info("Received from server: " + new String(data));// 可以在这里处理接收到的数据}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in reading from server: " + exc.getMessage());}});}}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in writing to server: " + exc.getMessage());}});}@Overridepublic void failed(Throwable exc, Void attachment) {logger.severe("Error in connecting to server: " + exc.getMessage());}});// 阻止主线程退出Thread.currentThread().join();} catch (IOException | InterruptedException e) {logger.severe("Error in AIO client: " + e.getMessage());}} } -
适用场景:
AIO适用于需要处理大量并发连接且对性能要求较高的场景,例如高性能的网络服务器、金融交易系统等。
总的来说,AIO通过异步I/O和事件回调机制,实现了高效的并发处理能力,相比于NIO更加灵活和高效。然而,AIO在Java中的实现相对较新,需要较高的技术要求,因此在实际应用中通常会使用成熟的AIO框架或者基于AIO的高级框架。
在Java中,有一些成熟的AIO框架或者基于AIO的高级框架,它们提供了更加便捷和高效的异步I/O编程方式。以下是一些常用的框架:
-
Netty:
Netty是一个基于NIO的高性能网络通信框架,但它也提供了对AIO的支持。Netty的异步事件驱动模型和高度可定制的架构使得它成为构建高性能、可扩展的网络应用程序的理想选择。Netty提供了丰富的功能,包括TCP/UDP传输、HTTP编解码、WebSocket支持等,广泛应用于网络服务器、分布式系统等领域。 -
Grizzly:
Grizzly是一个基于NIO的高性能网络框架,它提供了对AIO的支持,并且具有高度可扩展性和灵活性。Grizzly可以用于构建高性能的Web服务器、应用服务器等网络应用。 -
Apache MINA:
Apache MINA是一个基于NIO的网络应用框架,它提供了对AIO的支持,并且具有良好的扩展性和灵活性。MINA可以用于构建各种类型的网络应用,包括游戏服务器、即时通讯服务器等。
这些框架都提供了对AIO的封装和抽象,简化了异步I/O编程的复杂性,同时提供了丰富的功能和高性能的网络通信能力。在实际应用中,选择合适的框架取决于具体的需求和项目背景,但无论选择哪个框架,都可以极大地简化异步I/O编程的复杂性,提高开发效率和系统性能。
相关文章:
Java详解I/O
前言: 小弟能力不足,认知有限,难免考虑不全面,希望大佬能给出更好的建议,指出存在的问题和不足,在此跪谢。 IO发展史 Java中对于I/O能力的支持主要分为三个比较关键的阶段: BIO 第一个阶段…...
数据处理生产环境_spark获取df列当前日期的前一天日期
需求描述: 我现在有一个dataframe,名为dfin,样例数据如下 a1_id_lxha2_PHtime比亚迪_汉1232023-11-15 12:12:23比亚迪_汉1252023-11-15 13:14:51比亚迪_汉1232023-11-15 12:13:23比亚迪_汉1262023-11-16 14:12:34比亚迪_秦2312023-11-15 14:12:28比亚迪_秦2342023…...
第四代智能井盖传感器,实时守护井盖位安全
城市管理中井盖的安全问题始终是一个不容忽视的方面。传统的巡检方式不仅效率低下,无法实现实时监测,而且很难准确掌握井盖的异动状态。因此智能井盖传感器的应用具有重要意义。这种智能传感器可以帮助政府实时掌握井盖的状态,一旦发现异常情…...
【前端知识】Node——文件流的读写操作
四种基本流类型: 1.Writable: 可以向其写入数据的流 2.Readable: 可以从中读取数据的流 3.Duplex:同时为Readable 和 Writable 4.Transform: Duplex可以在写入和读取数据时修改或转换数据的流 一、Readable const fs require(fs);// 创建文件的Readable const rea…...
解决证书加密问题:OpenSSL与urllib3的兼容性与优化
在使用客户端证书进行加密通信时,用户可能会遇到一些问题。特别是当客户端证书被加密并需要密码保护时,OpenSSL会要求用户输入密码。这对于包含多个调用的大型会话来说并不方便,因为密码无法在连接的多个调用之间进行缓存和重复使用。用户希望…...
#gStore-weekly | gAnswer源码解析 调用NE模块流程
简介 gAnswer系统的主要思想,是将自然语言问题转化为语义查询图,再和RDF图做子图匹配。在转换成查询图的第一步就是确定查询图的节点,即节点提取(Node Extraction, NE)。 查询图中的节点由实体(entity&am…...
vscode 配置 lua
https://luabinaries.sourceforge.net/ 官网链接 主要分为4个步骤 下载压缩包,然后解压配置系统环境变量配置vscode的插件测试 这里你可以选择用户变量或者系统环境变量都行。 不推荐空格的原因是 再配置插件的时候含空格的路径 会出错,原因是空格会断…...
vscode设置代码模板
一键生成vue3模板代码 效果演示 输入vue3 显示快捷键 按回车键 一键生成自定义模板 实现方法 进入用户代码片段设置 选择片段语言 vue.json输入自定义的代码片段 prefix是触发的内容,按自己的喜好来就行; body是模板代码,写入自己需要的…...
用css实现原生form中radio单选框和input的hover已经focus的样式
一.问题描述:用css实现原生form中radio单选框和input的hover已经focus的样式 在实际的开发中,一般公司ui都会给效果图,比如单选按钮radio样式,input输入框hover的时候样式,以及focus的时候样式,等等&#…...
uniapp:录音权限检查,录音功能
1.可以使用:plus.navigator.checkPermission检查运行环境的权限 2.如果是"undetermined"表示程序未确定是否可使用此权限,此时调用对应的API时系统会弹出提示框让用户确认:plus.audio.getRecorder() <template><view cla…...
Rust开发——切片(slice)类型
1、什么是切片 在 Rust 中,切片(slice)是一种基本类型和序列类型。在 Rust 官方文档中,切片被定义为“对连续序列的动态大小视图”。 但在rust的Github 源码中切片被定义如下: 切片是对一块内存的视图,表…...
如何给shopify motion主题的产品系列添加description
一、Description是什么 Description是一种HTML标签类型,通过指定Description的内容,可以帮助搜索引擎以及用户更好的理解当前网页包含的主要了内容。 二、Description有什么作用 1、基本作用,对于网站和网页做一个简单的说明。 2、吸引点击&…...
力扣刷题-二叉树-二叉树最小深度
给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。(注意题意) 示例 1: 输入:root [3,9,20,null,null,15,7] 输出&#x…...
注解方式优雅的实现 Redisson 分布式锁
1前言 日常开发中,难免遇到一些并发的场景,为了保证接口执行的一致性,通常采用加锁的方式,因为服务是分布式部署模式,本地锁Reentrantlock和Synchnorized这些就先放到一边了,Redis的setnx锁存在无法抱保证…...
PHP/Laravel通过经纬度计算距离获取附近商家
实际开发中,常常需要获取用户附近的商家,思路是 获取用户位置(经纬度信息)在数据库中查询在距离范围内的商家 注: 本文章内计算距离所使用地球半径统一为 6378.138 km public function mpa_list($latitude,$longitude,$distance){// $latitude 34.306465;// $longitude 10…...
grafana面板介绍
grafana 快速使用 背景 随着公司业务的不断发展,紧接来的是业务种类的增加、服务器数量的增长、网络环境的越发复杂以及发布更加频繁,从而不可避免地带来了线上事故的增多,因此需要对服务器到应用的全方位监控,提前预警…...
实验三 循环结构程序设计(Python)
第1关:打印图形 zm=input("") #代码开始#代码结束def print_pattern(letter):if not letter.isalpha() or not letter.isupper():print("请输入大写字母")returnstart_char = Aend_char = letterfor i in range(ord(start_char), ord(end_char) + 1):spa…...
Flutter笔记:目录与文件存储以及在Flutter中的使用(上)
Flutter笔记 目录与文件存储以及在Flutter中的使用(上) 文件系统基础知识与路径操作 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:h…...
注意了!申请流量卡时地址一定不要填写学校,不好下卡哦!
当我们在网上购买流量卡时,都会要求让填写准确的收货地址,但是对于收货地址你填对了吗? 很多朋友在提交流量卡申请之后,往往会被运营商拒审,对于拒审的原因除了比较常见的信息填写有有误、涉及禁发地区、重复申…...
minio使用shell上传文件
minio使用shell上传文件 前言1. 编写调用脚本2.测试脚本上传3.候选脚本 前言 业务场景需要实现,服务器文件上传至存储服务。一种方式是安装minio的linux客户端,另一种方式是通过调用minio的api接口实现文件上传。后一种方式不需要依赖minio的客户端使用…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
