使用open62541的UA_Client_Service_read返回空响应求助
问题:open62541批量读取OPC UA节点返回空响应
我用C语言基于open62541库编写程序,通过OPC/UA轮询数据并转发到Kafka。单独读取每个节点值正常,但使用UA_ReadRequest批量读取指定NodeID的多个值时,仅收到空响应——返回状态码为UA_STATUSCODE_GOOD,但resultsSize为0。OPC UA服务器由Python的freeopcua库搭建。
批量读取节点的代码
void retrieveOPCData(void) { UA_ReadRequest request; UA_ReadRequest_init(&request); UA_ReadValueId ids[nodeCount]; for (int i = 0; i < nodeCount; i++) { UA_ReadValueId_init(&ids[i]); ids[i].attributeId = UA_ATTRIBUTEID_VALUE; ids[i].nodeId = nodesToRead[i]; } request.nodesToRead = ids; for (int i = 0; i < nodeCount; i++) { UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "ID%i: %s, %i", i, request.nodesToRead[i].nodeId.identifier.string.data, request.nodesToRead[i].nodeId.namespaceIndex); } UA_ReadResponse response = UA_Client_Service_read(client, request); UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Status: %i", response.responseHeader.serviceResult); UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Responses: %li", response.resultsSize); }
正常工作的单个节点读取代码
void readNodeAtIndex(int index) { if (index >= nodeCount) { UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Index out of Range"); return; } UA_Variant variant; UA_Variant_init(&variant); const UA_NodeId nodeId = nodesToRead[index]; UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeId, &variant); if (retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&variant, &UA_TYPES[UA_TYPES_DOUBLE])) { UA_Double value = *(UA_Double*)variant.data; UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Double-Value: %f", value); } else if (retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&variant, &UA_TYPES[UA_TYPES_BOOLEAN])) { UA_Boolean value = *(UA_Boolean*)variant.data; UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Boolean-Value: %i", value); } UA_Variant_clear(&variant); }
OPC UA服务器初始化代码
server = Server() space_url = "opc.tcp://localhost:61032" server.set_endpoint(space_url) server.set_security_policy([ua.SecurityPolicyType.NoSecurity]) node = server.get_objects_node()
问题原因与修复
核心问题是未设置UA_ReadRequest的nodesToReadSize字段。open62541的结构体中,所有列表类型的字段都需要同时指定指针(nodesToRead)和长度(nodesToReadSize),否则服务器无法识别要处理的节点数量,最终返回空结果。
修改后的批量读取函数如下(关键修改已标注):
void retrieveOPCData(void) { UA_ReadRequest request; UA_ReadRequest_init(&request); UA_ReadValueId ids[nodeCount]; for (int i = 0; i < nodeCount; i++) { UA_ReadValueId_init(&ids[i]); ids[i].attributeId = UA_ATTRIBUTEID_VALUE; ids[i].nodeId = nodesToRead[i]; } request.nodesToRead = ids; // 关键:设置要读取的节点数量 request.nodesToReadSize = nodeCount; for (int i = 0; i < nodeCount; i++) { UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "ID%i: %s, %i", i, request.nodesToRead[i].nodeId.identifier.string.data, request.nodesToRead[i].nodeId.namespaceIndex); } UA_ReadResponse response = UA_Client_Service_read(client, request); UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Status: %i", response.responseHeader.serviceResult); UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Responses: %li", response.resultsSize); // 补充:清理响应资源,避免内存泄漏 UA_ReadResponse_clear(&response); }
额外说明:
- 单个节点读取的
UA_Client_readValueAttribute是封装好的高层API,内部已自动处理节点数量逻辑,因此不会出现该问题。 - 调用
UA_Client_Service_read后必须用UA_ReadResponse_clear释放响应资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Sebastian
相关产品推荐
相关产品推荐

