4、通信协议栈:二进制协议、HTTPS协议、UA TCP协议、安全信道与会话

好,咱们今天聊聊OPC UA的通信协议栈。说实话,这玩意儿刚接触时确实容易懵——又是二进制又是HTTPS,还有UA TCP,到底什么场景该用哪个?我当年第一次搭OPC UA服务器时,就因为在协议选择上踩了坑,折腾了两天才跑通。今天我把这些经验掰开揉碎了讲给你听。

4.1 协议栈的整体架构

OPC UA的通信协议栈,说白了就是一套「打包-传输-解包」的规则。它分两层:底层传输协议和上层安全机制。底层负责把数据从A点搬到B点,上层负责保证搬的过程中没人偷看或篡改。

我个人习惯把协议栈想象成一个快递系统:

  • 二进制协议:就像同城闪送,快但需要双方约定好包装规则
  • HTTPS协议:像顺丰快递,安全可靠但有点慢
  • UA TCP协议:像专线物流,高效稳定,是OPC UA的亲儿子

你想想看,如果只是车间内部两台机器通信,用二进制协议就够了。但如果要跨公网访问,那HTTPS才是正道。嗯,这里要注意:选择哪种协议,取决于你的网络环境和安全需求。

4.2 二进制协议(UA Binary)

二进制协议是OPC UA的默认协议,也是效率最高的。它直接把数据编码成字节流,没有多余的文本标签,所以传输量最小。

核心特点:

  • 编码紧凑,带宽占用低
  • 解析速度快,适合实时控制
  • 需要客户端和服务器都支持相同的序列化规则

重要:二进制协议不是随便传裸数据。它有一套严格的编码规则,比如整数用Little-Endian,浮点遵循IEEE 754。我在项目中遇到过一个问题:两台设备一个用ARM一个用x86,结果整数高低位反了,数据全乱套。后来统一用OPC UA的编码规范才解决。

来看一个简单的二进制编码示例(伪代码):

// 编码一个32位整数
byte[] buffer = new byte[4];
buffer[0] = (byte)(value & 0xFF);
buffer[1] = (byte)((value >> 8) & 0xFF);
buffer[2] = (byte)((value >> 16) & 0xFF);
buffer[3] = (byte)((value >> 24) & 0xFF);

// 编码一个字符串(长度+内容)
WriteUInt32(string.Length);
WriteBytes(Encoding.UTF8.GetBytes(string));

二进制协议最适合的场景:

  • 工业现场总线,比如Profinet、EtherCAT的OPC UA映射
  • 嵌入式设备,内存和CPU资源有限
  • 对实时性要求高的控制回路

4.3 HTTPS协议(UA HTTPS)

HTTPS协议其实就是把OPC UA的数据包封装在HTTP请求里,再走TLS加密。说白了,就是用Web的方式做OPC UA通信。

为什么需要HTTPS?

  • 防火墙友好:大多数企业网络只开放80和443端口
  • 安全成熟:TLS证书体系完善,不用自己搞加密
  • 兼容性好:任何支持HTTPS的客户端都能接入

我的经验:曾经有个客户要求OPC UA服务器必须走公司IT的代理服务器。二进制协议根本过不去,换成HTTPS后,配置一下代理地址就通了。所以,如果你要跨网段、跨企业通信,HTTPS是首选。

但HTTPS也有缺点:

  • 性能开销大:每次请求都要建立TCP连接、TLS握手
  • 实时性差:不适合毫秒级的控制场景
  • 消息格式冗余:HTTP头部本身就有几百字节

HTTPS协议的工作流程:

  1. 客户端发起HTTPS连接,完成TLS握手
  2. 客户端发送HTTP POST请求,Body里是OPC UA的二进制数据
  3. 服务器解析请求,处理OPC UA服务
  4. 服务器返回HTTP响应,Body里是结果数据

4.4 UA TCP协议

UA TCP是OPC UA基金会专门设计的传输协议。它不像HTTPS那样依赖HTTP,也不像纯二进制那样裸奔。UA TCP在TCP之上加了一层自己的帧格式,专门为OPC UA优化。

UA TCP的帧结构:

字段 长度 说明
消息类型 4字节 HEL/ACK/ERR/OPN/CLO/MSG
保留位 4字节 固定为0
消息长度 4字节 整个消息的字节数
有效载荷 可变 OPC UA服务调用数据

UA TCP的握手过程很有意思:

  1. 客户端发送HEL(Hello)消息,包含自己的协议版本、缓冲区大小
  2. 服务器回复ACK(Acknowledge),确认参数或调整
  3. 如果参数不匹配,服务器发ERR(Error)断开连接
  4. 握手成功后,开始正常的OPN/CLO/MSG通信

注意:UA TCP的缓冲区大小协商是个坑。我曾经遇到过服务器声明缓冲区只有8KB,但客户端默认发了16KB的数据包,结果服务器直接ERR断开。后来我强制客户端先读服务器的缓冲区上限,再调整自己的发送大小,问题才解决。

UA TCP相比HTTPS的优势:

  • 长连接:一次握手,多次通信,省去重复建连开销
  • 异步消息:支持服务器主动推送数据(订阅机制)
  • 低延迟:没有HTTP的头部开销

4.5 安全信道(Secure Channel)

安全信道是OPC UA的安全基础。它建立在传输协议之上,负责加密和身份验证。说白了,就是给通信内容加了一把锁,只有持有钥匙的双方才能打开。

安全信道的建立过程:

  1. 客户端发送OpenSecureChannel请求,包含自己的安全策略和证书
  2. 服务器验证证书,协商安全策略(比如AES256-SHA256)
  3. 双方生成对称密钥,用于后续通信加密
  4. 服务器返回安全信道ID和令牌,后续消息都带上这个令牌

关键点:安全信道是有生命周期的。默认情况下,安全信道超时时间是一小时。如果超过时间没有通信,信道会自动关闭。我曾经在生产环境遇到过一个问题:服务器和客户端之间有个定时任务,每55分钟通信一次,刚好在超时边缘。后来某个批次的任务延迟了6分钟,安全信道就断了,所有订阅都失效。嗯,从那以后我习惯把超时时间设成2小时,留足余量。

安全策略的选择:

  • None:不加密,不签名。仅用于测试,千万别上生产
  • Basic128Rsa15:用RSA-15做密钥交换,AES-128加密。兼容性好,但强度一般
  • Basic256:AES-256加密,强度高,但性能开销大
  • Basic256Sha256:用SHA-256做签名,目前最推荐的安全策略

4.6 会话(Session)

会话是OPC UA的应用层概念。安全信道负责「怎么安全地传」,会话负责「谁在传、传什么」。一个安全信道上可以建立多个会话,但一个会话只能属于一个安全信道。

会话的生命周期:

  1. 客户端发送CreateSession请求,包含客户端URI、名称、超时时间
  2. 服务器创建会话,返回会话ID、认证令牌
  3. 客户端发送ActivateSession请求,提供用户身份凭证
  4. 服务器验证身份,激活会话
  5. 后续所有操作都在这个会话上下文中执行
  6. 客户端发送CloseSession,或超时后服务器自动关闭

我的建议:会话超时时间不要设得太短。我见过有人设成30秒,结果客户端稍微处理慢一点就被踢了。一般建议设成5-10分钟,既安全又不会频繁重连。另外,记得在客户端实现会话重连机制——安全信道断了可以重建,但会话里的订阅数据可能就丢了。

会话与安全信道的关系:

维度 安全信道 会话
层次 传输层 应用层
职责 加密、身份验证 用户权限、状态管理
生命周期 较长(小时级) 较短(分钟级)
复用 一个信道可承载多个会话 一个会话只能属于一个信道

4.7 协议选择实战建议

讲了这么多,到底怎么选?我总结了一个简单的决策树:

  • 同一台机器或局域网内,实时性要求高 → 二进制协议 + UA TCP
  • 跨公网,需要穿透防火墙 → HTTPS协议
  • 需要服务器主动推送数据 → UA TCP(HTTPS不支持长连接推送)
  • 安全要求极高,比如金融或军工 → HTTPS + 双向证书验证
  • 嵌入式设备,资源受限 → 二进制协议,关闭安全信道(仅限内网)

避坑指南:我曾经在一个项目里,为了图省事,所有设备都用HTTPS通信。结果车间里200多台设备同时连接服务器,HTTPS的TLS握手把服务器CPU直接打满。后来改成UA TCP + 二进制协议,CPU占用从95%降到了15%。所以,别迷信HTTPS,内网场景UA TCP才是王道。

好了,这一章的内容就这些。协议栈这块,理解了二进制、HTTPS、UA TCP的区别,再搞懂安全信道和会话的关系,OPC UA通信这块你就拿下了八成。下一章咱们聊聊地址空间和节点模型,那才是OPC UA真正有意思的地方。