有时候需要把OPCUA Server集成到已有工程中来,对于open62541,我们一般使用UA_Server_run()去运行server,但是这个函数是个循环执行,会阻塞当前工程,那么就会有2种办法。
方法1 使用线程
单独开启一个线程去运行OPCUA Server,这个比较简单,不再细说
方法2 拆开运行
假设现有工程是使用定时器运行,例如reactor模式,那么就需要把UA_Server_run()拆开运行,下面是个简单的定时运行代码,
#include <signal.h>
#include <sys/timerfd.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include "open62541.h"
UA_Boolean running = true;
static void stopHandler(int sign)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
running = false;
}
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(void)
{
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
UA_Server *server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_Server_run_startup(server);
int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (timerfd == -1)
{
handle_error("timerfd_create");
}
struct itimerspec new_value = {};
new_value.it_value.tv_sec = 0;
new_value.it_value.tv_nsec = 30000000; // 30ms
new_value.it_interval.tv_sec = 0;
new_value.it_interval.tv_nsec = 30000000; // 30ms
if (timerfd_settime(timerfd, 0, &new_value, NULL) == -1)
{
handle_error("timerfd_settime");
}
printf("timer started\n");
uint64_t exp = 0;
while (running)
{
int ret = read(timerfd, &exp, sizeof(uint64_t));
if (ret == sizeof(uint64_t)) // 每30ms条件为真
{
// do other things
UA_Server_run_iterate(server, false);
}
}
UA_StatusCode retval = UA_Server_run_shutdown(server);
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
拆开运行,可以更好的与现有工程融合在一起。
编译运行后,使用UaExpert连接,连接OK