跳到主要内容

订阅自恢复

概述

Session 重连后, 服务端 Subscription 可能仍存活也可能已被清理。SDK 两步走:

  1. TransferSubscriptions — 把旧 SubscriptionId 转给新 Session
  2. Recreate — 失败时, 按缓存重建 Sub + 全部 MI

业务侧无需手动处理。

API

函数 / 回调类别读写说明
DarraUa_Session_TransferSubscriptions(ua, old_sub_ids, n, send_initial_values, &out_results)方法转移订阅
DarraUa_RegisterSubLostHandler(ua, cb, ctx)事件订阅丢失
DarraUa_RegisterSubRestoredHandler(ua, cb, ctx)事件订阅恢复

代码示例

#include <opcua.h>

void on_lost(const DarraUa_EventEntry* e, void* ctx) {
fprintf(stderr, "订阅丢失: sub_id=%s\n", e->source);
}
void on_restored(const DarraUa_EventEntry* e, void* ctx) {
printf("订阅已恢复: %s\n", e->source);
}

int main() {
DarraUa_Session* ua;
DarraUa_Session_New("opc.tcp://localhost:4840", &ua);

DarraUa_RegisterSubLostHandler(ua, on_lost, NULL);
DarraUa_RegisterSubRestoredHandler(ua, on_restored, NULL);

DarraUa_Session_Connect(ua);

// 创建 sub + MI, 全程不变
DarraUa_Subscription* sub;
DarraUa_Session_CreateSubscription(ua, 500.0, &sub);

DarraUa_DataChangeFilter filter = {
.deadband_type = DBT_ABSOLUTE,
.deadband_value = 0.5
};
uint32_t mi;
DarraUa_Subscription_AddWithFilter(sub, "ns=2;s=Temp", ATTR_VALUE,
200.0, MM_REPORTING, 10, 1, &filter, &mi);

/* 拔网线 30 秒, 看日志:
reconnecting → reconnected → SubRestored
数据自动续上, filter 也保留
*/

// 手动 transfer
uint32_t sub_id = DarraUa_Subscription_GetId(sub);
uint32_t old_ids[] = { sub_id };
DarraUa_StatusCode* rcs = NULL;
DarraUa_Session_TransferSubscriptions(ua, old_ids, 1, 1, &rcs);
DarraUa_FreeStatusCodes(rcs);

DarraUa_Session_Free(ua);
return 0;
}

恢复流程

重连成功

对每个本地 Subscription:
1. TransferSubscriptions(old_sub_id)
├─ Good → SubRestored 事件
└─ BadSubscriptionIdInvalid → 进入 2
2. CreateSubscription(original_params) 拿新 sub_id
3. 按本地 _mi_cache 重建所有 MI
- SamplingInterval / Mode / QueueSize / DiscardOldest
- DataChangeFilter
- EventFilter
- Triggering Links
4. SubRestored 事件

缓存的字段

_mi_cache 保留: NodeId / AttributeId / SamplingInterval / Mode / QueueSize / DiscardOldest / DataChangeFilter / EventFilter。

恢复时全部重放, 服务端 mi id 会变, 业务侧应使用 client_handle 而非 server-side id 对账。

最佳实践

  • 业务用 client_handle, 不要持久化 mi id
  • 监听 SubRestored 事件
  • 不要在 SubLost 里手动 recreate
  • 关键参数变更后 pause 再 resume

跨语言对照

C#PythonJavaC++RustC
TransferSubscriptionstransfer_subscriptionstransferSubscriptionsTransferSubscriptionstransfer_subscriptionsDarraUa_Session_TransferSubscriptions

下一步