【RabbitMQ】工作模式

工作模式概述

简单模式

 简单模式中只存在一个生产者,只存在一个消费者。生产者生产消息,消费者消费消息。消息只能被消费一次,也称为点对点模式。

简单模式适合在消息只能被单个消费者处理的场景下存在。

工作队列模式(Work Queue)

工作队列模式中存在一个消费者,多个生产者。生产者生产消息,消息队列将生产的消息分发给不同的消费者,每个消费者接收到不同的消息后开始进行消费。简单来说,工作模式下,消息不会被重复消费,不同的消费者消费的是不同的消息。

工作模式适合在集群环境中做异步处理。

发布订阅模式

交换机(Exchange)

作用:生产者将消息发送到Broker中,会先经过交换机,由交换机将消息按照一定规则路由到一个或者多个消息队列中(在简单模式和工作队列模式下,由生产者直接将消息投递到队列中,这种情况在RabbitMQ中根本不会出现)。

RabbitMQ交换机有四种类型:fanout、direct、topic、headers。不同类型有着不同的路由策略。AMQP协议其实是有六种交换机类型的(除了上述四种,还有system和自定义),只不过RabbitMQ只使用了其四种而已。

1. Fanout:广播,交换机将从生产者中获取的消息交给与之绑定的全部队列(对应工作模式中的发布订阅模式)。

2. Direct:定向,交换机将从生产者中获取的消息交给与之绑定的符合RoutingKey的队列(对应工作模式中的路由模式)。具体RoutingKey是啥,后面会讲到。

3. Topic:通配符,交换机将从生产者中获取的消息交给与之绑定的符合RoutingKey的队列(对应工作模式中的通配符模式)。定向和通配符中的RoutingKey是略有不同的,具体到工作模式的路由模式和通配符模式就会明白。

4. headers:此类交换器并不依赖于RoutingKey的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。headers类型的交换器性能会很差,而且也不实用,基本看不到它的存在,了解即可。

Exchange只负责转化消息,并不负责存储消息。因此如果没有任何交换机和队列绑定,或者发送的消息没有符合路由规则的队列,消息就会丢失。

RoutingKey,路由键。生产者发送消息给Broker时,指定的一个字符串,用来告诉交换机应该如何处理这个消息。

BindingKey,绑定键。在声明交换机和队列之后,使用一个BindingKey将交换机和队列绑定起来。这样,当生产者将消息发送给Broker之后,交换机接收到消息就能根据消息中的RoutingKey和BindingKey进行对比,从而知道将消息路由到某个或者某几个队列中了。

本质上,BindingKey属于RoutingKey的一种。换句话说,两者的作用并没有什么差别。不同的是,路由键是生产者向Broker发送消息时使用的,绑定键则是交换机和队列绑定时进行绑定,然后再交换机给队列发送消息时使用。当生产者将一个绑定了RoutingKey的消息发送给交换机之后,交换机根据存在的BindingKey来将消息路由给队列。

发布订阅模式存在一个生产者,多个消费者。生产者生产消息,交换机将消息复制多份,每个队列都会接收到相同的消息,每个消费者接收到消息之后开始进行消费。简单来说,消费者发送的消息,所有与之关联的队列都会收到相同的消息。

发布订阅模式适合消费需要被多个消费者同时接收的场景,例如实时播报或者广播消息。

路由模式

 路由模式是发布订阅模式的变种,在发布订阅模式的基础上,增加了路由键。也就是说,消息到达交换机之后,不再是分发给所有关联的队列,而是根据绑定的路由规则来进行分发消息。

路由模式适合需要根据特定规则分发消息的场景。例如,系统日志打印,将不同级别的日志发送到不同的队列,最终输出到不同的文件。

通配符模式

通配符模式又是路由模式的变种,在路由模式的基础上,增加了通配符的功能,使消息分发更加灵活。

总的来说,发布订阅模式是消息到达交换机之后,交换机无条件的将所有消息转发给队列。路由模式是消息到达交换机之后,交换机根据RoutingKey的规则,将数据筛选之后分发给不同的队列。通配符模式也是消息到达交换机之后,交换机根据RoutingKey的规则,将数据筛选之后分发给不同的队列,只不过该RoutingKey不再是一个确定的路由键,而是类似于正则表达式的方式来定义路由键。

通配符模式适合需要灵活匹配和过滤消息的场景。

RPC模式

 RPC模式没有生产者和消费者,比较类似于咋们的RPC远程调用,大概就是通过两个队列实现了一个可回调的过程。

1. 客户端发送消息到一个指定队列,并在消息属性中设置replyTo字段,这个字段指定了一个回调队列,用于接收服务器的响应,并且还设置了correctionId字段,用来确定响应是否为服务器所期望的。

2. 服务器接收到请求之后,处理请求并将响应消息发送到replyTo指定的回调队列中。

3. 客户端在回调队列上等待响应消息,一旦收到响应,客户端会检查消息的correctionId属性,以确定它是所期望的响应。

发布确认模式(Publisher Confirms)

发布确认模式是RabbitMQ提供的一种确保消息可靠发送到RabbitMQ服务器的机制。在这种模式下,生产者可以等待RabbitMQ服务器确认收到消息的通知,以确保消息已经被服务器所接收并进行了处理。

1. 生产者将channel设置为confirm模式(通过调用channel.confirmSelect(),发布的每一条消息都会获得一个唯一的ID,生产者可以将这些序列号与消息关联起来,以便跟踪消息的状态)。

2. 当消息被RabbitMQ接收并处理后,服务器会异步地向生产者发送一个确认(ACK)给生产者(内容包含了唯一ID),表示消息已经送达。

通过发布确认模式,生产者可以确保消息被RabbitMQ服务器接收并处理,从而避免了消息丢失的问题。

发布确认模式适合对数据安全性要求较高的场景,比如金融交易、订单处理。

SDK工作模式代码案例

简单模式

生产者代码

// 简单模式public class Producer {public static void main(String[] args) throws IOException, TimeoutException {// TODO 创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost("43.138.108.125"); // IPconnectionFactory.setPort(5672); // PORTconnectionFactory.setUsername("admin"); // 用户名connectionFactory.setPassword("admin"); // 密码connectionFactory.setVirtualHost("mq-sdk-test"); // 虚拟主机// TODO 创建连接Connection connection = connectionFactory.newConnection();// TODO 获取信道Channel channel = connection.createChannel();// TODO 声明队列channel.queueDeclare(Constants.SIMPLE_QUEUE, true, false, false, null);// TODO 声明交换机,使用内置交换机,无需声明// TODO 发送消息String msg = "hello simple";channel.basicPublish("", Constants.SIMPLE_QUEUE, null, msg.getBytes());System.out.println("简单模式生产者发送消息!");// TODO 关闭资源channel.close();connection.close();}}

上述代码运行之后,在RabbitMQ的开源界面和IDEA终端上会有如下结果:

 

消费者代码

public class Consumer {public static void main(String[] args) throws IOException, TimeoutException {// TODO 创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost("43.138.108.125"); // IPconnectionFactory.setPort(5672); // PORTconnectionFactory.setUsername("admin"); // 用户名connectionFactory.setPassword("admin"); // 密码connectionFactory.setVirtualHost("mq-sdk-test"); // 虚拟主机// TODO 创建连接Connection connection = connectionFactory.newConnection();// TODO 获取信道Channel channel = connection.createChannel();// TODO 声明队列channel.queueDeclare(Constants.SIMPLE_QUEUE, true, false, false, null);// TODO 声明交换机,使用内置交换机,无需声明// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("成功接收到消息:" + new String(body));}};channel.basicConsume(Constants.SIMPLE_QUEUE, true, consumer);// TODO 关闭资源channel.close();connection.close();}}

 上述代码运行之后,队列中的消息被该消费者接收,控制台输出下述内容:

工作队列模式

由于在接下来的代码中,创建连接工厂,创建连接,开启信道,释放资源都要存在。因此为了简化开发,将这些步骤封装成方法,方便后续调用。

public class Common {private static Connection connection;private static Channel channel;// 获取信道public static Channel getChannel() throws IOException, TimeoutException {ConnectionFactory connectionFactory = new ConnectionFactory();connectionFactory.setHost("43.138.108.125"); // IPconnectionFactory.setPort(5672); // PORTconnectionFactory.setUsername("admin"); // 用户名connectionFactory.setPassword("admin"); // 密码connectionFactory.setVirtualHost("mq-sdk-test"); // 虚拟主机// TODO 创建连接connection = connectionFactory.newConnection();// TODO 获取信道channel = connection.createChannel();return channel;}// 释放资源public static void close() throws IOException, TimeoutException {channel.close();connection.close();}}

生产者代码

public class Producer {public static void main(String[] args) throws IOException, TimeoutException {// TODO 获取信道Channel channel = Common.getChannel();// TODO 声明交换机,使用内置交换机,因此无需声明// TODO 声明队列channel.queueDeclare(Constants.WORK_QUEUE, true, false, false, null);// TODO 发送消息/*** 工作队列的模式是一个队列,多个消费者。* 当存在多个消息时,不同的消费者会接收不同的消息,消息并不会重复消费* 因此为了检验这个模式,发送多条消息*/String msg = "hello work queue";for (int i = 0; i < 15; i++) {channel.basicPublish("", Constants.WORK_QUEUE, null, (msg + ":" + i).getBytes());}System.out.println("工作队列模式消息发送成功!");// TODO 释放资源Common.close();}}

 消费者代码

public class Consumer1 {public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {// TODO 获取信道Channel channel = Common.getChannel();// TODO 声明交换机,使用内置交换机,因此无需声明// TODO 声明队列channel.queueDeclare(Constants.WORK_QUEUE, true, false, false, null);// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者1接收到的消息:" + new String(body));}};channel.basicConsume(Constants.WORK_QUEUE, true, consumer);// TODO 释放资源
//        Common.close();}}
public class Consumer2 {public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {// TODO 获取信道Channel channel = Common.getChannel();// TODO 声明交换机,使用内置交换机,因此无需声明// TODO 声明队列channel.queueDeclare(Constants.WORK_QUEUE, true, false, false, null);// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者2接收到的消息:" + new String(body));}};channel.basicConsume(Constants.WORK_QUEUE, true, consumer);// TODO 释放资源
//        Common.close();}}

 在上述代码中,不要释放资源。将生产者的代码重新启动一次之后,就会发现如下内容。从消费者消费消息的输出情况来看,很容易得到工作模式最主要的内容:消费者消费的消息都是不同的消息,消息并不会被重复消费。

发布订阅模式

生产者代码

public class Producer {public static void main(String[] args) throws IOException, TimeoutException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT, true);// TODO 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1, true, false, false, null);channel.queueDeclare(Constants.FANOUT_QUEUE2, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.FANOUT_QUEUE1, Constants.FANOUT_EXCHANGE, "");channel.queueBind(Constants.FANOUT_QUEUE2, Constants.FANOUT_EXCHANGE, "");// TODO 发送消息String msg = "hello 发布订阅模式";channel.basicPublish(Constants.FANOUT_EXCHANGE, "", null, msg.getBytes());System.out.println("发布订阅模式发送消息成功!");// TODO 释放资源Common.close();}}

当上述代码启动之后,在开源界面中发生了如下变化。队列列表中新增了两个队列,交换机列表中新增了一条声明的交换机。

消费者代码

public class Consumer1 {public static void main(String[] args) throws IOException, TimeoutException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT, true);// TODO 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE1, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.FANOUT_QUEUE1, Constants.FANOUT_EXCHANGE, "");// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者1接收到消息:" + new String(body));}};channel.basicConsume(Constants.FANOUT_QUEUE1, true, consumer);// TODO 释放资源Common.close();}}
public class Consumer2 {public static void main(String[] args) throws IOException, TimeoutException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT, true);// TODO 声明队列channel.queueDeclare(Constants.FANOUT_QUEUE2, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.FANOUT_QUEUE2, Constants.FANOUT_EXCHANGE, "");// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者2接收到消息:" + new String(body));}};channel.basicConsume(Constants.FANOUT_QUEUE2, true, consumer);// TODO 释放资源Common.close();}}

路由模式

路由模式实现的代码案例按照此图的需求来做。根据此图可以看出,当生产者发送消息时的路由键为error时,两个队列都能收到消息;但是当生产者发送消息时的路由键为info或者warn时,只有队列二可以收到消息。

生产者代码

public class Producer {public static void main(String[] args) throws IOException, TimeoutException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);// TODO 声明队列channel.queueDeclare(Constants.DIRECT_QUEUE1, true, false, false, null);channel.queueDeclare(Constants.DIRECT_QUEUE2, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.DIRECT_QUEUE1, Constants.DIRECT_EXCHANGE, "error");channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "info");channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "warn");channel.queueBind(Constants.DIRECT_QUEUE2, Constants.DIRECT_EXCHANGE, "error");// TODO 发送消息// error的消息进入两个队列// info和warn只会进入队列2String[] msg = {"info", "error", "warn"};for (String s : msg) {channel.basicPublish(Constants.DIRECT_EXCHANGE, s, null, s.getBytes());}System.out.println("路由模式发送消息成功!");// TODO 释放资源Common.close();}}

 当运行上述代码之后,发现队列中的结果和预想结果一致。

消费者代码

public class Consumer1 {public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);// TODO 声明队列channel.queueDeclare(Constants.DIRECT_QUEUE1, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.DIRECT_QUEUE1, Constants.DIRECT_EXCHANGE, "error");// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者1接收到消息:" + new String(body));}};channel.basicConsume(Constants.DIRECT_QUEUE1, true, consumer);Thread.sleep(20000); // 阻塞等待消息接收完成// TODO 释放资源Common.close();}}
public class Consumer2 {public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {Channel channel = Common.getChannel();// TODO 声明交换机channel.exchangeDeclare(Constants.DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT, true);// TODO 声明队列channel.queueDeclare(Constants.DIRECT_QUEUE2, true, false, false, null);// TODO 绑定交换机和队列channel.queueBind(Constants.DIRECT_QUEUE2, Constants. DIRECT_EXCHANGE, "error");channel.queueBind(Constants.DIRECT_QUEUE2, Constants. DIRECT_EXCHANGE, "info");channel.queueBind(Constants.DIRECT_QUEUE2, Constants. DIRECT_EXCHANGE, "warn");// TODO 接收消息DefaultConsumer consumer = new DefaultConsumer(channel) {@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("消费者2接收到消息:" + new String(body));}};channel.basicConsume(Constants.DIRECT_QUEUE2, true, consumer);Thread.sleep(20000); // 阻塞等待消息接收完成// TODO 释放资源Common.close();}}

 上述代码启动之后,在控制台输出消息如下:

 

在该文章中,介绍了MQ的七大工作模式,并且对其中的前四种工作模式的SDK写法进行了代码示例,在下一篇文章中,将对剩下的三种SDK代码以及SpringBoot代码进行示例操作。

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

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

相关文章

Redisson分布式锁实现及原理详解

随着技术快速发展&#xff0c;数据规模增大&#xff0c;分布式系统越来越普及&#xff0c;一个应用往往会部署在多台机器上&#xff08;多节点&#xff09;&#xff0c;在有些场景中&#xff0c;为了保证数据不重复&#xff0c;要求在同一时刻&#xff0c;同一任务只在一个节点…

浏览器中的JavaScript核心BOM(浏览器对象模型)重点掌握对象之History对象的属性与方法

History对象是用来把网页浏览历史用类似栈的方式进行表示。 这定义听起来非常的抽象&#xff0c;其实History对象的作用就跟浏览器的前进和后退很像&#xff0c;我们来用几幅图来理解一下。首先我们先回顾一下浏览器的返回上一个页面 和 跳转到下一个页面 这两个功能。 就类似…

JDBC使用

7.2 创建JDBC应用 7.2.1 创建JDBC应用程序的步骤 使用JDBC操作数据库中的数据包括6个基本操作步骤&#xff1a; &#xff08;1&#xff09;载入JDBC驱动程序&#xff1a; 首先要在应用程序中加载驱动程序driver&#xff0c;使用Class.forName()方法加载特定的驱动程序&#xf…

【题解单调队列优化dp】划分

划分 分析&#xff1a; 首先&#xff0c;我们目光着眼于部分分 我们尝试用 O ( n 3 ) O(n^3) O(n3)的朴素dp去解决这个问题 f [ i ] [ j ] 表示划分到第 i 个位置&#xff0c;且上一个位置是 j 的最小运行时间是多少 f[i][j]表示划分到第i个位置&#xff0c;且上一个位置是j的…

erlang学习: Mnesia Erlang数据库3

Mnesia数据库删除实现和事务处理 -module(test_mnesia). -include_lib("stdlib/include/qlc.hrl").-record(shop, {item, quantity, cost}). %% API -export([insert/3, select/0, select/1, delete/1, transaction/1,start/0, do_this_once/0]). start() ->mnes…

自然语言处理系列六十九》搜索引擎项目实战》搜索框架技术选型

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 自然语言处理系列六十九搜索引擎项目实战》搜索框架技术选型搜索…

(k8s)kubernetes 挂载 minio csi 的方式

一、安装Minio&#xff08;Minio分布式集群搭建部署_minio集群最少几台-CSDN博客&#xff09; 生成accessKeyID和secretAccessKey&#xff1a; 二、安装csi-s3插件(在k8s集群上) 首先我们把插件的yaml文件都下载下来&#xff0c;为了保证版本测试的一致性&#xff0c;我们下载…

828华为云征文|基于华为云Flexus云服务器X搭建jumpserver堡垒机软件

文章目录 ❀前言❀jumpserver堡垒机概述❀环境准备❀部署说明❀在线安装❀浏览器访问❀资产添加❀资产授权❀资产登录❀总结 ❀前言 近期华为云推出了最新的华为云Flexus云服务器X&#xff0c;这款云主机在算柔性算力做出了重大变革。华为云Flexus云服务器X基于擎天QingTian架…

QT设置闹钟超时播报

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTimerEvent> #include<QTime> #include<QTextToSpeech>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic…

一个基于Spring Boot 3、Vue 3 和 Element-Plus 的中后台管理框架,流畅、直观且功能强大

前言 当前市面上的中后台管理系统虽然种类繁多&#xff0c;但在实际使用中仍存在不少痛点&#xff0c;比如技术栈陈旧、性能低下、扩展性差等问题。开发者们常常需要花费大量的时间和精力去处理这些问题&#xff0c;而不是专注于业务逻辑本身。 那么&#xff0c;有没有一个框…

计算赎金信

给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a; 输入&#xff…

使用3DUNet训练自己的数据集(pytorch)— 医疗影像分割

代码:lee-zq/3DUNet-Pytorch: 3DUNet implemented with pytorch (github.com) 文章<cicek16miccai.pdf (uni-freiburg.de)3D U-Net: Learning Dense Volumetric Segmentation

HarmonyOS学习(十)——网络编程

文章目录 1、通过HTTP请求网络2、Web组件2.1、加载本地网页2.2、加载在线网页2.3、网页缩放2.4、文本缩放2.5、web组件事件以及状态说明2.6、处理页面导航 1、通过HTTP请求网络 官方API文档地址&#xff1a;HTTP数据请求-Network Kit数据传输能力-Network Kit&#xff08;网络…

Linux 下 C/C++ 程序编译的过程

目录 一、GCC 工具链二、编译过程1、预处理2、编译3、汇编4、链接 本文将介绍如何将 C/C 语言编写的程序转换成为处理器能够执行的二进制代码的过程&#xff0c;包括四个步骤&#xff1a;预处理&#xff08;Preprocessing&#xff09;编译&#xff08;Compilation&#xff09;汇…

Qt_自定义信号

目录 1、自定义信号的规定 2、创建自定义信号 3、带参数的信号与槽 4、一个信号连接多个槽 5、信号与槽的断开 结语 前言&#xff1a; 虽然Qt已经内置了大量的信号&#xff0c;并且这些信号能够满足大部分的开发场景&#xff0c;但是Qt仍然允许开发者自定义信号&#…

ARMxy嵌入式边缘计算控制器支持Linux OS应用于AIOT

人工智能与物联网&#xff08;AIoT&#xff09;的融合正深刻改变着各个行业。而在这一变革中&#xff0c;ARMxy 嵌入式控制器以其卓越的性能和对 Linux OS 的支持&#xff0c;成为了 AIoT 应用的关键推动力量。 一、ARMxy 嵌入式控制器的优势 强大的处理能力 ARMxy 嵌入式控制…

浮毛危害人体健康?希喂、安德迈、有哈宠物空气净化器吸毛测评

养宠之前了解清楚相关的知识&#xff0c;这既是对宠物负责&#xff0c;也是对我们自己负责。宠物最让铲屎官头疼的就是毛发问题&#xff0c;大量脱落的毛发会带来繁重的清理任务&#xff0c;同时飘在空中浮毛还是潜藏在身边的健康”杀手“。浮毛微小、质量轻&#xff0c;容易随…

opencv之图像轮廓(三)--凸包

文章目录 前言获取凸包凸缺陷几何学测试测试轮廓是否是凸形的点到轮廓的距离 形状场景算法比较轮廓轮廓的特征值宽高比ExtentSolidity等效直径&#xff08;Equivalent Diameter&#xff09;方向掩模和像素点使用Numpy函数获取轮廓像素点使用OpenCV函数获取轮廓点 最大值和最小值…

VR 尺寸美学主观评价-解决方案-现场体验研讨会报名

棣拓科技VR创新解决方案助力尺寸美学所见即所得! 诚邀各位行业专家莅临指导交流 请扫描海报二维码踊跃报名&#xff0c;谢谢 中国上海 2024.10.25 亮点介绍 1、通过精湛渲染技术&#xff0c;最真实展现设计效果&#xff0c;并通过VR设备一比一比例进行展现。 2、设置相关设…

ctfshow-PHP反序列化

web254 源码 <?php/* # -*- coding: utf-8 -*- # Author: h1xa # Date: 2020-12-02 17:44:47 # Last Modified by: h1xa # Last Modified time: 2020-12-02 19:29:02 # email: h1xactfer.com # link: https://ctfer.com //mytime 2023-12-4 0:22 */ error_reporting(0)…