Read / Write
前置阅读
- 数据类型 Variant 和 DataValue 是所有读写的基础.
- 高频访问相同节点请用 RegisterNodes 加速.
- 实时变化通知用 Subscription 而不是循环 Read.
Read
DataValue Read(std::string const& node_id,
AttributeId attr = AttributeId::Value);
读单节点的指定 Attribute.
| 参数 | 类型 | 默认 | 说明 |
|---|---|---|---|
node_id | std::string const& | — | NodeId 字符串 (i=2258 / ns=2;s=...) |
attr | AttributeId | Value (13) | 要读的属性 |
返回: DataValue (栈对象, 析构自动释放)
异常: Exception (BadNodeIdUnknown / BadNotReadable / BadCommunicationError / ...)
// 读 Value
auto dv = s.Read("ns=2;s=Temperature");
double t = 0; dv.Value().TryGetDouble(t);
std::cout << t << "\n";
// 读 DisplayName
auto dn = s.Read("ns=2;s=Temperature", AttributeId::DisplayName);
std::cout << dn.Value().AsString() << "\n";
ReadMany
std::vector<DataValue> ReadMany(
std::vector<std::string> const& node_ids,
AttributeId attr = AttributeId::Value);
一次 RPC 批量读多个节点的同一 Attribute.
std::vector<std::string> nodes = { "ns=2;s=T1", "ns=2;s=T2", "ns=2;s=T3" };
auto values = s.ReadMany(nodes);
for (size_t i = 0; i < nodes.size(); ++i) {
std::cout << nodes[i] << " = " << values[i].Value().AsString() << "\n";
}
性能: 批量比循环单读快 ~N 倍 (省 N-1 次 RPC 往返).
如果某个节点解析失败, 对应槽位 Handle() 为空, 用前先检查.
Write
Status Write(std::string const& node_id,
Variant const& value,
AttributeId attr = AttributeId::Value);
写单节点.
Variant v; v.SetDouble(42.5);
Status st = s.Write("ns=2;s=Setpoint", v);
if (st != Status::Good) {
std::cerr << "Write failed: 0x" << std::hex << static_cast<uint32_t>(st) << "\n";
}
返回 Status (Good / BadNotWritable / BadTypeMismatch / BadUserAccessDenied / ...).
业务级失败不抛异常
Write 不抛异常 (除非 transport 级错误), 业务级失败通过返回值判断. 必须检查返回值, 不要假定 Good.
Variant 构造速查
Variant v;
v.SetBool(true); // Boolean
v.SetInt16(42); // Int16
v.SetInt32(42); // Int32
v.SetInt64(42LL); // Int64
v.SetDouble(3.14); // Double
v.SetFloat(3.14f); // Float
v.SetString("hello"); // String
v.SetDateTime(file_time); // DateTime (FileTime: 100ns since 1601)
详见 Variant 数据类型.
DataValue 字段速查
| 访问器 | 类型 | 说明 |
|---|---|---|
Value() | Variant | 实际值 (借用) |
StatusCode() | uint32_t | 原始 32-bit 状态码 |
StatusEnum() | Status | 强类型枚举 |
IsGood() | bool | 等价 StatusCode() == 0 |
SourceTimestamp() | int64_t | FileTime (100ns since 1601) |
ServerTimestamp() | int64_t | FileTime |
auto dv = s.Read("ns=2;s=T1");
if (!dv.IsGood()) {
std::cerr << "Bad value: 0x" << std::hex << dv.StatusCode() << "\n";
return;
}
double t = 0; dv.Value().TryGetDouble(t);
std::cout << t << " @ ft=" << dv.SourceTimestamp() << "\n";
AttributeId 常用值
enum class AttributeId : int {
NodeId = 1, NodeClass = 2, BrowseName = 3, DisplayName = 4,
Description = 5, WriteMask = 6, UserWriteMask = 7,
IsAbstract = 8, Symmetric = 9, InverseName = 10,
ContainsNoLoops = 11, EventNotifier = 12,
Value = 13, // 默认
DataType = 14, ValueRank = 15, ArrayDimensions = 16,
AccessLevel = 17, UserAccessLevel = 18,
MinimumSamplingInterval = 19, Historizing = 20,
Executable = 21, UserExecutable = 22,
};
最佳实践
- 批量优先: 监控 100+ Tag 用
ReadMany, 不要循环Read - 栈对象 RAII:
auto dv = s.Read(...);离开作用域自动释放, 不要new - Write 检查返回值: 不要假定一定 Good
- 实时变化用订阅: 不要循环 Read, 改用
Subscription(服务端推送)