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
相关产品推荐
相关产品推荐

