我正在设置一个C应用程序,该应用程序应该从OPCUA服务器读取数据并将其转换为JSON消息,以便在其他地方使用.

目前OPCUA客户端的设置如下:

void setUpClient(struct ClientParameters *clientParameters, struct ClientOPCEndpointInfo* *clientInfos, int clientInfosLength)
{
    signal(SIGINT, stopHandler);

    client = UA_Client_new();
    UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
    UA_ClientConfig_setDefault(clientConfig);

    clientConfig->securityMode = UA_MESSAGESECURITYMODE_NONE;

    opcServerAddress = clientParameters->endpointUrl;

    nodeCount = clientInfosLength;

    prepareClientNodes(clientInfos);
}

数据是这样读取的:

int readOPCData(struct ClientOPCEndpointInfo* *clientInfos, char *timestamp)
{
    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 = clientNodes[i];
    }

    UA_ReadRequest_init(&request);
    request.nodesToRead = ids;
    request.nodesToReadSize = nodeCount;

    UA_ReadResponse response = UA_Client_Service_read(client, request);

    if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
    {
        logError("Error while reading OPC data from OPC server!", true);
        return 1;
    }

    UA_DateTime responseDateTime = response.responseHeader.timestamp;
    UA_Int64 responseTimestamp = UA_DateTime_toUnixTime(responseDateTime);
    sprintf(timestamp, "%li", responseTimestamp);

    for (int i = 0; i < nodeCount; i++)
    {
        UA_Variant *variant = &response.results[i].value;

        if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_DOUBLE]))
        {
            UA_Double value = *(UA_Double*)variant->data;

            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_FLOAT]))
        {
            UA_Float value = *(UA_Float*)variant->data;

            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_UINT32]))
        {
            UA_UInt32 value = *(UA_UInt32*)variant->data;

            *clientInfos[i]->value = (double)value;
        }
        else if (UA_Variant_hasScalarType(variant, &UA_TYPES[UA_TYPES_BOOLEAN]))
        {
            UA_Boolean value = *(UA_Boolean*)variant->data;

            *clientInfos[i]->value = (double)value;
        }
    }

    return 0;
}

从功能上讲,这对我的情况完全有效.但当在生产机器上运行时,该进程将在一段时间后被Ubuntu终止.我怀疑原因是可用内存有问题.

Valgrind在程序终止后报告以下问题:

==19032== 43,624 (40,320 direct, 3,304 indirect) bytes in 8 blocks are definitely lost in loss record 44 of 45
==19032==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==19032==    by 0x6A60F4: Array_decodeBinary (ua_types_encoding_binary.c:484)
==19032==    by 0x6A6ABB: decodeBinaryStructure.lto_priv.0 (ua_types_encoding_binary.c:1666)
==19032==    by 0x6B5B23: UA_decodeBinaryInternal (ua_types_encoding_binary.c:1817)
==19032==    by 0x69685D: processMSGResponse (ua_client.c:469)
==19032==    by 0x6B7A0F: UnknownInlinedFun (ua_securechannel.c:712)
==19032==    by 0x6B7A0F: UnknownInlinedFun (ua_securechannel.c:859)
==19032==    by 0x6B7A0F: UA_SecureChannel_processBuffer (ua_securechannel.c:975)
==19032==    by 0x698EB0: __Client_networkCallback (ua_client_connect.c:1489)
==19032==    by 0x6AD94E: TCP_connectionSocketCallback (eventloop_posix_tcp.c:217)
==19032==    by 0x6A142B: UA_EventLoopPOSIX_pollFDs (eventloop_posix_epoll.c:111)
==19032==    by 0x6A161B: UA_EventLoopPOSIX_run (eventloop_posix.c:287)
==19032==    by 0x699B3D: __Client_Service (ua_client.c:643)
==19032==    by 0x699C1E: __UA_Client_Service (ua_client.c:690)

这似乎是Open62541库的内部问题.但我不知道它是由我这一端的不正确使用引起的,还是由库本身的错误引起的.

编辑:更正一些拼写错误.

推荐答案

在变量离开其作用域之前,需要对变量调用相应的*_clear个清理函数(因为*_deleteMembers个函数已被弃用):

int readOPCData(struct ClientOPCEndpointInfo* *clientInfos, char *timestamp)
{
    ...

    if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
    {
        logError("Error while reading OPC data from OPC server!", true);

        UA_ReadResponse_clear(&response);
        for (int i = 0; i < nodeCount; i++)
        {
            UA_ReadValueId_clear(&ids[i]);
        }
        UA_ReadRequest_clear(&request);
        return 1;
    }

    ...

    UA_ReadResponse_clear(&response);
    for (int i = 0; i < nodeCount; i++)
    {
        UA_ReadValueId_clear(&ids[i]);
    }
    UA_ReadRequest_clear(&request);
    return 0;
}

C++相关问答推荐

错误:在.h程序中重新定义 struct

从C函数调用asm函数时生成错误的BLX指令(STM32H753上的gcc)

需要大整数和浮点数.使用long long int和long double

两个连续的语句是否按顺序排列?

C编译器是否遵循restrict的正式定义?

在编译时参数化类型定义

如何使用指向 struct 数组的指针并访问数组中特定索引处的 struct

将返回的char*设置为S在函数中定义的字符串文字可能会产生什么问题?

如何在提取的索引中分配空值?

为什么Fread()函数会读取内容,然后光标会跳到随机位置?

如何使这个While循环在新行上结束

如何使用空元素块声明指针数组

为什么我无法访问C语言中的文件

为什么我在我的代码中得到错误和退出代码-1073741819(0xC0000005),但如果我添加了一个不相关的打印语句,它仍然有效?

x86-64平台上的int_fast8_t大小与int_fast16_t大小

gdb - 你能找到持有内部 glibc 锁的线程吗?

C 和 C++ 标准如何告诉您如何处理它们未涵盖的情况?

既然我们在 if 中将 int 的值更改为 10,为什么在第二个 fork 后,子进程及其创建的子进程都会打印 33 ?

为什么<到达*时不会转换为>?

Linux memcpy 限制关键字语法