跳到主要内容

KeepAlive 心跳

Session 内置 KeepAlive 心跳: 后台线程周期性读 ServerStatus.CurrentTime (i=2258) 做探测, 既维持会话不超时, 又能在第一时间发现连接异常.

前置阅读

配置

构造时通过 ConnectionConfig.keepalive_interval_ms:

ConnectionConfig cfg;
cfg.endpoint_url = "opc.tcp://server:4840";
cfg.keepalive_interval_ms = 5000; // 改成 5 秒
Session s(cfg);

运行时改:

s.SetKeepAliveInterval(5000);  // 立即重启心跳线程
单位毫秒
默认10000 (10 秒)
最小推荐1000
0禁用

自动启停

时机行为
Connect() 成功后自动启动 (如果 keepalive_interval_ms > 0)
Disconnect()自动停止
SetKeepAliveInterval(ms)重启 (新周期生效)
重连成功自动启动

心跳事件回调

每次心跳成功都触发 on_keepalive:

constexpr int64_t WIN_EPOCH_OFFSET = 116444736000000000LL;
s.Events().on_keepalive = [](int64_t server_time_ft, Status server_status) {
time_t t = (server_time_ft - WIN_EPOCH_OFFSET) / 10000000;
std::cout << "KeepAlive @ " << t
<< " status=0x" << std::hex << static_cast<uint32_t>(server_status) << "\n";
};

心跳失败 (Read 抛异常) 触发 on_communication_error:

s.Events().on_communication_error = [](Status code, std::string const& where, std::string const& msg) {
if (where == "keepalive") {
std::cerr << "Heartbeat lost: 0x" << std::hex << static_cast<uint32_t>(code)
<< " " << msg << "\n";
}
};

与 SessionTimeout 的关系

服务端 SessionTimeout 默认 10 分钟. 客户端的 KeepAlive 必须比 SessionTimeout 短得多 (推荐 ~1/10), 否则服务端会因为 "Session 长时间无活动" 主动 Cleanup, 客户端拿到 BadSessionIdInvalid 才发现.

SessionTimeoutKeepAlive 推荐
10 分钟 (默认)10 秒 (默认)
5 分钟5 秒
1 小时30 秒

为什么用 ServerStatus.CurrentTime

OPC UA 没有专门的 KeepAlive 协议消息, 通常的做法是发一个轻量级 Read 请求做心跳. ServerStatus.CurrentTime (i=2258) 是 OPC Foundation 标准节点, 任何符合规范的 Server 都有, Read 开销极小.


自定义心跳逻辑

如果想完全禁用 SDK 内置心跳, 自己实现:

ConnectionConfig cfg;
cfg.endpoint_url = "opc.tcp://server:4840";
cfg.keepalive_interval_ms = 0; // 禁用 SDK 内置
Session s(cfg);
s.Connect();

// 自己起 std::thread
std::thread heartbeat([&]() {
while (s.IsConnected()) {
try {
auto dv = s.Read("i=2258");
// 或读"业务心跳节点"
} catch (Exception const& ex) {
std::cerr << "heartbeat: " << ex.what() << "\n";
}
std::this_thread::sleep_for(std::chrono::seconds(5));
}
});

性能影响

KeepAlive 每次开销:

  • 1 次 Read RPC (网络往返 + 服务端读 + 序列化)
  • 典型局域网 ~3-5 ms
  • 远程网络 ~50-200 ms

10 秒周期 = ~0.5% CPU / 带宽开销, 完全可忽略.

下一步