文章目录

Modbus TCP的MBAP报头解析

发布于 2026-03-24 14:21:38 · 浏览 15 次 · 评论 0 条

Modbus TCP协议建立在TCP/IP网络之上,相较于传统的Modbus RTU,它去除了复杂的CRC校验,增加了一个标准的7字节MBAP报头。解析这个报头是进行Modbus TCP通信开发及故障排查的核心基本功。


一、 MBAP报头结构概览

MBAP报头全长固定为7个字节,位于Modbus TCP数据包的最前端。它主要负责解决“这是谁发的”、“发给谁”、“数据有多长”这三个核心问题。

其结构定义如下表所示:

字节索引 (偏移量) 字段名称 长度 描述
0-1 事务处理标识符 2 字节 标识一次通信请求与响应的配对关系
2-3 协议标识符 2 字节 Modbus协议中固定为 0
4-5 长度 2 字节 后续字节数(单元标识符 + PDU)
6 单元标识符 1 字节 从站地址或网关目标地址

二、 字段深度解析

理解每个字段的含义与字节序,是解析报文的关键。Modbus TCP协议统一采用大端模式传输,即高位字节在前、低位字节在后。

1. 解析事务处理标识符

查看 数据包的前两个字节(字节0和字节1)。

这对字段用于配对请求与响应。客户端发起请求时生成一个随机或递增的数字,服务器响应时必须原样返回。例如,请求包前两字节为 00 05,响应包前两字节也必须是 00 05。这在多线程或高并发通信中至关重要,用于区分不同的事务。

  • 操作要点:在编程实现时,建议使用全局递增计数器生成此ID,避免重复。
  • 数值范围0x00000xFFFF (0 - 65535)。

2. 解析协议标识符

检查 第3和第4个字节(字节2和字节3)。

在标准的Modbus TCP通信中,这两个字节必须00 00。如果收到的数据包中此处非零,说明该数据包可能属于Modbus over TCP/IP以外的协议,或者是错误报文。

  • 特殊情况:仅在极少数网关转换场景下可能遇到非零值,但在标准Modbus TCP应用层开发中,直接将其视为固定值 0 即可。

3. 解析长度字段

读取 第5和第6个字节(字节4和字节5)。

这是一个至关重要的字段,它告诉接收方“后面还有多少个字节”。它指示的是从“单元标识符”开始到数据包结束的总字节数。

  • 计算逻辑
    该字段的值 = 1(单元标识符) + 功能码长度(1字节) + 数据域长度。
  • 示例:如果长度字段值为 00 06,表示后续还有6个字节的数据需要读取。

4. 解析单元标识符

确认 第7个字节(字节6)。

这是MBAP报头的最后一个字节,也是Modbus TCP寻址的核心。它对应传统Modbus RTU中的“从站地址”。

  • 默认范围:通常为 01F7 (1 - 247)。
  • 特殊用途
    • 00:通常保留或用于广播。
    • FF (255):常用于某些PLC作为默认本机地址。

三、 报文解析实战流程

以下通过一个具体的抓包案例,演示如何从原始十六进制数据中提取MBAP报头信息。假设捕获到的请求报文如下:

00 01 00 00 00 06 01 03 00 00 00 0A

步骤 1:分割报文

按照 7字节的固定长度,将报文切分为MBAP报头与PDU(协议数据单元)两部分。

  • MBAP报头:00 01 00 00 00 06 01
  • PDU部分:03 00 00 00 0A

步骤 2:逐字段解码

按顺序 解析MBAP报头中的四个字段。

  1. 解析事务处理标识符

    • 原始数据:00 01
    • 解析结果:1
    • 含义:这是第1号通信事务。
  2. 解析协议标识符

    • 原始数据:00 00
    • 解析结果:0
    • 含义:标准的Modbus协议。
  3. 解析长度

    • 原始数据:00 06
    • 解析结果:6
    • 含义:后续还有6个字节的数据(即 01 03 00 00 00 0A)。
  4. 解析单元标识符

    • 原始数据:01
    • 解析结果:1
    • 含义:目标从站地址为1号站。

步骤 3:完整性校验

对比 长度字段的值与实际剩余字节数。

  • 长度字段声明:6字节。
  • 实际剩余字节:01 (单元ID) + 03 (功能码) + 00 00 (起始地址) + 00 0A (数量) = 6字节。
  • 结论:校验通过,报文完整。

四、 解析流程可视化

为了更直观地理解MBAP报头的解析过程,以下是解析逻辑的流程示意:

graph TD A["接收TCP数据流"] --> B["截取前7字节"] B --> C{"解析字段"} C --> D["字节0-1: 事务处理标识符"] C --> E["字节2-3: 协议标识符 (必须为0)"] C --> F["字节4-5: 长度字段"] C --> G["字节6: 单元标识符 (从站地址)"] D --> H["存储ID用于匹配响应"] E --> I{"值是否为0?"} I -- "是" --> J["继续解析"] I -- "否" --> K["丢弃报文 (协议错误)"] F --> L["计算剩余字节数"] G --> M["确定目标设备"] J --> L --> N["提取后续PDU数据"] M --> N

五、 开发注意事项

在进行底层报文构造或解析代码编写时,需特别注意以下几点。

1. 字节序的处理

切记 Modbus协议使用大端模式。

在C/C++或Java等语言中,直接读取内存通常没问题;但在x86架构的小端模式系统(如某些PLC或特定环境下的Python struct 解包)中,必须进行字节序转换。

  • 错误示例:在小端机器上直接将 00 06 读取为整数,可能被错误解释为 0x0600 (1536)。
  • 正确操作使用 高位字节乘以256加上低位字节的方式计算,或使用网络字节序转换函数(如 ntohs)。

2. 长度字段的动态计算

在编写发送程序时,不要 将长度字段写死。

因为PDU的长度是变化的(例如读保持寄存器功能码 03 的请求帧与写多个寄存器 10 的请求帧长度不同),必须先构造好PDU部分,统计其长度加1(单元标识符),再将结果填入MBAP报头的长度字段。

3. TCP粘包处理

避免 假设一次 recv 调用就能读取完整的MBAP报头。

TCP是流式协议,可能会出现粘包或分包现象。正确的处理逻辑是:

  1. 尝试读取 前7个字节(MBAP头)。
  2. 解析 长度字段 Length
  3. 继续读取 后续 Length 个字节的数据。

4. 网关场景下的单元标识符

注意 区分Modbus TCP设备与Modbus TCP转RTU网关。

  • 若目标设备是纯TCP设备(如支持以太网的PLC),单元标识符通常忽略或为固定值(如 FF01)。
  • 若通过网关连接RTU从站,单元标识符必须 设置 为对应RTU从站的地址。

六、 常见报文结构对比

为了加深理解,对比不同场景下的MBAP报头构成。

场景描述 事务ID 协议ID 长度 单元ID 后续PDU示例
读1号站线圈状态 00 01 00 00 00 06 01 01 00 00 00 0A
写5号站单个寄存器 00 02 00 00 00 06 05 06 00 01 00 03
读纯TCP设备数据 00 03 00 00 00 06 FF 03 00 00 00 01

通过上述表格可以看出,无论PDU内容如何变化,MBAP报头的前4个字节结构保持高度稳定,仅长度和单元标识符根据具体指令动态调整。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文