跳到主要内容

Darra OPC UA Client — C SDK

Darra OPC UA Client 协议栈最底层的对外接口, 也是 C# / Java / Python / C++ / Rust 五种语言绑定的共同基座. 与其他语言不同, C 用户没有 wrapper class — 直接 #include <darra_opcua/darra_opcua.h>, 调用 DarraUa_* 系列 C ABI 函数即可.

章节导航

安装

cmake_minimum_required(VERSION 3.16)
project(my_opcua_app C)

set(CMAKE_C_STANDARD 99)

set(DARRA_STACK_ROOT "/path/to/Darra_OPCUA_Stack")
add_executable(my_app main.c)
target_include_directories(my_app PRIVATE "${DARRA_STACK_ROOT}/include")
target_link_directories(my_app PRIVATE "${DARRA_STACK_ROOT}/build")

if(WIN32)
target_link_libraries(my_app PRIVATE Darra.OpcUa.Core)
else()
target_link_libraries(my_app PRIVATE darra_opcua)
endif()

系统要求

要求
CompilerC99+ (GCC 8+, Clang 10+, MSVC 2019+)
OSWindows 10/11, Linux (Ubuntu 20.04+), macOS 11+
平台x64
协议OPC UA TCP (opc.tcp://)
Darra.OpcUa.Core.dll (Windows) / libdarra_opcua.so (Linux)

头文件

主入口只有一个: <darra_opcua/darra_opcua.h>, 它已经包含 status / types / session / subscribe 子头. 历史与事件订阅按需加:

#include <darra_opcua/darra_opcua.h>            /* Session + Browse + Subscription */
#include <darra_opcua/darra_opcua_history.h> /* HistoryRead / HistoryUpdate */
#include <darra_opcua/darra_opcua_event.h> /* Event 订阅 (Alarms & Conditions) */

主要类型:

类型用途
DarraUa_SessionHandle会话句柄 (uint32_t, 0 = 非法)
DarraUa_SubscriptionHandle订阅句柄
DarraUa_MonitoredItemHandleMonitoredItem 句柄
DarraUa_Variant*通用值容器 (opaque)
DarraUa_DataValue*Read 返回的完整值 (opaque)
DarraUa_BrowseResult*Browse 返回的子节点列表 (opaque)
DarraUa_StatusStatusCode (uint32_t, 0 = Good)
DarraUa_NodeClass / DarraUa_AttributeIdOPC UA 枚举

跨平台 sleep 宏

C99 没有标准 sleep, 跨平台 demo 一律放这段在文件顶部:

#if defined(_WIN32)
# include <windows.h>
# define OPCUA_SLEEP_MS(ms) Sleep(ms)
# define OPCUA_SLEEP_SEC(s) Sleep((s) * 1000)
#else
# include <unistd.h>
# define OPCUA_SLEEP_MS(ms) usleep((ms) * 1000)
# define OPCUA_SLEEP_SEC(s) sleep(s)
#endif

一分钟快速开始

#include <darra_opcua/darra_opcua.h>
#include <stdio.h>

int main(int argc, char** argv)
{
const char* endpoint = (argc >= 2) ? argv[1] : "opc.tcp://localhost:4840";

/* 1. 库初始化 */
DarraUa_Initialize();

/* 2. 配置 + 创建 Session */
DarraUa_SessionConfig cfg;
DarraUa_SessionConfig_Init(&cfg);
cfg.endpoint_url = endpoint;
cfg.security_mode = DARRA_UA_MSG_SECURITY_MODE_NONE;
cfg.security_policy_uri = "http://opcfoundation.org/UA/SecurityPolicy#None";
cfg.user_token_type = DARRA_UA_USER_TOKEN_ANONYMOUS;

DarraUa_SessionHandle h = DARRA_UA_INVALID_SESSION_HANDLE;
DarraUa_Session_Create(&cfg, &h);
DarraUa_Session_Connect(h);

/* 3. 读 ServerStatus.CurrentTime */
DarraUa_Status st = 0;
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, "i=2258", DARRA_UA_ATTR_VALUE, &st);
if (dv && DARRA_UA_STATUS_IS_GOOD(st)) {
const DarraUa_Variant* v = DarraUa_DataValue_GetValue(dv);
DarraUa_DateTime ft = DarraUa_Variant_GetDateTime(v);
printf("CurrentTime ft=%lld\n", (long long)ft);
DarraUa_DataValue_Delete(dv);
}

/* 4. 反向清理 */
DarraUa_Session_Disconnect(h);
DarraUa_Session_Close(h);
DarraUa_Shutdown();
return 0;
}

高级 API 概览

功能入口 API说明
库初始化 / 卸载DarraUa_Initialize / DarraUa_Shutdown进程级, 内部引用计数
创建会话DarraUa_Session_Create(&cfg, &h)不连接
连接 / 断开DarraUa_Session_Connect / Disconnect / CloseNone / Sign / SignAndEncrypt + Username / Anonymous
单点读写DarraUa_Session_ReadNode / WriteNode字符串 NodeId 便捷 API
批量读DarraUa_Session_ReadNodes / Read一次 RPC, N 节点
浏览DarraUa_Session_BrowseNode / Browse / BrowseNodes / BrowseNext含分页支持
路径解析DarraUa_Session_TranslateBrowsePaths / ResolveBrowsePath浏览路径 → NodeId
注册节点DarraUa_Session_RegisterNodes / UnregisterNodes高频访问加速
数据订阅DarraUa_Subscription_Create + _AddNode / _AddNodespublishing / sampling 双层
事件订阅DarraUa_Event_AddItem (darra_opcua_event.h)报警 & 条件
调方法DarraUa_Session_Call(...)OPC UA Method 节点
历史读DarraUa_Session_HistoryReadRaw / Modified / AtTime / Processed / Events5 模式
历史写DarraUa_Session_HistoryUpdateData / HistoryDeleteRangeInsert / Replace / Update / Remove
心跳cfg.keepalive_interval_ms后台周期探测
自动重连cfg.auto_reconnect = 1检测断线 → 重连
服务发现DarraUa_Discovery_GetEndpoints / FindServers不需要 Session
命名空间DarraUa_Session_GetNamespaceUri / FindNamespaceIndex防 ns 漂移

内存所有权

C 没有 RAII / GC, 所有"返回堆对象"的 API 都需要调用对应的 _Delete. 谁分配谁释放, Stack 分配的对象用 Stack 提供的 _Delete 释放, 切勿混用 free() (跨 DLL CRT 不一致会崩).

分配释放
DarraUa_Variant_New()DarraUa_Variant_Delete(v)
DarraUa_Session_ReadNode(...)DarraUa_DataValue_Delete(dv)
DarraUa_Session_BrowseNode(...)DarraUa_BrowseResult_Delete(br)
DarraUa_Session_HistoryReadRaw(...)DarraUa_DataValueArray_Delete(arr, count)
DarraUa_Session_HistoryReadEvents(...)DarraUa_EventArray_Delete(arr, count)
DarraUa_Session_Call(...)DarraUa_VariantArray_Delete(arr, count)
DarraUa_Discovery_GetEndpoints(...)DarraUa_GetEndpointsResult_Delete(r)
DarraUa_Session_TranslateBrowsePaths(...) 单项DarraUa_Free(out_node_ids[i])
Stack 内部 malloc 的"裸缓冲区"DarraUa_Free(p)

句柄 (uint32_t) 由 Stack pool 管理, 不要 free():

句柄关闭
DarraUa_SessionHandleDarraUa_Session_Close(h)
DarraUa_SubscriptionHandleDarraUa_Subscription_Delete(sub)
DarraUa_MonitoredItemHandleDarraUa_MonitoredItem_Delete(sub, mi)

错误处理模板

C 没有异常, 每个 API 都返回 DarraUa_Status:

DarraUa_Status st = DarraUa_Session_Connect(h);
if (!DARRA_UA_STATUS_IS_GOOD(st)) {
fprintf(stderr, "connect failed: 0x%08X (%s)\n",
(unsigned)st, DarraUa_StatusName(st));
/* 走 cleanup goto label */
}

线程模型与回调

  • 所有 DarraUa_* API 线程安全 (内部加锁), 可在多线程并发调用同一会话
  • 订阅 / 事件回调由 Stack 内部线程池触发, 与调用线程不同
  • 手动 pump 模式下 (调 DarraUa_Session_Publish), 回调在调用 Publish 的线程触发
  • DarraUa_Session_StartAutoPublish(h) 让 SDK 后台线程持续 Publish
  • 回调里访问跨线程共享数据务必加锁 / 用原子, 不要做长时间计算或阻塞 IO

跨语言对齐

C SDK 暴露的函数与 C# SDK 一一对应, C# ua.Read("ns=2;s=X") 等价于 C DarraUa_Session_ReadNode(handle, "ns=2;s=X", attr, &status). 概念性内容 (协议 / 行为) 请优先参考 C# 文档, C 文档只强调 C 特有的内存所有权和回调线程语义.

操作C# (DarraOpcUa)C
库初始化(隐式)DarraUa_Initialize()
创建会话new DarraOpcUa(url)DarraUa_Session_Create(&cfg, &h)
连接ua.Connect()DarraUa_Session_Connect(h)
读单节点ua.Read("i=2258")DarraUa_Session_ReadNode(h, "i=2258", attr, &st)
写单节点ua.Write(id, v)DarraUa_Session_WriteNode(h, id, attr, v)
浏览ua.Browse("i=84")DarraUa_Session_BrowseNode(h, "i=84", filter, &res)
创建订阅ua.CreateSubscription(500)DarraUa_Subscription_Create(h, &cfg, &sub)
订阅一节点sub.Add("i=2258")DarraUa_Subscription_AddNode(sub, "i=2258", attr, smpl, cb, ctx, &mi)
Pumpua.Publish(2000)DarraUa_Session_Publish(h, 2000)
销毁using var uaDarraUa_Session_Close(h)

按左侧侧边栏顺序读完即可掌握全部 C ABI.