You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQTT/mosquitto大文件传输遇4MB限制:能否传150MB文件?

问题:通过Mosquitto传输150MB大文件是否可行?

我的目标是通过Mosquitto传输约150MB的文件,目前暂不考虑传输效率,仅需确认该传输是否可行。

MQTT规范提到消息payload上限为256MB,但我仅能成功传输最大4095KB的文件。发布端基于C语言Mosquitto库实现,动态分配存储二进制数据的vector。发布程序未报错,但当文件大小超过4065KB时,Broker端无发布通知,mosquitto_sub也无法接收消息,仅显示发布客户端成功断开连接:

1711360340: New connection from 127.0.0.1:50002 on port 1883.
1711360340: New client connected from 127.0.0.1:50002 as auto-A51C5B5B-F445-5952-5EA5-49B12F2E614D (p2, c1, k5).
1711360340: No will message specified.
1711360340: Sending CONNACK to auto-A51C5B5B-F445-5952-5EA5-49B12F2E614D (0, 0)
1711360340: Client auto-A51C5B5B-F445-5952-5EA5-49B12F2E614D disconnected: Success.

补充代码

发布端实现代码:

#include <cstdio>
#include <mosquitto.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <memory>

struct mosquitto *mosq;

void publishImage(const char *topic, const char *image_path)
{
    std::ifstream fs(image_path, std::ios::in | std::ios::binary | std::ios::app);  
    std::unique_ptr<std::vector<uint8_t>> v_buf;
    void *msgPayload = nullptr;
    int msgPayloadLen;
    
    if (fs.good()) 
    {
        v_buf.reset(new std::vector<uint8_t>((std::istreambuf_iterator<char>(fs)), (std::istreambuf_iterator<char>())));
        fs.close();

        msgPayload = static_cast<void*>(v_buf.get()->data());
        msgPayloadLen = v_buf.get()->size();
    }

    if(msgPayload == nullptr)
    {
        fprintf(stderr, "image could not be copied to memory\n");
        return;
    }

    int rc = mosquitto_publish(mosq, NULL, topic, msgPayloadLen, msgPayload, 1, false);
    if (rc != MOSQ_ERR_SUCCESS)
    {
        fprintf(stderr, "mosquitto publish error: %s\n", mosquitto_strerror(rc));
    }

    return;
};

int main(int argc, const char* argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "Not enough input arguments!\nUsage: imageUpdater <topic> <path_to_image>\n");
        return 1;
    }

    const char *topic = argv[1];
    const char *pathToImage = argv[2];

    mosquitto_lib_init();

    mosq = mosquitto_new(NULL, true, NULL);
    if (mosq == NULL)
    {
        fprintf(stderr, "Error: Out of memory.\n");
        return 1;
    }

    int rc = mosquitto_connect(mosq,  "127.0.0.1", 1883, 5);
    if (rc != MOSQ_ERR_SUCCESS)
    {
        mosquitto_destroy(mosq);
        fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc));
        return 1;
    }
    else
    {
        printf("Connected!\n");
    }

    rc = mosquitto_loop_start(mosq);
    if (rc != MOSQ_ERR_SUCCESS)
    {
        mosquitto_destroy(mosq);
        fprintf(stderr, "Error: %s\n", mosquitto_strerror(rc));
        return 1;
    }

    publishImage(topic, pathToImage);
    mosquitto_lib_cleanup();
    return 0;
}

补充日志:成功发布小文件的情况

1711376922: New client connected from 127.0.0.1:38426 as auto-33E25100-81EB-0583-E540-C73A5D29E267 (p2, c1, k5).
1711376922: No will message specified.
1711376922: Sending CONNACK to auto-33E25100-81EB-0583-E540-C73A5D29E267 (0, 0)
1711376922: Received PUBLISH from auto-33E25100-81EB-0583-E540-C73A5D29E267 (d0, q1, r0, m1, 'fota/update', ... (4192256 bytes))
1711376922: Sending PUBACK to auto-33E25100-81EB-0583-E540-C73A5D29E267 (m1, rc0)
1711376922: Client auto-33E25100-81EB-0583-E540-C73A5D29E267 closed its connection.

额外测试发现:使用QoS0替代QoS1可传输更大文件,但可靠性极低,10MB文件尝试5次才成功;QoS1多次尝试后也能传输10MB文件,但QoS0对4000KB左右文件的可靠性不如QoS1。

现询问:通过Mosquitto传输此类大文件是否可行?若可行,实现的最佳实践是什么?


回答

1. 可行性结论

通过Mosquitto传输150MB文件完全可行,当前传输失败是因为客户端实现逻辑和Broker默认配置的限制,而非MQTT或Mosquitto本身的能力问题。

2. 当前代码的核心问题

代码在调用publishImage后立即执行mosquitto_lib_cleanup()并退出程序,但MQTT QoS1的消息需要等待Broker返回PUBACK确认后才算发布完成。大文件的网络传输+Broker处理需要更长时间,此时客户端直接退出会导致消息传输中断,Broker会直接断开连接,自然不会处理该消息。

3. 快速修复方案

3.1 等待消息确认完成

可以通过回调函数监听PUBACK,确保消息发送完成后再退出:

void on_publish(struct mosquitto *mosq, void *obj, int mid) {
    printf("消息ID %d 发布成功\n", mid);
    // 收到确认后标记可以退出
    *(bool*)obj = true;
}

int main(int argc, const char* argv[]) {
    // ... 原有代码省略 ...

    bool publish_done = false;
    // 设置发布回调
    mosquitto_publish_callback_set(mosq, on_publish);
    // 将标记变量绑定到客户端实例
    mosquitto_user_data_set(mosq, &publish_done);

    publishImage(topic, pathToImage);

    // 循环等待直到收到发布确认
    while(!publish_done) {
        mosquitto_loop(mosq, 100, 1);
    }

    mosquitto_lib_cleanup();
    return 0;
}

3.2 调整Mosquitto Broker配置

修改mosquitto.conf文件,调整以下参数后重启Broker:

  • message_size_limit 268435456:设置为256MB(匹配MQTT规范上限)
  • max_inflight_messages 10:提升QoS1/2的消息处理队列容量
  • max_queued_messages 100:增大Broker的消息队列,避免大消息阻塞

4. 大文件传输最佳实践

虽然单次传输大文件可行,但更推荐以下方案提升稳定性:

  • 文件分片传输:将150MB文件拆分为多个小分片(比如每片1MB),按顺序发布,订阅端接收后重组。这种方式能避免单次大消息的内存压力,还支持断点续传。
  • 添加分片标识:每个分片消息中包含总片数、当前片序号、文件唯一ID,方便订阅端校验和重组。
  • 内存优化:避免一次性加载整个大文件到内存,分块读取文件并发布,降低客户端内存占用。
  • 使用QoS1:依靠PUBACK机制保证每个分片的可靠传输,避免丢包。

5. 验证步骤

  1. 修改Mosquitto配置并重启服务
  2. 修复客户端代码,确保等待消息确认后退出
  3. 测试传输150MB文件,确认Broker和订阅端能正常接收

内容的提问来源于stack exchange,提问作者Antoni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 07:42:03