历史流式读
概述
C 没有 IAsyncEnumerable / Stream, SDK 用 callback 模式: 每读到一条 DataValue 调一次 callback, 业务可立即处理 (例如 push 到 chart) 而不必先装进 array。
对应规范段: Part 11 §6.5。
API
| 函数 | 类别 | 读写 | 说明 |
|---|---|---|---|
| DarraUa_Session_ReadHistoryStream(ua, nid, t0_ms, t1_ms, batch_size, on_value, ctx) | 历史 | 读 | 流式读, 每条调 on_value |
回调签名: int cb(const DarraUa_DataValue* dv, void* ctx) — 返回非零表示继续, 返回 0 提前退出。
t0_ms / t1_ms 是 UTC ms epoch。
代码示例
#include <opcua.h>
int on_value(const DarraUa_DataValue* dv, void* ctx) {
/* 处理每个点 */
chart_add_point(ctx, dv->source_timestamp, dv->value /* AsDouble 等 */);
return 1; // 继续
}
int main() {
DarraUa_Session* ua;
DarraUa_Session_New("opc.tcp://localhost:4840", &ua);
DarraUa_Session_Connect(ua);
int64_t t1_ms = /* now */;
int64_t t0_ms = t1_ms - 24LL * 3600 * 1000;
// 1) 边拉边渲染
DarraUa_StatusCode st = DarraUa_Session_ReadHistoryStream(ua, "ns=2;s=Temp",
t0_ms, t1_ms, /*batch_size=*/1000, on_value, my_chart);
// 2) 取消支持: callback 返回 0
int cancel_requested = 0;
auto inner_cb = ^(const DarraUa_DataValue* dv, void* ctx) -> int {
if (cancel_requested) return 0;
process(dv);
return 1;
};
DarraUa_Session_ReadHistoryStream(ua, "ns=2;s=Temp", t0_ms, t1_ms, 1000,
inner_cb, &cancel_requested);
DarraUa_Session_Free(ua);
return 0;
}
实现限制
- 当前底层 ReadHistory 不暴露 ContinuationPoint, 一次 RPC 返回区间内所有点 (受 batch_size 限)
- 大区间业务侧自行切片调多次
- callback 不能阻塞超过 100 ms, 不然 RPC 队列卡
最佳实践
- callback 内部不做长操作
- 区间 > 1 小时建议外层切片
- UI 渲染节流: 累积 100 条再 refresh
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| ReadHistoryStreamAsync | read_history_stream | readHistoryStream | ReadHistoryStream | read_history_stream | DarraUa_Session_ReadHistoryStream |