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

C++从MQTT读取字节数组写入图片报错求助

问题描述

尝试在C++中从MQTT读取图片二进制字节数组并写入对应格式(PNG/JPEG)的文件,但写入后的图片无法打开,报错:

Error interpreting JPEG image file(improper call to JPEG library in state 201)

测试用发布端Python代码

更新:按照建议使用publish.single,结果依旧。

import paho.mqtt.client as mqtt

f=open("/home/anup/Documents/img_2.jpg", "rb") # 同目录下3.7kiB的文件
fileContent = f.read()
byteArr = bytearray(fileContent)
broker_address="0.0.0.0" 
client = mqtt.Client("P1") # 创建新实例
client.connect(broker_address, 1883) # 连接到 broker
res = client.publish("in",byteArr) # 发布消息
client.loop()
print(res)
import paho.mqtt.publish as publish
publish.single("in", payload=byteArr, hostname="localhost", port=1883)

订阅端C++代码

使用aschiffler/cpp-mqtt仓库的MQTT库,通过Ninja编译:

// 引入Mosquitto MQTT库及其他标准库
#include <mqtt/client.h>  // Mosquitto客户端
#include <ostream>  // std::cout
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <fstream>


int main()
{
    // 定义broker地址(本地1883端口)
    std::string ip = "localhost:1883";
    // 定义客户端ID
    std::string id = "consumer";

    // 使用MQTT V5构造客户端
    mqtt::client client(ip, id, mqtt::create_options(MQTTVERSION_5));
    // 连接到broker
    client.connect();
    // 订阅主题"in"
    client.subscribe("in");
    // 启动消息消费循环
    client.start_consuming();

    bool running = true;
    while (running)
    {
        // 存储消息指针
        mqtt::const_message_ptr messagePointer;

        // 尝试消费消息
        if (client.try_consume_message(&messagePointer))
        {
            // 将payload转为字符串
            std::string messageString = messagePointer -> get_payload_str();
            // 打印payload到控制台(调试用)
            std::cout << messageString << std::endl;

            std::string filename = "/home/anup/Documents/mqtt/cpp-mqtt/image.jpg";
            std::ofstream outfile(filename, std::ios::binary);
            outfile.write((char*)messageString.c_str(), sizeof(messageString));
            outfile.close();

            // 收到"quit"则退出循环
            if (messageString == "quit")
            {
                running = false;
            } 
        }
    }

    return 0;
}

订阅端控制台输出(截断)

�Y,���àyPà�U���ٳ�F��!*�G9�6dD������xr��é�ì�Tm塦d��˨�TKGj��W�5��6'��nvK��W�D��۩(ځf՛��6��˲p�
                                                                                          �V�+°��?)°27M���̴I��R�������8��/;�޽���<�ì�DB�����5�u^�M�j�ò��K���U��gg��QF�/3%����MЮ��W��8_���d�0j£�"�OX�R���mm�K��K�E4H���L��
                                           ���w��F;�'���8�9�O ��
                                                                        �S)M��é���-ĜBxcP���§-� ֆ����9��+><$?�g�Rf��+a6��1R���.�
e��d��O�ù����� ��Y�_�h�.X�i�mù����W��x�9eG�v3é��T:�����1Z�
�n�����7�_�$G7���ù
W)Wn�=�R���z�è��uè�XZ*(ø�>F���$�B&��h�>�e�;Ҩ�x�d�aò�?��y��՛�è�nҕ�����5���jI�^ç��/e���a�
                                                                                        ��a�òm�N*�߀U��5.<���8z:A��ӍZ��&V§��.�IEND�Bù�

问题原因与修复

核心问题

  1. 二进制转字符串丢失数据:图片二进制数据中可能包含\0(空字符),使用get_payload_str()转为std::string时,会将\0视为字符串结束符,导致后续字节被截断,写入文件的数据不完整。
  2. 写入长度错误:sizeof(messageString)获取的是std::string对象本身的内存大小,不是存储的字节长度,导致写入的字节数错误。

修复后的C++代码

直接处理原始二进制payload,避免转字符串:

#include <mqtt/client.h>
#include <ostream>
#include <string>
#include <fstream>

int main()
{
    std::string ip = "localhost:1883";
    std::string id = "consumer";

    mqtt::client client(ip, id, mqtt::create_options(MQTTVERSION_5));
    client.connect();
    client.subscribe("in");
    client.start_consuming();

    bool running = true;
    while (running)
    {
        mqtt::const_message_ptr messagePointer;

        if (client.try_consume_message(&messagePointer))
        {
            // 获取原始二进制payload
            auto payload = messagePointer->get_payload();
            const char* data = payload.data();
            size_t data_len = payload.size();

            // 打印接收数据长度(调试用)
            std::cout << "Received data length: " << data_len << std::endl;

            std::string filename = "/home/anup/Documents/mqtt/cpp-mqtt/image.jpg";
            std::ofstream outfile(filename, std::ios::binary);
            // 写入完整二进制数据
            outfile.write(data, data_len);
            outfile.close();

            // 单独判断quit命令
            if (data_len == 4 && std::string(data, 4) == "quit")
            {
                running = false;
            }
        }
    }

    return 0;
}

修复说明

  • 使用get_payload()获取mqtt::binary类型的原始二进制数据,直接通过data()和size()访问完整字节内容,避免空字符截断问题。
  • 写入文件时使用实际数据长度data_len,确保所有字节都被写入。
  • 处理quit命令时,单独提取前4个字节转为字符串判断,不干扰二进制图片数据的处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:22:34