配置与创建 (C)
C SDK 用 结构体 + 函数 替代 C# 的多重载构造函数. 流程:
- 声明
DarraUa_SessionConfig cfg; - 调
DarraUa_SessionConfig_Init(&cfg)填默认值 - 覆写需要修改的字段
- 调
DarraUa_Session_Create(&cfg, &handle)创建句柄 - 用完调
DarraUa_Session_Close(handle)释放
前置阅读
- 加密参数 (SecurityMode / 证书) 见 Security 加密.
- 服务端预扫描见 Discovery.
- 连上后的操作见 Connect / Disconnect.
DarraUa_SessionConfig 字段详解
typedef struct {
const char* endpoint_url;
DarraUa_MessageSecurityMode security_mode;
const char* security_policy_uri;
DarraUa_UserTokenType user_token_type;
const char* username;
const char* password;
const char* client_cert_path;
const char* client_key_path;
const char* server_cert_path;
uint32_t session_timeout_ms;
uint32_t connect_timeout_ms;
uint32_t request_timeout_ms;
uint32_t keepalive_interval_ms;
uint32_t auto_reconnect;
uint32_t reconnect_max_retries;
uint32_t reconnect_delay_ms;
} DarraUa_SessionConfig;
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| 必填 | endpoint_url | const char* | in | UTF-8, opc.tcp://host:port. 字符串内存由调用方管理, 必须在 Connect 之前保持有效 |
| 安全 | security_mode | DarraUa_MessageSecurityMode | in | 默认 NONE |
security_policy_uri | const char* | in | 默认 #None; 推荐 #Basic256Sha256 | |
client_cert_path | const char* | in | 客户端 PFX (Sign / SignAndEncrypt 必填) | |
client_key_path | const char* | in | PFX 密码 (字段复用) | |
server_cert_path | const char* | in | 服务端 DER, NULL = TOFU | |
| 登录 | user_token_type | DarraUa_UserTokenType | in | 默认 ANONYMOUS |
username | const char* | in | user_token_type=USERNAME 时必填 | |
password | const char* | in | 配 username 用 | |
| 超时 | session_timeout_ms | uint32_t | in | 服务端 Session 超时, 默认 600000 (10 分钟) |
connect_timeout_ms | uint32_t | in | 建链超时, 默认 10000 | |
request_timeout_ms | uint32_t | in | 单 RPC 超时, 默认 10000 | |
keepalive_interval_ms | uint32_t | in | 心跳周期, 默认 10000, 0 = 禁用 | |
| 重连 | auto_reconnect | uint32_t | in | 1 = 启用 (默认), 0 = 不重连 |
reconnect_max_retries | uint32_t | in | 默认 3 | |
reconnect_delay_ms | uint32_t | in | 默认 2000 |
DarraUa_MessageSecurityMode
typedef enum {
DARRA_UA_MSG_SECURITY_MODE_INVALID = 0,
DARRA_UA_MSG_SECURITY_MODE_NONE = 1,
DARRA_UA_MSG_SECURITY_MODE_SIGN = 2,
DARRA_UA_MSG_SECURITY_MODE_SIGN_ENCRYPT = 3
} DarraUa_MessageSecurityMode;
DarraUa_UserTokenType
typedef enum {
DARRA_UA_USER_TOKEN_ANONYMOUS = 0,
DARRA_UA_USER_TOKEN_USERNAME = 1,
DARRA_UA_USER_TOKEN_CERTIFICATE = 2,
DARRA_UA_USER_TOKEN_ISSUED = 3
} DarraUa_UserTokenType;
常用 SecurityPolicy URI
| 模式 | URI |
|---|---|
| 无加密 | http://opcfoundation.org/UA/SecurityPolicy#None |
| Basic256Sha256 (推荐) | http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256 |
| Aes128_Sha256_RsaOaep | http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep |
| Aes256_Sha256_RsaPss | http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss |
DarraUa_Session_Create
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_Create(
const DarraUa_SessionConfig* cfg,
DarraUa_SessionHandle* out_handle);
| 参数 | 说明 |
|---|---|
cfg | 已 Init + 覆写的配置 |
out_handle | 出参, 成功后写入有效句柄, 失败置 0 |
| 返回 | 含义 |
|---|---|
DARRA_UA_STATUS_GOOD | 成功 |
DARRA_UA_STATUS_INVALID_ARGUMENT | cfg=NULL 或 endpoint_url=NULL |
DARRA_UA_STATUS_NOT_INITIALIZED | 没先调 DarraUa_Initialize() |
DARRA_UA_STATUS_OUT_OF_MEMORY | 内部分配失败 |
DARRA_UA_STATUS_BAD_TCP_ENDPOINT_URL_INVALID | URL 格式不对 |
_Create 只是创建本地上下文, 不发起任何网络请求. 真正联网发生在 _Connect.
三种典型配置示例
#include <darra_opcua/darra_opcua.h>
#include <stdio.h>
/* 1. 匿名 + 明文 (开发期) */
static int demo_anonymous_no_security(const char* endpoint)
{
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_Status st = DarraUa_Session_Create(&cfg, &h);
if (!DARRA_UA_STATUS_IS_GOOD(st)) {
fprintf(stderr, "Create failed: 0x%08X (%s)\n",
(unsigned)st, DarraUa_StatusName(st));
return -1;
}
DarraUa_Session_Close(h);
return 0;
}
/* 2. 匿名 + Sign (内网生产) */
static int demo_anonymous_sign(const char* endpoint, const char* pfx)
{
DarraUa_SessionConfig cfg;
DarraUa_SessionConfig_Init(&cfg);
cfg.endpoint_url = endpoint;
cfg.security_mode = DARRA_UA_MSG_SECURITY_MODE_SIGN;
cfg.security_policy_uri = "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256";
cfg.user_token_type = DARRA_UA_USER_TOKEN_ANONYMOUS;
cfg.client_cert_path = pfx;
cfg.client_key_path = "123456";
DarraUa_SessionHandle h = DARRA_UA_INVALID_SESSION_HANDLE;
if (!DARRA_UA_STATUS_IS_GOOD(DarraUa_Session_Create(&cfg, &h))) return -1;
DarraUa_Session_Close(h);
return 0;
}
/* 3. 用户名 + SignAndEncrypt (典型生产) */
static int demo_username_sign_encrypt(const char* endpoint, const char* pfx,
const char* user, const char* pass)
{
DarraUa_SessionConfig cfg;
DarraUa_SessionConfig_Init(&cfg);
cfg.endpoint_url = endpoint;
cfg.security_mode = DARRA_UA_MSG_SECURITY_MODE_SIGN_ENCRYPT;
cfg.security_policy_uri = "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256";
cfg.user_token_type = DARRA_UA_USER_TOKEN_USERNAME;
cfg.username = user;
cfg.password = pass;
cfg.client_cert_path = pfx;
cfg.client_key_path = "123456";
cfg.session_timeout_ms = 1800000; /* 30 分钟 */
cfg.keepalive_interval_ms = 5000; /* 5 秒, 更敏感的断线检测 */
DarraUa_SessionHandle h = DARRA_UA_INVALID_SESSION_HANDLE;
if (!DARRA_UA_STATUS_IS_GOOD(DarraUa_Session_Create(&cfg, &h))) return -1;
DarraUa_Session_Close(h);
return 0;
}
常见坑
- 未调
DarraUa_SessionConfig_Init: 字段含未定义值, Connect 时大概率BadConfigurationError endpoint_url字符串过早释放: 字符串 lifetime 必须覆盖整个 Session 生命周期 (Stack 不会拷贝)- 客户端证书路径含中文 / 空格: 路径一律用 ASCII
- 重连参数太激进:
reconnect_max_retries太大 + 网络抖动会无限重连, 建议 ≤ 5
资源管理
句柄必须用 DarraUa_Session_Close(h) 关闭, 否则 native 上下文泄漏:
DarraUa_SessionHandle h = DARRA_UA_INVALID_SESSION_HANDLE;
DarraUa_Status st = DarraUa_Session_Create(&cfg, &h);
if (!DARRA_UA_STATUS_IS_GOOD(st)) goto cleanup;
st = DarraUa_Session_Connect(h);
/* ... 业务 ... */
DarraUa_Session_Disconnect(h); /* 可选, Close 内部会先 Disconnect */
cleanup:
if (h != DARRA_UA_INVALID_SESSION_HANDLE) {
DarraUa_Session_Close(h);
}