4. Modbus TCP详解

Modbus TCP 是 Modbus 协议在以太网上的承载方式。它把传统 Modbus RTU 的串行帧结构改造成“TCP/IP 传输 + MBAP 报文头 + PDU”的组合,使网关、PLC、SCADA 和云平台之间可以通过标准以太网交换数据。理解 Modbus TCP,关键不是记住“它跑在 502 端口”,而是看清 TCP/IP 提供了什么、MBAP 又补充了什么,以及事务标识、协议标识和长度字段如何保证请求与响应正确配对。

一、TCP/IP基础:Modbus TCP 的传输底座

Modbus TCP 使用 TCP 作为传输层协议,默认端口号为 502。TCP 提供面向连接、可靠、有序的字节流服务,因此 Modbus TCP 不需要像 Modbus RTU 那样依赖 CRC 校验来发现传输错误,也不需要 3.5 字符间隔来划分帧边界。帧边界由 MBAP 中的长度字段和 TCP 流本身来界定。

一次典型的 Modbus TCP 通信过程如下:客户端(如 SCADA、网关)向服务器(如 PLC、Modbus TCP 从站)发起 TCP 连接;连接建立后,客户端发送请求报文;服务器解析 MBAP 和 PDU,执行操作后返回响应;双方可在一个 TCP 连接上连续进行多次事务。由于 TCP 是字节流,接收方必须根据 MBAP 长度字段准确切分每一帧,不能假设“一次 recv 就是一条完整报文”。

Modbus TCP 的默认端口是 502,但很多网关和软件允许自定义端口。集成时若发现连接被拒绝,先确认端口是否被防火墙、NAT 或设备配置修改。

二、MBAP报文头:Modbus TCP 的“信封”

MBAP(Modbus Application Protocol)报文头位于 PDU 之前,共 7 个字节,是 Modbus TCP 区别于 Modbus RTU 的核心标志。它包含四个字段:事务标识符、协议标识符、长度字段和单元标识符。MBAP 的作用是让接收方知道“这是哪一次事务、是不是 Modbus、后面还有多少字节、目标是从站还是网关后面的某个串口设备”。

字段 长度 典型值/说明 作用
事务标识符 2 字节 由客户端递增或随机生成 匹配请求与响应,支持并发事务
协议标识符 2 字节 0x0000 表示 Modbus 标识上层协议类型
长度字段 2 字节 后续字节数,含单元标识符 界定报文边界,防止粘包/拆包
单元标识符 1 字节 0x01~0xFF,网关常用 0x01 标识目标从站或网关后端设备

三、事务标识、协议标识与长度字段的协作

事务标识符(Transaction ID)由客户端生成,服务器在响应中原样返回。客户端收到响应后,用事务标识符判断“这是不是我刚才发出的那条请求的回复”。在并发请求较多的 SCADA 系统中,事务标识符是避免响应错配的关键。若客户端同时发出多个请求,事务标识符必须不同;若相同,客户端将无法区分响应归属。

协议标识符(Protocol ID)固定为 0x0000,表示这是 Modbus 协议。如果收到非 0 值,接收方应丢弃或报错。长度字段(Length)表示从单元标识符开始到 PDU 结束的字节数,即“单元标识符 1 字节 + PDU 长度”。例如,读保持寄存器请求的 PDU 为 5 字节(功能码 1 字节 + 起始地址 2 字节 + 寄存器数量 2 字节),则长度字段为 1 + 5 = 6。接收方先读 7 字节 MBAP,再根据长度字段读取剩余字节,从而准确切分报文。

Modbus TCP 报文结构:MBAP + PDU MBAP 报文头(7 字节) 事务标识符 2B 协议标识符 2B 长度字段 2B 单元标识符 1B PDU(协议数据单元) 功能码 + 数据(如起始地址、寄存器数量、字节数、寄存器值) 事务标识符 请求与响应配对 并发事务区分 响应原样返回 协议标识符 固定 0x0000 标识 Modbus 协议 非 0 则丢弃 长度字段 单元标识符 + PDU 界定报文边界 防止粘包/拆包

四、案例:一次读保持寄存器请求的报文拆解

假设客户端要读取从站 1 的保持寄存器,起始地址 0x0000,数量 0x000A。功能码为 0x03。其 Modbus TCP 请求报文(十六进制)如下:

事务标识符:0x0001
协议标识符:0x0000
长度字段:0x0006
单元标识符:0x01
功能码:0x03
起始地址:0x0000
寄存器数量:0x000A

完整报文:
00 01 00 00 00 06 01 03 00 00 00 0A

服务器返回响应时,事务标识符仍为 0x0001,协议标识符为 0x0000,长度字段为 0x0005 + 2×10 = 0x0017(单元标识符 1 字节 + 功能码 1 字节 + 字节数 1 字节 + 20 字节数据 = 23 字节,即 0x17)。客户端收到后,先核对事务标识符,再根据长度字段读取完整数据。若事务标识符不匹配,说明该响应属于其他请求,应丢弃或重新匹配。

在网关集成中,Modbus TCP 客户端通常需要维护“事务标识符 → 请求上下文”的映射表。当响应到达时,用事务标识符找到对应的请求,再把结果返回给上层应用。若网关同时代理多个串口设备,单元标识符用于区分后端从站地址。

五、常见误区与排障复盘

  • 误区一:把单元标识符当成从站地址。在 Modbus TCP 直连设备中,单元标识符常被忽略或固定为 0x01;但在网关场景中,它用于指定网关后端的 Modbus RTU 从站地址,必须与后端设备地址一致。
  • 误区二:忽略长度字段导致粘包。TCP 是字节流,若接收方不按长度字段切分,可能把两条响应拼在一起,造成解析错位。正确做法是先读 7 字节 MBAP,再根据长度字段读取剩余字节。
  • 误区三:事务标识符重复。并发请求时若事务标识符重复,响应无法正确配对。建议客户端使用递增计数器,并处理回绕。
  • 误区四:协议标识符非 0 仍继续解析。协议标识符必须为 0x0000,否则应丢弃报文并记录异常,避免误解析非 Modbus 流量。
排障时建议同时抓取 TCP 流和 Modbus 应用层报文。仅看 TCP 端口 502 只能确认连接建立,无法判断 MBAP 字段是否正确。使用 Wireshark 的 modbus 过滤器可直接查看事务标识符、单元标识符和功能码,快速定位请求响应错配问题。

总结来说,Modbus TCP 的可靠性来自 TCP,而可解析性来自 MBAP。事务标识符负责“配对”,协议标识符负责“认协议”,长度字段负责“切边界”,单元标识符负责“找设备”。在网关集成中,只有把这四个字段与 TCP/IP 连接管理结合起来,才能稳定地完成 Modbus RTU 与 Modbus TCP 之间的协议转换和数据转发。