RocketMQ 发送顺序消息

文章目录

  • 顺序消息应用场景
  • 消息组(MessageGroup)
  • 顺序性
    • 生产的顺序性
    • MQ 存储的顺序性
    • 消费的顺序性
  • rocketmq-client-java 示例(gRPC 协议)
    • 1. 创建 FIFO 主题
    • 生产者代码
    • 消费者代码
    • 解决办法
    • 解决后执行结果
  • rocketmq-client 示例(Remoting 协议)
    • 生产者
      • MessageQueueSelector 详解
    • 消费者

顺序消息应用场景

在有序事件处理、撮合交易、数据实时增量同步等场景下,异构系统间需要维持强一致的状态同步,上游的事件变更需要按照顺序传递到下游进行处理。在这类场景下使用 RocketMQ 的顺序消息可以有效保证数据传输的顺序性。比如:同一个用户的操作,一定是先生成订单、再进行支付、扣减库存、生成物流信息等。

消息组(MessageGroup)

RocketMQ 顺序消息的顺序关系通过消息组(MessageGroup)判定和识别,发送顺序消息时需要为每条消息设置归属的消息组,相同消息组的多条消息之间遵循先进先出的顺序关系,不同消息组、无消息组的消息之间不涉及顺序性。

基于消息组的顺序判定逻辑,支持按照业务逻辑做细粒度拆分,可以在满足业务局部顺序的前提下提高系统的并行度和吞吐能力。

顺序性

RocketMQ 的消息的顺序性分为两部分,生产顺序性和消费顺序性。

生产的顺序性

生产的顺序性就是必须保证每个消息在生成时是顺序的,且顺序的发送到 MQ 服务器。要保证生产的顺序,需要满足以下条件

  • 单一生产者:消息生产的顺序性仅支持单一生产者,不同生产者分布在不同的系统,即使设置相同的消息组,不同生产者之间产生的消息也无法判定其先后顺序。
  • 串行发送:Apache RocketMQ 生产者客户端支持多线程安全访问,但如果生产者使用多线程并行发送,则不同线程间产生的消息将无法判定其先后顺序。

MQ 存储的顺序性

MQ 按顺序收到消息后,会保证设置了同一消息组的消息,按照发送顺序存储在同一队列中。服务端顺序存储逻辑如下:

  • 相同消息组的消息按照先后顺序被存储在同一个队列。
  • 不同消息组的消息可以混合在同一个队列中,且不保证连续。
    在这里插入图片描述

消费的顺序性

消费的顺序性,是消费者在消费的时候要严格按照 MQ 中的存储顺序来执行。

  • 消费者保证执行的顺序
    • PushConsumer 类型消费者,RocketMQ 会保证消息按照存储顺序一条一条投递给消费者
    • SimpleConsumer 类型消费者,需要业务实现方自行保证消费的顺序。消费消息时需要严格按照接收—处理—应答的语义处理消息,避免因异步处理导致消息乱序。
  • 重试策略

Apache RocketMQ 顺序消息投递仅在重试次数限定范围内,即一条消息如果一直重试失败,超过最大重试次数后将不再重试,跳过这条消息消费,不会一直阻塞后续消息处理。

所以对于需要严格保证消费顺序的场景,请务设置合理的重试次数,避免参数不合理导致消息乱序。

rocketmq-client-java 示例(gRPC 协议)

1. 创建 FIFO 主题

本示例,我们模拟多个用户的一系列操作,并多个消息组区分不同的顺序消息。要求每个用户的消息按顺序执行,不同用户的消息之间不做必要关联。

$> ./mqadmin updatetopic -n localhost:9876 -c DefaultCluster -t MY_FIFO_TOPIC -o true -a +message.type=FIFO

注意:这里比普通消息和顺序消息多了一个 -o 参数,表示 order 的意思。

生产者代码

import com.yyoo.mq.rocket.MyMQProperties;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;import java.io.IOException;public class FifoProducerDemo {public static void main(String[] args) throws ClientException, IOException {// 用于提供:生产者、消费者、消息对应的构建类 BuilderClientServiceProvider provider = ClientServiceProvider.loadService();// 构建配置类(包含端点位置、认证以及连接超时等的配置)ClientConfiguration configuration = ClientConfiguration.newBuilder()// endpoints 即为 proxy 的地址,多个用分号隔开。如:xxx:8081;xxx:8081.setEndpoints(MyMQProperties.ENDPOINTS).build();// 构建生产者Producer producer = provider.newProducerBuilder()// Topics 列表:生产者和主题是多对多的关系,同一个生产者可以向多个主题发送消息.setTopics("MY_FIFO_TOPIC").setClientConfiguration(configuration)// 构建生产者,此方法会抛出 ClientException 异常.build();for(int i = 1; i <= 10;i++) {String msgGroup = "user" ; // 表示有两个用户String keys = "key_" + i;// 构建消息类Message message = provider.newMessageBuilder()// 设置消息发送到的主题.setTopic("MY_FIFO_TOPIC")// 设置消息索引键,可根据关键字精确查找某条消息。其一般为业务上的唯一值。如:订单id.setKeys(keys)// 设置消息Tag,表示为创建订单.setTag("ORDER_CREATE")// 设置消息组.setMessageGroup(msgGroup)// 消息体,单条消息的传输负载不宜过大。所以此处的字节大小最好有个限制.setBody(("{\"success\":true,\"msg\":\""+ msgGroup + ":" + keys +"\"}").getBytes()).build();// 发送消息(此处最好进行异常处理,对消息的状态进行一个记录)try {SendReceipt sendReceipt = producer.send(message);System.out.println(keys);System.out.println("Send message successfully, messageId=" + sendReceipt.getMessageId());} catch (ClientException e) {System.out.println("Failed to send message");}}// 发送完,关闭生产者// producer.close();}}

发送顺序消息时,消息一定要设置消息组,同一消息组的消息将会按服务器接收的顺序进行消费。

注:发送顺序消息前需要设置 NameServer 中的配置 orderMessageEnable 和 returnOrderTopicConfigToBroker 为 true。特别是 orderMessageEnable 默认为 false。建议在启动 namesrv 的时候使用自定义配置,在自定义配置中配置选项为true即可。

# namesrv.conf 为我们自定义的配置文件
nohup sh bin/mqnamesrv -c conf/namesrv.conf &

消费者代码

import com.yyoo.mq.rocket.MyMQProperties;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.PushConsumer;import java.nio.ByteBuffer;
import java.util.Collections;public class FifoConsumerDemo {public static void main(String[] args) throws ClientException {// 用于提供:生产者、消费者、消息对应的构建类 BuilderClientServiceProvider provider = ClientServiceProvider.loadService();// 构建配置类(包含端点位置、认证以及连接超时等的配置)ClientConfiguration configuration = ClientConfiguration.newBuilder()// endpoints 即为 proxy 的地址,多个用分号隔开。如:xxx:8081;xxx:8081.setEndpoints(MyMQProperties.ENDPOINTS).build();// 设置过滤条件(这里为使用 tag 进行过滤)String tag = "ORDER_CREATE";FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);// 构建消费者PushConsumer pushConsumer = provider.newPushConsumerBuilder().setClientConfiguration(configuration)// 设置消费者分组.setConsumerGroup("MY_FIFO_GROUP")// 设置主题与消费者之间的订阅关系.setSubscriptionExpressions(Collections.singletonMap("MY_FIFO_TOPIC", filterExpression)).setMessageListener(messageView -> {System.out.println(messageView);ByteBuffer rs = messageView.getBody();byte[] rsByte = new byte[rs.limit()];rs.get(rsByte);System.out.println("Message body:" + new String(rsByte));// 处理消息并返回消费结果。System.out.println("Consume message successfully, messageId=" + messageView.getMessageId());return ConsumeResult.SUCCESS;}).build();System.out.println(pushConsumer);// 如果不需要再使用 PushConsumer,可关闭该实例。// pushConsumer.close();}}

注:多验证几次后会发现,消费执行并没有严格的按照顺序执行,查找源码后发现,PushConsumer 的 builder 在构建 PushConsumer 的时候有个 Settings 对象,该对象的主题配置信息是从服务器获取,获取后有一个 isFifo 参数,此参数对应是否顺序消费,但是目前此值一直为false。此问题为消费者分组的问题,Remoting 协议方式无此问题,因为两种 Client 的实现是不一样的。

解决办法

在 MQ bin目录执行如下命令即可,具体的相关说明,我们将在后续章节中(《RocketMQ 消费者分类与分组》)详细说明。

$> ./mqadmin updateSubGroup -n 127.0.0.1:9876 -g MY_FIFO_GROUP -o true -c DefaultCluster

解决后执行结果

MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000001, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543268, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_2], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000000, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543178, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_1], messageGroup=user2, deliveryTimestamp=null, properties={__SHARDINGKEY=user2}}
Message body:{"success":true,"msg":"user1:key_2"}
Message body:{"success":true,"msg":"user2:key_1"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000000
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000001
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000002, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543279, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_3], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
Message body:{"success":true,"msg":"user1:key_3"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000002
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000004, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543294, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_5], messageGroup=user2, deliveryTimestamp=null, properties={__SHARDINGKEY=user2}}
Message body:{"success":true,"msg":"user2:key_5"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000004
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000003, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543288, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_4], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000005, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543301, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_6], messageGroup=user2, deliveryTimestamp=null, properties={__SHARDINGKEY=user2}}
Message body:{"success":true,"msg":"user1:key_4"}
Message body:{"success":true,"msg":"user2:key_6"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000005
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000003
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000006, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543313, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_7], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
Message body:{"success":true,"msg":"user1:key_7"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000006
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000007, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543320, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_8], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
Message body:{"success":true,"msg":"user1:key_8"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000007
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000008, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543331, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_9], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
Message body:{"success":true,"msg":"user1:key_9"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000008
MessageViewImpl{messageId=010456E5ECA6F32F6C051313D700000009, topic=MY_FIFO_TOPIC, bornHost=DESKTOP-S1DMOAD, bornTimestamp=1694595543340, endpoints=ipv4:192.168.1.1:8081, deliveryAttempt=1, tag=ORDER_CREATE, keys=[key_10], messageGroup=user1, deliveryTimestamp=null, properties={__SHARDINGKEY=user1}}
Message body:{"success":true,"msg":"user1:key_10"}
Consume message successfully, messageId=010456E5ECA6F32F6C051313D700000009

注意:user1 和 user2 的操作顺序是一致的。因为我们不需要保证 user1 的操作必须在 user2 之前,只需要保证他们各自的操作为顺序的就可以。

rocketmq-client 示例(Remoting 协议)

生产者

import com.yyoo.mq.rocket.MyMQProperties;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.shaded.commons.lang3.RandomUtils;import java.util.List;public class FifoProducerDemo {/*** 生产者分组*/private static final String PRODUCER_GROUP = "FIFO_PRODUCER_GROUP";/*** 主题*/private static final String TOPIC = "MY_FIFO_TOPIC";public static void main(String[] args) throws MQClientException {/** 创建生产者,并使用生产者分组初始化*/DefaultMQProducer producer = new DefaultMQProducer(PRODUCER_GROUP);/** NamesrvAddr 的地址,多个用分号隔开。如:xxx:9876;xxx:9876*/producer.setNamesrvAddr(MyMQProperties.NAMESRV_ADDR);/** 发送消息超时时间,默认即为 3000*/producer.setSendMsgTimeout(3000);/** 启动生产者,此方法抛出 MQClientException*/producer.start();/** 发送消息*/for (int i = 1; i <= 10; i++) {try {Message msg = new Message();msg.setTopic(TOPIC);// 设置消息索引键,可根据关键字精确查找某条消息。msg.setKeys("messageKey");// 设置消息Tag,用于消费端根据指定Tag过滤消息。msg.setTags("ORDER_CREATE");// 设置消息体msg.setBody(("顺序消息" + i).getBytes());// 这里 userId 取值为 1,2,3(模拟有3个用户的顺序操作)int userId = RandomUtils.nextInt(1,4);SendResult sendResult = producer.send(msg, new MessageQueueSelector() {@Overridepublic MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {// 这个arg就是对应userIdInteger userId = (Integer)arg;// 我们按队列的数量,对每个user进行分组int index = userId % mqs.size();// 同一个user的消息放入同一个队列return mqs.get(index);}},userId);System.out.printf("%s%n", sendResult);} catch (Exception e) {e.printStackTrace();System.out.println("消息发送失败!i = " + i);}}// 如果生产者不再使用,则调用关闭// 异步发送消息注意:异步发送消息,建议此处不关闭或者在sleep一段时间后再关闭// 因为异步 SendCallback 执行的时候,shutdow可能已经执行了,生产者被关闭了// producer.shutdown();}}

MessageQueueSelector 详解

public interface MessageQueueSelector {MessageQueue select(final List<MessageQueue> mqs, final Message msg, final Object arg);
}

mqs:队列列表,我们前面说了,默认 8 个队列
msg:当前消息
arg:为我们 send 方法传的第三个参数,示例中就是 userId

MessageQueueSelector 意为队列选择器,Remoting 协议客户端中没有 消息组的概念,所以需要我们手动的为消息进行分组(将需要严格顺序的消息放在同一个队列),这个接口就是完成此任务的,而且分组的逻辑需要我们自己实现。实际应用中我们可以使用 用户id、订单id等来为顺序消息分组。

消费者

import com.yyoo.mq.rocket.MyMQProperties;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;import java.util.List;public class FifoConsumerDemo {public static void main(String[] args) throws MQClientException {// 初始化 consumerDefaultMQPushConsumer consumer = new DefaultMQPushConsumer("REMOTING_FIFO_CONSUMER_GROUP");// 设置 namesrv 地址consumer.setNamesrvAddr(MyMQProperties.NAMESRV_ADDR);// 设置从开头开始读取消息consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);// 设置订阅的主题,以及过滤tagconsumer.subscribe("MY_FIFO_TOPIC", "ORDER_CREATE || TagA || TagD || messageTag");consumer.registerMessageListener(new MessageListenerOrderly() {@Overridepublic ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);for(MessageExt msg : msgs){System.out.println(new String(msg.getBody()));}return ConsumeOrderlyStatus.SUCCESS;}});consumer.start();System.out.printf("Consumer Started.%n");}}

注意:顺序消息消费者的监听类型为 MessageListenerOrderly ,注意与我们前面的示例 MessageListenerConcurrently 进行区分。

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

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

相关文章

【结构型】代理模式(Proxy)

目录 代理模式(Proxy)适用场景代理模式实例代码&#xff08;Java&#xff09; 代理模式(Proxy) 为其他对象提供一种代理以控制对这个对象的访问。Proxy 模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候。 适用场景 远程代理 (Remote Proxy) 为一个对象在不同…

《ADS2011射频电路设计与仿真实例》功率放大器设计的输入输出匹配

徐兴福这本书的6.6 Smith圆图匹配这一节中具体匹配时&#xff0c;直接给出了电容与串联微带的值&#xff0c;没有给出推导过程&#xff0c;我一开始以为是省略了详细推导过程&#xff0c;后来发现好像基本上是可以随便自己设的。以输入匹配&#xff08;书本6.6.4输入匹配电路的…

Modbus RTU(Remote Terminal Unit)与RS-485协议介绍(主站设备(Master)、从站设备(Slave))

文章目录 Modbus RTU与RS-485协议介绍一、引言二、Modbus RTU 协议介绍2.1 Modbus RTU 协议简介2.2 Modbus RTU 协议帧结构主站设备、从站设备与从站设备地址2.3 Modbus RTU 协议举例 三、RS-485 协议介绍3.1 RS-485 协议简介3.2 RS-485 物理连接方式3.3 RS-485 与 Modbus RTU …

LeetCode-热题100-笔记-day31

105. 从前序与中序遍历序列构造二叉树https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c…

全国职业技能大赛云计算--高职组赛题卷④(容器云)

全国职业技能大赛云计算--高职组赛题卷④&#xff08;容器云&#xff09; 第二场次题目&#xff1a;容器云平台部署与运维任务1 Docker CE及私有仓库安装任务&#xff08;5分&#xff09;任务2 基于容器的web应用系统部署任务&#xff08;15分&#xff09;任务3 基于容器的持续…

企业架构LNMP学习笔记61

Nginx作为tomcat的前段反向代理&#xff1a; 在实际业务环境中&#xff0c;用户是直接通过域名访问&#xff0c;基于协议一般是http、https等。默认tomcat运行在8080端口。一般会通过前端服务器反向代理到后端的tomcat的方式&#xff0c;来实现用户可以通过域名访问tomcat的we…

2023全新TwoNav开源网址导航系统源码 | 去授权版

2023全新TwoNav开源网址导航系统源码 已过授权 所有功能可用 测试环境&#xff1a;NginxPHP7.4MySQL5.6 一款开源的书签导航管理程序&#xff0c;界面简洁&#xff0c;安装简单&#xff0c;使用方便&#xff0c;基础功能免费。 TwoNav可帮助你将浏览器书签集中式管理&#…

Java面试八股文宝典:初识数据结构-数组的应用扩展之HashMap

前言 除了基本的数组&#xff0c;还有其他高级的数据结构&#xff0c;用于更复杂的数据存储和检索需求。其中&#xff0c;HashMap 是 Java 集合框架中的一部分&#xff0c;用于存储键值对&#xff08;key-value pairs&#xff09;。HashMap 允许我们通过键来快速查找和检索值&…

【数据结构】树的存储结构;树的遍历;哈夫曼树;并查集

欢~迎~光~临~^_^ 目录 1、树的存储结构 1.1双亲表示法 1.2孩子表示法 1.3孩子兄弟表示法 2、树与二叉树的转换 3、树和森林的遍历 3.1树的遍历 3.1.1先根遍历 3.1.2后根遍历 3.2森林的遍历 3.2.1先序遍历森林 3.2.2中序遍历森林 4、树与二叉树的应用 4.1哈夫曼树…

【Linux网络编程】Socket-TCP实例

该代码利用socket套接字建立Tcp连接&#xff0c;包含服务器和客户端。当服务器和客户端启动时需要把端口号或ip地址以命令行参数的形式传入。服务器启动如果接受到客户端发来的请求连接&#xff0c;accept函数会返回一个打开的socket文件描述符&#xff0c;区别于监听连接的lis…

【校招VIP】前端网络之路由选择协议

考点介绍 当两台非直接连接的计算机需要经过几个网络通信时&#xff0c;通常就需要路由器。路由器提供一种方法来开辟通过一个网状联结的路径。在图R-9中标示了几条存在于洛杉矶和纽约办公室的路径。这种网状网络提供了冗余路径以调整通信负载或倒行链路&#xff0c;通常有一条…

灰狼算法优化ICEEMDAN参数,四种适应度函数任意切换,最小包络熵、样本熵、信息熵、排列熵...

今天给大家带来一期由灰狼算法优化ICEEMDAN参数的MATLAB代码。 优化ICEEMDAN参数的思想可以参考该文献&#xff1a; [1]陈爱午,王红卫.基于HBA-ICEEMDAN和HWPE的行星齿轮箱故障诊断[J].机电工程,2023,40(08):1157-1166. 文献原文提到&#xff1a;由于 ICEEMDAN 方法的分解效果取…

【数据结构】队列知识点总结--定义;基本操作;队列的顺序实现;链式存储;双端队列;循环队列

欢迎各位看官^_^ 目录 1.队列的定义 2.队列的基本操作 2.1初始化队列 2.2判断队列是否为空 2.3判断队列是否已满 2.4入队 2.5出队 2.6完整代码 3.队列的顺序实现 4.队列的链式存储 5.双端队列 6.循环队列 1.队列的定义 队列&#xff08;Queue&#xff09;是一种先…

Vue3记录

Vue3快速上手 1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;https://github.com/vuejs/vue-next/releas…

软件需求怎么写?

前言&#xff1a;一般来说&#xff0c;软件产品的需求人员的主要输出物就是软件需求&#xff0c;如果这个软件产品就XX系统&#xff0c;人们口中的“系统需求”和“软件需求”就没有什么区别了。在车企行业&#xff0c;推行这ASPICE体系&#xff0c;在这个体系中明确申请了系统…

DMNet复现(一)之数据准备篇:Density map guided object detection in aerial image

一、生成密度图 密度图标签生成 采用以下代码&#xff0c;生成训练集密度图gt&#xff1a; import cv2 import glob import h5py import scipy import pickle import numpy as np from PIL import Image from itertools import islice from tqdm import tqdm from matplotli…

哈希及哈希表的实现

目录 一、哈希的引入 二、概念 三、哈希冲突 四、哈希函数 常见的哈希函数 1、直接定址法 2、除留余数法 五、哈希冲突的解决 1、闭散列 2、开散列 一、哈希的引入 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找…

浅析三维模型3DTile格式轻量化处理常见问题与处理措施

浅析三维模型3DTile格式轻量化处理常见问题与处理措施 三维模型3DTile格式的轻量化处理是大规模三维地理空间数据可视化的关键环节&#xff0c;但在实际操作过程中&#xff0c;往往会遇到一些问题。下面我们来看一下这些常见的问题以及对应的处理措施。 变形过大&#xff1a;压…

Vue入门--vue的生命周期

一.什么是Vue 二.Vue的简介 官方网址 特点 三. 前后端的分离 重大问题 优势 4.Vue入门 定义一个管理边界 ​编辑 测试结果 vue的优势 ​编辑 测试结果 5.Vue的生命周期 vue的生命周期图 ​编辑建立一个html 测试结果 一.什么是Vue Vue是一种流行的JavaScript前端框…

【Graph Net学习】GNN/GCN代码实战

一、简介 GNN&#xff08;Graph Neural Network&#xff09;和GCN&#xff08;Graph Convolutional Network&#xff09;都是基于图结构的神经网络模型。本文目标就是打代码基础&#xff0c;未用PyG&#xff0c;来扒一扒Graph Net两个基础算法的原理。直接上代码。 二、代码 …