跳到主要内容

KeepAlive 心跳

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

前置阅读

getKeepAliveIntervalMs() / setKeepAliveIntervalMs(int)

public int  getKeepAliveIntervalMs();
public void setKeepAliveIntervalMs(int ms);
单位毫秒
默认10000 (10 秒)
最小推荐1000
0禁用

修改后立即生效 (重启 Timer):

ua.setKeepAliveIntervalMs(5000);  // 改成 5 秒

自动启停

时机行为
connect() 成功后自动启动
disconnect()自动停止
修改 setKeepAliveIntervalMs()重启
自动重连成功自动启动

心跳事件

每次心跳成功都触发 events.onKeepAlive:

ua.events.onKeepAlive.add(e ->
System.out.println("KeepAlive @ " + e.serverTimeUtc + " (status=" + e.serverStatus + ")"));

心跳失败 (Read 抛异常) 触发 events.onCommunicationError:

ua.events.onCommunicationError.add(e -> {
if ("keepalive".equals(e.category)) {
System.err.println("Heartbeat lost: " + e.statusCode + " " + e.message);
}
});

与 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 (WellKnownNodes.SERVER_SERVER_STATUS_CURRENT_TIME = i=2258) 是 OPC Foundation 标准节点, 任何符合规范的 Server 都有, Read 开销极小.


自定义心跳逻辑

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

ua.setKeepAliveIntervalMs(0);  // 禁用 SDK 内置

// 自己起 Timer
java.util.Timer timer = new java.util.Timer("MyHeartbeat", true);
timer.schedule(new java.util.TimerTask() {
@Override public void run() {
if (!ua.isConnected()) return;
try (OpcUaDataValue dv = ua.read(WellKnownNodes.SERVER_SERVER_STATUS_CURRENT_TIME)) {
// 用 dv 做自定义业务
} catch (OpcUaException ex) {
// 自己处理
}
}
}, 5000, 5000);

性能影响

KeepAlive 每次开销:

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

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

下一步