4、Modbus TCP协议:与RTU的区别、MBAP报文头、网关应用、连接管理

好,咱们今天聊聊Modbus TCP。说实话,这个协议在工控圈子里太常见了。你随便进一个自动化项目现场,十有八九都能看到它的影子。我个人习惯把Modbus TCP看作是Modbus RTU的“网络升级版”——它把串行总线上的那套东西,搬到了以太网上来跑。

但要注意,这不只是换个物理层那么简单。很多坑,恰恰就藏在那些“看起来一样”的地方。

4.1 Modbus TCP与RTU的核心区别

先说说最直观的区别。RTU跑在RS-232或RS-485上,是串行通信。TCP跑在以太网上,是网络通信。但更深层的区别,我列个表给你看:

对比项 Modbus RTU Modbus TCP
物理层 RS-232 / RS-485 以太网 (RJ45)
传输方式 半双工 / 主从查询 全双工 / 客户端-服务器
地址机制 设备地址 (1-247) IP地址 + 单元标识符
报文结构 地址 + PDU + CRC MBAP头 + PDU
校验方式 CRC16 (整个报文) TCP/IP协议栈保证
典型速率 9.6kbps - 115.2kbps 10/100Mbps

看到没?RTU有CRC校验,TCP没有。为什么?因为TCP/IP协议栈自己已经做了校验和重传,Modbus TCP就不需要再画蛇添足了。嗯,这里要注意,很多人刚接触时会问:“没有CRC,数据错了怎么办?”其实底层已经帮你兜底了。

还有一个关键点:RTU是严格的主从模式,一个主站轮询多个从站。而TCP是客户端-服务器模式,一个客户端可以同时连接多个服务器,反过来也行。说白了,TCP的拓扑灵活得多。

4.2 MBAP报文头——TCP的灵魂

Modbus TCP和RTU最大的结构差异,就是这个MBAP头。全称是Modbus Application Protocol Header,7个字节,放在PDU前面。

我直接给你看报文结构:

MBAP报文头 (7字节) + 功能码 (1字节) + 数据 (N字节)

MBAP头具体格式:
| 事务处理标识符 (2字节) | 协议标识符 (2字节) | 长度 (2字节) | 单元标识符 (1字节) |

咱们拆开来看:

  • 事务处理标识符:用来匹配请求和响应。客户端发一个请求,设一个ID,服务器响应时原样返回。这样客户端就能知道哪个响应对应哪个请求。我在项目中遇到过,有些设备这个字段处理不对,导致多请求时数据全乱套了。
  • 协议标识符:固定为0x0000,表示Modbus协议。别的值?目前基本不用。你看到非0的值,八成是设备有问题。
  • 长度:从单元标识符之后到报文结束的总字节数。注意,这个长度不包括MBAP头自身。很多人第一次写代码时容易算错,我建议你画个图,标清楚每个字段的偏移量。
  • 单元标识符:这个字段很有意思。它其实就是RTU里的设备地址。为什么TCP还要这个?因为网关要用。后面细说。

重点记忆:MBAP头的长度字段,只算“单元标识符 + PDU”的字节数。不算MBAP头自己的7个字节。这个坑,我见过不下五次。

4.3 网关应用——RTU与TCP的桥梁

现实项目中,很少有纯TCP或纯RTU的情况。往往是老设备走RTU,新设备走TCP。怎么打通?用网关。

网关的作用,说白了就是“翻译”。它一端接以太网,一端接串口。TCP报文进来,它剥掉MBAP头,加上CRC,变成RTU报文发出去。反过来也一样。

这里有个关键点:单元标识符。网关收到TCP请求时,会看MBAP头里的单元标识符,把它当作RTU的从站地址。举个例子:

  • 客户端发TCP请求,单元标识符设为0x01
  • 网关收到后,把0x01填入RTU报文的地址字段
  • 然后通过RS-485发给地址为1的从站

我曾经调试过一个项目,现场有30多个RTU设备,全部通过一个网关接入上位机。当时有个问题:单元标识符和实际设备地址对不上,导致数据全读错了。排查了半天,最后发现是网关的地址映射表配错了。嗯,这种低级错误,犯过一次就记住了。

我的建议:网关配置时,先把单元标识符和设备地址的对应关系画成表格。一个萝卜一个坑,别偷懒。

4.4 连接管理——别把TCP当串口用

这是很多人容易忽略的地方。RTU是串行通信,发完一个请求,等响应,再发下一个。但TCP是网络通信,你可以同时发多个请求,也可以保持长连接。

但问题来了:有些设备对并发处理能力很差。你一口气发10个请求,它可能只处理前3个,后面的直接丢包。我建议的做法是:

  • 控制并发数:一般不超过5个未响应的请求
  • 设置超时:TCP默认超时可能很长,应用层要自己设。我习惯设3-5秒
  • 心跳机制:长时间不通信,有些设备会主动断开连接。定期发个读请求,保持连接活跃

还有一个坑:端口号。Modbus TCP默认用502端口。但有些现场会把502端口封掉,或者被其他服务占用。这时候就需要改端口。但改了之后,所有客户端和网关都得同步改,很麻烦。所以,除非万不得已,别动502。

避坑指南:我曾经遇到一个项目,上位机每秒钟轮询一次所有设备,结果网关CPU跑满,导致通信超时。后来把轮询间隔改成2秒,问题解决。别把TCP当串口那样高频轮询,网络开销比串口大得多。

最后说一句:连接管理没有标准答案。有的设备支持多连接,有的只支持单连接。有的设备断线后会自动重连,有的不会。我的经验是:先看设备手册,再写代码。别想当然。

好了,Modbus TCP的核心内容就这些。下一章咱们聊聊Modbus的异常处理——那些错误码到底是什么意思,以及怎么在代码里优雅地处理它们。