信息模型 (Information Model)
OPC UA 服务端的全部"可见数据"都组织在一棵叫 Address Space 的节点树里. 客户端不直接访问内存, 而是访问 Address Space 里的节点.
- 节点 (Nodes) — 8 类 NodeClass 详解
- 引用 (References) — 节点之间的关系
- 服务集 (Services) — 怎么操作节点
Address Space 三个核心目录
OPC Foundation 规定服务端 Address Space 必须包含三个根目录:
Root (i=84)
├── Objects (i=85) ← 业务数据 / Server 状态 / 自定义节点都挂这里
├── Types (i=86) ← ObjectType / VariableType / DataType / ReferenceType 定义
└── Views (i=87) ← 视图 (子集) 定义, 较少用
Server 节点 (i=2253) 就挂在 Objects 下, 里面有 ServerStatus / ServerCapabilities / ServerArray / NamespaceArray 等.
NodeId
每个节点有一个全局唯一的 NodeId, 由命名空间索引 + 标识符构成:
NodeId 格式: 例子
i=N (ns=0, 数字) i=2258 → CurrentTime
ns=N;i=M (命名空间 N, 数字) ns=2;i=1001
ns=N;s=... (字符串) ns=2;s=Temperature
ns=N;g={...} (GUID) ns=3;g={550e8400-...}
ns=N;b=base64 (ByteString) ns=4;b=YWJjZA==
- ns=0 是 OPC Foundation 标准命名空间, 客户端可硬编码 (i=2258 永远是 CurrentTime)
- ns=1+ 是服务端自定义命名空间, 客户端通过
Namespaces集合查 NamespaceUri ↔ Index 映射
NamespaceArray
服务端的 NamespaceArray (i=2255) 列出所有命名空间 URI:
[0] http://opcfoundation.org/UA/
[1] urn:server:hostname (服务端本地)
[2] urn:my-company:plc1
[3] http://my-company.com/UA/
客户端连接后, SDK 自动加载 NamespaceArray, 用 ua.Namespaces.GetIndex("urn:my-company:plc1") 即可拿到该 URI 的 Index. 注意: NamespaceIndex 不稳定 (Server 重启可能变), 但 NamespaceUri 稳定 — 所以生产代码不能硬编码 ns=2, 要先反查.
Attributes (属性)
每个节点都有一组标准 Attribute, AttributeId 由 OPC Foundation 固定:
| AttributeId | 含义 | 适用 NodeClass |
|---|---|---|
| 1 (NodeId) | 节点 ID | 全部 |
| 2 (NodeClass) | 节点类型 | 全部 |
| 3 (BrowseName) | 浏览名 | 全部 |
| 4 (DisplayName) | 显示名 | 全部 |
| 5 (Description) | 描述 | 全部 |
| 13 (Value) | 变量的值 | Variable |
| 14 (DataType) | 数据类型 | Variable, VariableType |
| 17 (AccessLevel) | 访问级别 | Variable |
| 21 (Executable) | 是否可执行 | Method |
Read / Write 默认操作 Attribute 13 (Value), 但也可以读 NodeId / DisplayName / DataType 等任何 Attribute.
一个完整例子
Objects (i=85)
└── Calculator (ns=2;s=Calculator)
NodeClass: Object
BrowseName: 2:Calculator
DisplayName: Calculator
├── Add (ns=2;s=Calculator.Add)
│ NodeClass: Method
│ InputArguments: [a:Int32, b:Int32]
│ OutputArguments: [sum:Int32]
│
└── LastResult (ns=2;s=Calculator.LastResult)
NodeClass: Variable
DataType: Int32
AccessLevel: CurrentRead | CurrentWrite
Value: 7
客户端可以:
Browse("ns=2;s=Calculator")→ 列出 Add / LastResult 两个子节点Read("ns=2;s=Calculator.LastResult")→ 拿到 7Call("ns=2;s=Calculator", "ns=2;s=Calculator.Add", 3, 4)→ 返回 7
为什么要这样设计
把"数据"包装成"带元数据 (DataType / Description / 单位 / 范围) 的节点", 客户端无需先知道数据格式就能浏览发现. 这是 OPC UA 与传统 Modbus / S7 等"地址=寄存器号"协议的根本区别.
相关链接
- 节点 — 8 类 NodeClass 详解
- 引用 — 节点之间的关系
- 服务集 — Browse / Read / Write 等
- C# SDK Nodes API