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

Azure IoT Hub直连方法Payload尾部出现乱码的问题排查

问题描述

树莓派上运行的Azure IoT直连方法模块,调用start-transaction方法时,打印的Payload尾部附加了乱码767733。模块使用Azure C SDK,基于MQTT over WebSockets通信。

执行的调用命令:

az iot hub invoke-module-method --device-id raspi --module-id raspiNayax --method-name start-transaction --hub-name dcfcdev --method-payload '{"deviceId":"pedestal1","type":"start-transaction","timestamp":"2024-06-07T04:13:21.9172154Z","sequenceId":"1ABC","parameters":[{"name":"connectorOcppNumber","value":5},{"name":"productCode","value":2},{"name":"productPrice","value":"test1"}]}'

设备打印输出:

Method name: start-transaction, Payload: {"deviceId":"pedestal1","type":"start-transaction","timestamp":"2024-06-07T04:13:21.9172154Z","sequenceId":"1ABC","parameters":[{"name":"connectorOcppNumber","value":5},{"name":"productCode","value":2},{"name":"productPrice","value":"test1"}]}**767733**

设备端直连方法处理代码:

int DirectMethodCb(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback)
{   
char deviceMethodResponse[MAX_RESPONSE_LENGTH];  
int responseCode  = 400; 

    printf("+++++++++++++ Direct method call received +++++++++++++\n");
__log_ts("Azure Direct Method Received \n Method name: %s, Payload: %s\n", method_name, payload);  

if(strcmp("is-ready", method_name) == 0){
    __log_ts("Direct method: is-ready\n");

    responseCode = payload_parser(payload, IS_READY); 
    strcpy(deviceMethodResponse, "{}");

}else if(strcmp("is-available", method_name) == 0){
    __log_ts("Direct method: is-available\n");
    
    responseCode = payload_parser(payload, IS_AVAILABLE); 
    responseCode = get_current_session(IS_AVAILABLE); 

    strcpy(deviceMethodResponse, "{}");

}else if(strcmp("start-transaction", method_name) == 0){
    __log_ts("Direct method: start-transaction\n");

    responseCode = start_transaction_handler(payload); 
    strcpy(deviceMethodResponse, "{}");

}else if(strcmp("close-transaction", method_name) == 0){
    __log_ts("Direct method: close-transaction\n");

    // responseCode = payload_parser(payload, CLOSE_TRANSACTION); 
    responseCode = close_cancel_session_handler(payload, CLOSE_TRANSACTION);
    strcpy(deviceMethodResponse, "{}");

}else if(strcmp("cancel-transaction", method_name) == 0){
    __log_ts("Direct method: cancel-transaction\n");

    // responseCode = cancel_session_handler(payload); 
    responseCode = close_cancel_session_handler(payload, CANCEL_TRANSACTION); 
    strcpy(deviceMethodResponse, "{}");

}else{
    responseCode = 700; 
    strcpy(deviceMethodResponse, "{}");
}

*resp_size = strlen(deviceMethodResponse);
*response = malloc(*resp_size + 1); // Allocate an extra byte for the null-terminator
strncpy((char *)*response, deviceMethodResponse, *resp_size); // Use strncpy to copy the string
(*response)[*resp_size] = '\0';
__log_ts("Azure Direct Method to method call:%s\n Response Code: %d, Response Payload: %s\n", method_name, responseCode, deviceMethodResponse); 

fflush(NULL);
return responseCode;
}

void *init_az_service(void *arg) {
IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle = NULL;
int retval = 1;

do{
    printf("\n\n=======================\n");

    fflush(NULL);

    srand((unsigned int)time(NULL));
    
    // Ensuring platform is initialized. 
    if (0 != IoTHub_Init())
    {

        // printf("Failed to initialize the platform.");
        __log_ts("Failed to initialize the platform.\n");

        break;
    }

    // |** Establish MQTT protocol. **| 
    iotHubModuleClientHandle = IoTHubModuleClient_LL_CreateFromEnvironment(MQTT_Protocol);
    if (NULL == iotHubModuleClientHandle)
    {
        // printf("IoTHubModuleClient_LL_CreateFromEnvironment failed");
        __log_ts("IoTHubModuleClient_LL_CreateFromEnvironment failed\n");
        break;
    }

    // Setting up the Direct Method Callback function. 
    IOTHUB_CLIENT_RESULT result = IoTHubModuleClient_LL_SetModuleMethodCallback(iotHubModuleClientHandle, DirectMethodCb, iotHubModuleClientHandle);
    if (IOTHUB_CLIENT_OK != result)
    {
        // printf("IoTHubModuleClient_SetModuleMethodCallback failed: %d", result);
        __log_ts("IoTHubModuleClient_SetModuleMethodCallback failed: %d\n", result);
        break;
    }


while (true)
{
    IoTHubModuleClient_LL_DoWork(iotHubModuleClientHandle);
    ThreadAPI_Sleep(100);
}

}while(false); 

// Destroy iotHubModuleClientHandle if function errored out. 
if (NULL != iotHubModuleClientHandle)
{
    IoTHubModuleClient_LL_Destroy(iotHubModuleClientHandle);
}
IoTHub_Deinit();

return retval;
}
原因分析

问题核心是Azure C SDK传递的payload是无空终止符的二进制数据。SDK通过unsigned char* payload和size_t size参数传递内容,不会自动添加C字符串要求的\0结尾。而你用%s格式符打印时,printf会持续读取内存直到遇到\0,缓冲区后的随机内存内容(即乱码767733)就被一并输出了。

解决方案

提供两种修复方式,可任选其一:

方式1:打印时限制读取长度

直接在日志打印中指定Payload的实际长度,避免越界读取:

// 替换原日志打印行
__log_ts("Azure Direct Method Received \n Method name: %s, Payload: %.*s\n", method_name, (int)size, payload);

%.*s格式符中,*表示用后续的(int)size作为字符串的最大读取长度,只会读取size字节的有效内容,不会读取缓冲区外的乱码。

方式2:转换为带空终止符的C字符串

将Payload复制到带空终止符的缓冲区,后续所有操作使用该缓冲区:

// 在DirectMethodCb函数开头添加
char* payload_str = malloc(size + 1);
if (payload_str != NULL) {
    memcpy(payload_str, payload, size);
    payload_str[size] = '\0'; // 手动添加空终止符

    // 用payload_str替代原payload进行打印
    __log_ts("Azure Direct Method Received \n Method name: %s, Payload: %s\n", method_name, payload_str);

    // 后续处理函数(如start_transaction_handler)也使用payload_str
    responseCode = start_transaction_handler((const unsigned char*)payload_str);

    // 使用完毕释放内存
    free(payload_str);
} else {
    __log_ts("Failed to allocate memory for payload string\n");
}

如果后续的Payload处理函数也依赖空终止符,这种方式更彻底。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 08:13:15