MQTT报文超过最大消息,消息大小长度

项目中接触到mqtt用的是emqtt,下发消息的时候消息数量过大,就会提示

已断开连接 (32109) - java.io.EOFException
	at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:181)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266)
	at java.util.concurrent.FutureTask.run(FutureTask.java)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException
	at java.io.DataInputStream.readByte(DataInputStream.java:267)
	at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92)
	at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:133)
	... 8 more

我测试过无数次,证明不是连接断开的原因,只要发送的数据小于60kb左右就没事,在数据库中一点点长度测出来的

但是这个也解决不了我的问题啊.我需要下发130KB左右的消息,里面包含了base64图片问题

在官网找文档

https://docs.emqx.io/broker/v3/cn/config.html#mqtt

MQTT 最大报文尺寸:

mqtt.max_packet_size = 1MB

随后去 \emqttd\etc\emq.conf果然找到了这个大小

## Maximum MQTT packet size allowed.
##
## Value: Bytes
##
## Default: 64K
mqtt.max_packet_size = 64KB

人家实际限制的是64KB,将这个数值改一下重启

这下好了.在此记录一下 

<think>好的,用户想了解如何在STM32标准库环境下实现MQTT报文的可靠传输,特别是重传机制。首先,我需要回顾一下MQTT协议的基本知识,尤其是关于QoS等级和报文传输的部分。MQTT有三种QoS等级,其中QoS1和QoS2需要确认机制,所以可能需要重传。用户提到的是报文重传,所以可能主要关注QoS1的情况,因为QoS2更复杂,涉及多次握手。 接下来,我需要考虑STM32标准库的编程环境。标准库通常指的是ST提供的用于操作寄存器的函数库,比如处理定时器、串口、中断等。实现重传机制,可能需要用到定时器来设置超时,当发送一个报文后,如果在规定时间内没有收到确认(比如PUBACK),就需要重新发送。 然后,用户的需求是“实现MQTT报文重传”,所以需要设计一个重传机制。这通常包括以下几个部分:报文缓存、超时定时器管理、重传计数和触发条件。需要确保在发送报文时,将报文存储在缓存中,并启动定时器。如果在超时时间内收到确认,就清除缓存中的报文;如果超时,则重新发送,并增加重试次数,直到达到最大次数后可能断开连接。 同时,需要考虑资源限制。STM32的内存有限,特别是如果使用较小的型号,所以缓存的设计需要高效,可能使用环形队列或链表来管理待确认的报文。另外,定时器的使用也需要考虑,硬件定时器的数量有限,可能需要软件定时器或者基于系统滴答定时器(SysTick)来实现多个定时任务。 还需要处理网络通信的稳定性。比如,在重传时,可能需要处理网络断开的情况,这时候重试几次后应该停止并报告错误。此外,确认报文的接收需要正确解析MQTT协议,识别对应的Packet Identifier,以匹配发送的报文和确认。 可能的实现步骤包括: 1. 设计报文缓存结构,存储Packet Identifier、报文内容、发送时间、重试次数等。 2. 使用定时器中断或轮询检查是否有超时的报文3. 在发送MQTT报文(如PUBLISH)时,将其加入缓存并启动定时器。 4. 当收到确认报文(如PUBACK)时,从缓存中移除对应的报文。 5. 定时检查缓存中的报文是否超时,若超时则重传,并增加重试次数,超过最大次数则处理错误。 需要注意的问题包括: - 确保Packet Identifier的正确生成和管理,避免重复或冲突。 - 处理并发情况,比如同时多个报文需要重传,如何高效管理定时器和缓存。 - 资源管理,避免内存泄漏或溢出,特别是在频繁重传的情况下。 - 线程安全,如果使用RTOS,需要考虑任务间的同步;如果裸机编程,则需确保中断和主循环之间的数据一致性。 可能还需要参考MQTT协议规范,确认不同QoS等级下的重传机制要求,比如QoS1需要等待PUBACK,而QoS2有更复杂的流程。用户可能主要关注QoS1的情况,所以可以重点讲解这部分。 最后,在STM32标准库中具体实现时,可能需要使用硬件定时器或者SysTick来生成定时事件,比如每100ms检查一次报文缓存中的超时条目。发送和接收部分需要使用串口或网络接口(如以太网模块或Wi-Fi模块)的驱动,确保数据正确发送和接收。确认报文的解析需要正确解析MQTT控制报文,提取Packet Identifier,以便找到对应的缓存条目。 总结来说,实现步骤大致是设计缓存结构、管理定时器、处理发送和确认、以及超时重传逻辑。同时需要考虑资源限制和稳定性问题,确保在嵌入式环境中可靠运行。</think>在STM32标准库中实现MQTT报文重传机制需结合协议规范与嵌入式特性,以下是分步实现方案: --- ### 一、MQTT重传机制核心原理 1. **QoS等级要求** - QoS0:无重传(最多一次传输) - **QoS1**:至少一次传输(需PUBACK确认,需实现重传) - QoS2:精确一次传输(需PUBREC/PUBREL/PUBCOMP握手) 2. **关键触发条件** - 发送PUBLISH报文后未收到PUBACK - 超时时间(通常1.5-2倍网络延迟,默认建议60秒) - 最大重试次数(通常3-5次) --- ### 二、STM32标准库实现步骤 #### 1. 数据结构设计 ```c typedef struct { uint16_t packet_id; // 报文标识符 uint8_t *payload; // 报文内容指针 uint32_t send_time; // 最后发送时间戳 uint8_t retry_count; // 当前重试次数 } MQTT_PendingPacket; #define MAX_PENDING_PACKETS 5 // 根据RAM大小调整 MQTT_PendingPacket pending_list[MAX_PENDING_PACKETS]; ``` #### 2. 定时器配置(以SysTick为例) ```c // 在SysTick中断服务函数中添加超时检查 void SysTick_Handler(void) { static uint32_t tick = 0; tick++; if (tick % 1000 == 0) { // 每1秒检查一次 check_pending_timeout(); } } ``` #### 3. 超时检测函数 ```c void check_pending_timeout(void) { for (int i = 0; i < MAX_PENDING_PACKETS; i++) { if (pending_list[i].packet_id != 0) { // 计算超时(示例使用60秒超时) if (HAL_GetTick() - pending_list[i].send_time > 60000) { if (pending_list[i].retry_count < MAX_RETRY) { resend_packet(&pending_list[i]); pending_list[i].retry_count++; pending_list[i].send_time = HAL_GetTick(); } else { handle_transmission_failure(pending_list[i].packet_id); clear_pending_slot(i); } } } } } ``` #### 4. 报文发送与缓存 ```c void mqtt_publish_qos1(const char* topic, const char* msg) { uint16_t packet_id = generate_packet_id(); // 生成唯一ID send_mqtt_publish(topic, msg, packet_id); // 实际发送函数 // 存入重传队列 int free_slot = find_free_pending_slot(); if (free_slot != -1) { pending_list[free_slot].packet_id = packet_id; pending_list[free_slot].payload = (uint8_t*)msg; // 实际需深拷贝 pending_list[free_slot].send_time = HAL_GetTick(); pending_list[free_slot].retry_count = 0; } } ``` #### 5. 确认处理(PUBACK接收) ```c void mqtt_handle_puback(uint16_t received_id) { for (int i = 0; i < MAX_PENDING_PACKETS; i++) { if (pending_list[i].packet_id == received_id) { clear_pending_slot(i); // 清除对应条目 break; } } } ``` --- ### 三、关键优化点 1. **内存管理** - 使用静态数组而非动态分配(提高稳定性) - 实现深拷贝payload(避免原数据被修改) 2. **Packet ID生成** ```c static uint16_t last_packet_id = 0; uint16_t generate_packet_id(void) { return (++last_packet_id == 0) ? 1 : last_packet_id; // 跳过0值 } ``` 3. **网络中断处理** - 在TCP/IP断开回调中清空重传队列 - 添加心跳机制(防止因网络阻塞误判) --- ### 四、调试建议 1. **模拟丢包测试** 通过注释确认处理代码,强制触发重传逻辑 2. **使用Wireshark抓包** 验证重传间隔是否符合预期 3. **内存泄漏检测** 确保每次清除slot时释放payload内存(若使用动态分配) --- ### 五、扩展实现(QoS2) 如需支持QoS2,需扩展数据结构: ```c typedef enum { WAIT_PUBREC, WAIT_PUBREL, WAIT_PUBCOMP } QoS2_State; typedef struct { QoS2_State state; uint16_t packet_id; // ...其他字段 } QoS2_PendingPacket; ``` 并实现状态机驱动重传逻辑。 --- 通过以上实现,可在STM32标准库环境中建立可靠的MQTT重传机制,确保关键数据的可靠传输。实际开发中需根据具体硬件资源调整队列长度和超时参数。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值