1. OPC UA 服务器基础搭建

任务目标

在网关设备(以 Ubuntu 22.04 x64 为例)上安装并配置一个 OPC UA 服务器,使其能够启动并接受客户端连接。本案例使用开源实现 open62541,通过编译内置示例服务器并修改监听端口,完成最小可验证的服务器搭建。

环境与依赖

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • 编译工具:gcc、cmake(≥3.10)、git
  • 依赖库:无需额外第三方库,open62541 编译时自动处理
sudo apt update
sudo apt install -y gcc cmake git

实现步骤

open62541 提供单文件发行版(open62541.c + open62541.h),可直接编译运行,无需完整源码树。以下步骤下载单文件版本并编写服务器启动代码。

# 下载 open62541 单文件版本(v1.3)
wget https://github.com/open62541/open62541/releases/download/v1.3.10/open62541-linux64.tar.gz
tar -xzf open62541-linux64.tar.gz
# 解压后得到 open62541.h 和 open62541.c

服务器代码

创建 server.c,实现一个监听端口可配置的 OPC UA 服务器。服务器启动后创建默认对象节点,并持续运行直到收到中断信号。

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <open62541.h>

static UA_Boolean running = true;

static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "收到信号 %d,正在停止服务器...", sig);
    running = false;
}

int main(int argc, char** argv) {
    uint16_t port = 4840;  // 默认端口
    if (argc > 1) {
        port = (uint16_t)atoi(argv[1]);
        if (port == 0) {
            fprintf(stderr, "无效端口号: %s\n", argv[1]);
            return 1;
        }
    }

    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    UA_Server *server = UA_Server_new();
    UA_ServerConfig *config = UA_Server_getConfig(server);
    UA_ServerConfig_setMinimal(config, port, NULL);

    UA_StatusCode retval = UA_Server_run(server, &running);
    if (retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "服务器运行失败,错误码: 0x%08X", retval);
        UA_Server_delete(server);
        return 1;
    }

    UA_Server_delete(server);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "服务器已正常退出");
    return 0;
}

编译与运行

# 编译(与 open62541.c 一起编译)
gcc -std=c99 -O2 server.c open62541.c -o ua_server -lm

# 启动服务器(默认端口 4840)
./ua_server

# 指定端口启动(例如 16664)
./ua_server 16664

验证方法

服务器启动后,使用 OPC UA 客户端工具连接验证。推荐使用 UaExpert(图形化)或 opcua-client 命令行工具。以下为命令行验证方式:

# 安装 python 客户端库(用于快速验证)
pip install opcua

# 连接测试脚本(保存为 test_client.py)
from opcua import Client

client = Client("opc.tcp://127.0.0.1:4840")
try:
    client.connect()
    print("连接成功,服务器名称:", client.get_server_node().get_child("0:Server").get_value())
finally:
    client.disconnect()
python3 test_client.py

通过条件:服务器控制台输出监听启动日志,客户端脚本打印 连接成功 且无异常抛出。若使用 UaExpert,在地址栏输入 opc.tcp://127.0.0.1:4840,双击服务器节点可浏览到 Objects 文件夹即表示连接正常。

常见问题

  • 端口被占用:启动时提示 bind: Address already in use,更换端口或使用 ss -tlnp | grep 4840 查找占用进程。
  • 防火墙拦截:若客户端从其他机器连接,需放行对应端口:sudo ufw allow 4840/tcp。
  • 编译警告:忽略 deprecated 相关警告不影响运行,如需消除可添加 -Wno-deprecated-declarations 编译选项。