通过 MQTT / mosquitto 发送大文件 - 限制为 4MB

问题描述 投票:0回答:2

我的目标是能够通过

mosquitto
发送大约 150MB 的文件。这种转移的效率问题目前并不重要,只是看看这样的转移是否可能。

MQTT 规范提到消息有效负载限制为 256MB,但我只能发送最大为 4095KB 的文件,仅此而已。发布器是用 C mosquitto 库实现的,动态分配带有二进制数据的向量。发布者程序不会出现任何错误,但是在客户端发布数据后,如果发送的文件大于4065KB,则代理端不会出现发布通知,

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.

真的可以通过

mosquitto
发送那些大文件吗?如果是这样,实施方面的最佳实践是什么?

编辑:附加文件源代码

#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;
}

EDIT2:成功发布的日志输出(小文件)

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文件。对于 4000KB 左右的文件,QoS0 的可靠性不如 QoS1。

c mqtt mosquitto
2个回答
3
投票

这里正确的解决方案可能是在

mosquitto_loop_stop()
 之前使用 
mosquitto_lib_cleanup()

正如文档所解释的,这应该等待未完成的消息发送后再退出。

这是线程客户端界面的一部分。调用一次以停止先前使用 mosquitto_loop_start 创建的网络线程。此调用将阻塞,直到网络线程完成。

文档:https://mosquitto.org/api/files/mosquitto-h.html#mosquitto_loop_stop


0
投票

mosquitto_lib_cleanup
之前添加超时是解决方案。似乎在大型有效负载场景中,网络堆栈无法在清理调用之前处理整个有效负载。可能非阻塞循环(mosquitto 循环是用
mosquitto_start
启动的)根本没有等待包通过管道传输到网络中。

© www.soinside.com 2019 - 2024. All rights reserved.