OPC-UA open62541 sdk динамически добавляет переменные узлы после запуска сервера

#c #opc-ua #open62541

#c #opc-ua #open62541

Вопрос:

Читая документацию и примеры OPC-UA foundation и OPC-UA open62541 sdk, переменные узлы всегда добавляются перед инструкцией для запуска запуска сервера. Возможно ли добавить их после запуска сервера? Если я изменю порядок инструкций, это не сработает.

Подумайте вместе со мной о следующей ситуации: мне нужно выполнить несколько http-запросов, как только мы начнем асинхронный запуск приложения / программного обеспечения (не сервера). Затем сервер запускается, после выполнения моего http-запроса я добавил переменные узлы на основе информации, возвращенной из Интернета.

Я добавил несколько комментариев к коду, чтобы пояснить, что я пытаюсь сделать.

 int main() {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    UA_ServerConfig *config = UA_ServerConfig_new_default();
    UA_Server *server = UA_Server_new(config);

    // If I put this statement after the other statement:
    // UA_StatusCode retval = UA_Server_run(server, amp;running);
    // The variables are not added.
    addVariable(server);

    // I would like to add some variables nodes after this statement, 
    // for example, like I said I request some information online 
    // and I will add the nodes after return from this request asynchronous.
    UA_StatusCode retval = UA_Server_run(server, amp;running);
    UA_Server_delete(server);
    UA_ServerConfig_delete(config);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
  

Ответ №1:

Да, это возможно с помощью UA_Server_addVariableNode , поскольку вы уже используете его (вероятно) в addVariable() . Я предполагаю, что ваш код основан на https://github.com/open62541/open62541/blob/master/examples/tutorial_server_variable.c

Простое изменение порядка кода не работает, поскольку

 UA_StatusCode retval = UA_Server_run(server, amp;running);
  

блокируется.

Вам нужно изменить это, чтобы использовать итеративный подход:

 UA_StatusCode retval = UA_Server_run_startup(server);
if(retval != UA_STATUSCODE_GOOD)
   return 1;

while(running) {
    UA_UInt16 timeout = UA_Server_run_iterate(server, waitInternal);

    // HERE you can add any node to the server you like.
    // e.g. call addVariable2().
    // Make sure that you only call it once in the loop.

    struct timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = timeout * 1000;
    select(0, NULL, NULL, NULL, amp;tv);
}
retval = UA_Server_run_shutdown(server);
  

Обратите внимание, что open62541 в настоящее время не поддерживает многопоточность. Если вы добавляете переменные в другом потоке, вам нужно убедиться, что вы мьютексируете доступ к server объекту.

Приведенный выше пример основан на:https://github.com/open62541/open62541/blob/master/examples/server_mainloop.c

Другой подход заключается в том, чтобы просто запустить другой поток, который обрабатывает ваши асинхронные запросы, а затем вызывает UA_Server_addVariableNode в отдельном потоке. По-прежнему убедитесь, что вы используете мьютексы.

Комментарии:

1. Большое вам спасибо @Stefan Profanter. Это было именно то, что я хотел сделать, и да, ваше предположение было правильным относительно того, на чем основан мой код. У меня все еще есть еще один вопрос? В моем случае я жду выполнения задачи в другом потоке, прежде чем продолжить выполнение программы. Потому что сначала мне нужны эти данные, прежде чем выполнять другие запросы для поиска дополнительных данных. Это нормально для сервера? Я знаю, что если бы было приложение с графическим интерфейсом, я бы заблокировал, если бы я ждал потока, но что в этом случае?

2. В общем, вы можете блокировать (или, лучше сказать, не вызывать UA_Server_run_iterate ) столько, сколько захотите. Сам сервер может справиться с этим довольно хорошо. Единственная проблема, с которой вы столкнетесь, заключается в том, что сервер также не отвечает на сетевые сообщения, например, если клиент пытается подключиться. Или также, если у клиента активная подписка, это не будет обработано до тех пор, пока вы снова не вызовете _iterate. Рекомендуется периодически вызывать это.

3. Спасибо за подробное объяснение @Stefan Profanter

Ответ №2:

Возможно, есть решение, но оно должно быть запущено клиентом OPC UA.

Спецификация OPC UA определяет некоторые службы, позволяющие клиенту добавлять / удалять узлы или ссылки ( AddNodes , AddRefererences , DeleteNodes , DeleteReferences )

Как ваш клиент OPC UA, так и сервер должны поддерживать эти службы.