4. Modbus TCP协议详解:报文结构、与RTU的区别、端口502、多会话管理

各位同学,咱们今天来啃一块硬骨头——Modbus TCP协议。说实话,这玩意儿在工业现场太常见了,PLC和CNC通信,十有八九会碰到它。我最早接触Modbus TCP是在一个汽车零部件的生产线上,当时调试了整整两天才把报文结构吃透。嗯,今天我就把那些踩过的坑、总结的经验,一股脑儿倒给你们。

4.1 Modbus TCP报文结构

先看报文结构。Modbus TCP的报文,说白了就是在标准Modbus协议外面套了一层TCP/IP的外衣。它的报文格式长这样:

| MBAP Header (7字节) | 功能码 (1字节) | 数据 (N字节) |

这个MBAP Header是Modbus TCP独有的,全称是Modbus Application Protocol Header。我习惯把它拆成四个部分来看:

字段 长度 说明
事务处理标识符 2字节 用于匹配请求和响应,一般从0开始递增
协议标识符 2字节 固定为0x0000,表示Modbus协议
长度字段 2字节 后续字节的总长度(功能码+数据)
单元标识符 1字节 相当于RTU中的从站地址

这里有个细节我要强调一下。事务处理标识符,很多初学者会忽略它。我在项目中遇到过一台CNC设备,同时发多个请求时,如果事务ID重复了,设备直接不理你。所以我的习惯是,每次请求都递增这个ID,从0到65535循环。

4.2 与Modbus RTU的区别

很多同学会问:Modbus TCP和Modbus RTU到底有啥区别?我打个比方你就明白了。RTU就像寄挂号信,你得写清楚地址、贴邮票、等回执。TCP呢,就像发微信,直接发消息就行,底层已经帮你搞定了传输可靠性。

具体区别我列个表:

对比项 Modbus RTU Modbus TCP
物理层 RS-232/RS-485 以太网
地址方式 从站地址(1-247) 单元标识符 + IP地址
校验方式 CRC16校验 TCP/IP协议栈校验
报文长度 有最大长度限制 理论上无限制
通信模式 主从模式 客户端/服务器模式

你想想看,RTU的CRC校验是自己算的,而TCP的校验交给了协议栈。这意味着什么?意味着Modbus TCP的报文里没有CRC字段,省了2个字节。嗯,这里要注意,有些老工程师会把RTU的报文直接塞进TCP里,结果发现通信失败——就是因为多了CRC。

核心区别一句话总结:Modbus TCP去掉了CRC校验,增加了MBAP Header,用IP地址代替了从站地址。

4.3 端口502的秘密

端口502,这个数字你得记住。IANA(互联网数字分配机构)把502端口专门分配给了Modbus TCP协议。为什么是502?说实话我也不知道,但我知道的是,几乎所有支持Modbus TCP的设备都默认监听这个端口。

我曾经遇到过一个坑:现场有一台CNC的防火墙把502端口给封了,结果PLC死活连不上。排查了半天才发现是端口问题。所以我的建议是,调试时先用telnet测试一下端口通不通:

telnet 192.168.1.100 502

如果连接成功,会看到一个空白界面或者光标闪烁。如果失败,那就得检查网络和防火墙了。

注意:有些设备允许修改端口号,但我不建议你这么做。除非有特殊需求,否则保持502端口不变,兼容性最好。

4.4 多会话管理

多会话管理,说白了就是一台PLC同时和多个CNC设备通信。Modbus TCP是基于TCP的,所以天然支持多连接。每个连接就是一个会话,用IP地址和端口号来区分。

我给你们看一个典型的场景:

PLC (192.168.1.10) 
  ├── CNC #1 (192.168.1.20:502)  会话1
  ├── CNC #2 (192.168.1.30:502)  会话2
  └── CNC #3 (192.168.1.40:502)  会话3

每个会话独立管理自己的事务处理标识符。我的习惯是,给每个CNC设备分配一个独立的会话ID,这样方便排查问题。比如CNC #1的会话ID从0开始,CNC #2的从1000开始,互不干扰。

多会话管理有几个要点:

  • 连接池管理:不要频繁建立和断开连接,开销太大。我一般保持长连接,除非设备离线。
  • 超时处理:每个会话单独设置超时时间。我曾经遇到过一台CNC偶尔响应慢,如果全局超时设置太短,其他设备也会受影响。
  • 资源限制:TCP连接数不是无限的。有些PLC最多支持8个并发连接,超过就会拒绝。嗯,这个得看具体设备手册。

实战技巧:如果你用C#或Python写上位机,可以用异步方式管理多会话。每个会话开一个独立的Task或线程,互不阻塞。我最早用同步方式,结果一个设备卡住,整个系统都停了——那叫一个惨。

4.5 报文实例分析

光说不练假把式。咱们来看一个实际的报文例子。假设PLC要读取CNC的保持寄存器,起始地址0,读取2个寄存器。

请求报文:

事务ID: 0x0001
协议ID: 0x0000
长度:   0x0006
单元ID: 0x01
功能码: 0x03
起始地址: 0x0000
寄存器数量: 0x0002

完整报文: 00 01 00 00 00 06 01 03 00 00 00 02

响应报文:

事务ID: 0x0001
协议ID: 0x0000
长度:   0x0007
单元ID: 0x01
功能码: 0x03
字节数: 0x04
数据:   0x1234 0x5678

完整报文: 00 01 00 00 00 07 01 03 04 12 34 56 78

你看,事务ID是匹配的,这样PLC就知道这个响应对应哪个请求。如果同时发了多个请求,事务ID就是唯一的标识。

好了,关于Modbus TCP协议,今天就讲这么多。下一节咱们聊聊实际编程中怎么用Socket实现Modbus TCP通信。记住,理论是基础,动手才是关键。回去找个支持Modbus TCP的设备,抓个包看看,比看十遍书都管用。