Modbus TCP · 以太网协议百科
Modbus 跑在 TCP/IP 上的形态:MBAP 报文头、端口 502、无 CRC、长连接多请求并发。PLC 以太网通信必读。
⌕
输入关键词实时过滤下方章节。
★一句话总览
先记住最本质的区别。
- Modbus TCP = Modbus 应用层(功能码+数据)直接封装进 TCP/IP,默认端口 502。
- 报文 = MBAP 报文头(7字节) + 功能码 + 数据;MBAP 里的"长度"字段替代了 RTU 的帧间隔,TCP 层的可靠传输替代了 CRC。
- 和 RTU 比:没有 CRC、没有地址冲突问题、支持长连接并发,一台主机可同时跟多台设备、甚至同时发多个请求。
一是什么
协议出身与定位。
- 由 Modbus 组织于 1999 年定义(Modbus Messaging on TCP/IP Implementation Guide),本质是把 Modbus 应用协议搬上以太网。
- 工业以太网事实标准之一:西门子 S7-1200/1500(走 Modbus TCP 库)、罗克韦尔、施耐德、以及大量国产 PLC/仪表/网关都支持。
- 好处:带宽大(百兆/千兆)、距离远(走交换机)、无轮询瓶颈——RTU 是"一根线轮流问",TCP 是"各连各的,并行问"。
- 坏处:实时性不如 EtherCAT/PROFINET 等实时以太网;纯软件协议栈,靠 TCP 重传保证可靠,不适合硬实时运动控制。
二MBAP 报文头(7 字节)
Modbus Application Protocol 头,是 TCP 版与 RTU 版最大的区别。
完整报文(ADU): ┌─────────────────────────── MBAP 头 7B ───────────────────────────┐ ┌──────────────┬──────────────┬──────────────┬──────────────┬─────────────┐ │ 事务标识符(2B) │ 协议标识符(2B) │ 长度(2B) │ 单元标识符(1B) │ 功能码+数据(NB) │ │ Transaction │ Protocol │ Length │ Unit ID │ PDU │ └──────────────┴──────────────┴──────────────┴──────────────┴─────────────┘
| 字段 | 长度 | 说明 |
|---|---|---|
| 事务标识符 Transaction ID | 2 字节 | 请求序号,用于匹配请求与响应(可并发多请求);响应必须原样回显 |
| 协议标识符 Protocol ID | 2 字节 | 恒为 0x0000(Modbus 协议);非 0 是其他协议 |
| 长度 Length | 2 字节 | 后面所有字节数 = 单元标识符(1) + 功能码(1) + 数据(N)。不含事务/协议标识符和长度自身 |
| 单元标识符 Unit ID | 1 字节 | 相当于 RTU 的从站地址。直连设备通常填 1 或 0xFF;经网关转发到串口从站时填实际从站号 1~247 |
💡
Length 怎么算。请求"读保持寄存器"(功能码 03 + 4 字节数据):Length = 1(Unit) + 1(功能码) + 4(数据) = 6(0x0006)。不含 7 字节 MBAP 头本身。
💡
Unit ID 的坑。直连 PLC 时很多设备忽略 Unit ID 或要求 0xFF("我本身就是目标");走网关转串口时 Unit ID 才是真正的从站号。联不上先查设备手册对 Unit ID 的要求。
三报文实例
逐字节拆解读/写请求与响应。
读保持寄存器(功能码 03,读 2 个)
请求(共 12 字节): 00 01 00 00 00 06 01 03 00 00 00 02 │ │ │ │ │ │ │ └─── 数量 2 │ │ │ │ │ │ └─ 起始地址 0x0000 │ │ │ │ │ └─ 功能码 03 │ │ │ │ └─ Unit ID = 1 │ │ │ └─ Length = 6 │ │ └─ Protocol ID = 0x0000 │ └─ Transaction ID = 0x0001(本次请求的序号) └─ Transaction ID 高字节 响应(共 12 字节): 00 01 00 00 00 07 01 03 04 12 34 56 78 │ │ │ │ │ │ │ └────── 数据 0x1234、0x5678 │ │ │ │ │ │ └─ 字节数 4 │ │ │ │ │ └─ 功能码 03 │ │ │ │ └─ Unit ID = 1 │ │ │ └─ Length = 7(1+1+1+4) │ │ └─ Protocol ID 回显 0x0000 │ └─ Transaction ID 回显 0x0001 ← 靠它对应请求 └─ 高字节 0x00
写单个寄存器(功能码 06)
请求:00 02 00 00 00 06 01 06 00 01 12 34
│ │ └─── 写入值 0x1234
│ └─ 寄存器地址 0x0001
└─ 功能码 06
响应:00 02 00 00 00 06 01 06 00 01 12 34 (正常时原样回显)
异常响应(功能码最高位置 1)
请求读超出范围 → 响应:
00 01 00 00 00 03 01 83 02
│ └─ 异常码 02 = 非法数据地址
└─ 功能码 0x83(0x03 | 0x80)
Length = 3(Unit 1 + 功能码 1 + 异常码 1)
四Modbus TCP vs RTU
一张表记住差异。
| 项目 | Modbus RTU | Modbus TCP |
|---|---|---|
| 物理层 | RS-485 / RS-232 串口 | 以太网(TCP/IP) |
| 默认端口 | 无(串口) | 502 |
| 报文头 | 1 字节从站地址 | 7 字节 MBAP(事务 ID + 协议 ID + 长度 + Unit ID) |
| CRC 校验 | CRC16(必须) | 无(TCP 层保证可靠传输) |
| 帧界定 | 3.5 字符静默间隔 | Length 字段 |
| 从站寻址 | 地址 1~247,一根总线共享 | IP + Unit ID;每设备独立连接,无地址冲突 |
| 并发 | 严格一问一答(串口半双工) | 可并发多请求(靠 Transaction ID 匹配) |
| 距离 | 485 最长 ~1200m | 交换机级联,几乎不限(以太网标准内) |
| 接线/成本 | 双绞线,简单便宜 | 网线/交换机,需 IP 规划 |
| 功能码/数据模型 | 完全相同(线圈/离散输入/输入寄存器/保持寄存器) | |
✅
一句话记忆。TCP 版 = RTU 版去掉 CRC 和帧间隔,换成 7 字节 MBAP 头 + TCP 可靠传输;功能码和数据格式完全一样。
五端口与连接管理
TCP 连接的生命周期。
端口 502
- IANA 分配的 Modbus 标准端口 502(TCP 和 UDP 都有,但工业上 99% 用 TCP)。
- 有些设备允许自定义端口(如 50200),上位机/组态软件里要跟着改。
连接方式
- PLC/设备作 服务器(从站) 监听 502;上位机/SCADA/触摸屏作客户端(主站)发起连接。
- 长连接为主:连接建立后持续复用,频繁重连反而慢且占资源;也有"每次请求新建连接"的用法(简单但低效)。
- 同一 TCP 连接内可流水线并发:连续发出多个请求,再按 Transaction ID 收响应,不必等一个回一个。
- 无响应处理:客户端设超时(典型 1~5s);TCP 层本身有重传,但应用层超时要自己写。
六网关与组网
TCP 与 RTU 世界怎么互通。
上位机(以太网)
│ Modbus TCP(一个连接一个 Unit ID)
▼
┌─────────────┐ RS-485 ┌──────────┐
│ 网关(485-TCP) │ ──────────── │ 仪表1(从站1)│
└─────────────┘ ├──────────┤
│ TCP 侧 Unit ID = 1..N │ 仪表2(从站2)│
└── 网关把 Unit ID 翻译成 └──────────┘
串口帧里的从站地址
- 典型场景:老设备只有 RS-485 口,上位机要网线接入 → 加一台 Modbus RTU/TCP 网关(串口服务器)。
- 网关对 TCP 侧暴露一个 IP;上位机访问不同从站 = 同一 IP 不同 Unit ID;网关负责转成串口帧并轮询。
- 部分网关还支持"多主站并发访问"(多个上位机同时读),比直连 485 灵活得多。
- 西门子 S7-1200/1500:用 "MB_CLIENT / MB_SERVER" 指令实现 Modbus TCP 客户端/服务器,纯库实现无需专用模块。
七排查与调试
联不通时按顺序查。
分层排查法
| 层 | 检查项 |
|---|---|
| 物理/网络 | 网线灯亮?IP 同网段?ping 通?防火墙/安全组是否放行 502? |
| TCP 连接 | nc -zv IP 502 或 telnet 测试端口通不通;设备是否在监听 |
| 报文 | Wireshark 抓包:Protocol ID 是否 0x0000、Length 是否正确、Transaction ID 是否回显 |
| 应用 | Unit ID 对不对、寄存器地址范围、功能码是否支持 |
Wireshark 抓包要点
- 过滤器:tcp.port == 502,能直接看到 MBAP 头和 PDU,逐字节对。
- 看响应里 Transaction ID 是否和请求一致——不一致说明多连接/乱序问题。
- 抓包确认请求发出去了、设备有没有回——"没回"基本是网络或设备侧;"回了但上位机不认"基本是格式/字节序。
常见坑
- 上位机防火墙默认拦 502 → 首次联不通先加放行规则。
- 交换机/路由器开了"端口隔离"或 AP 隔离,设备间互相 ping 不通。
- PLC 侧 MB_CLIENT 指令的 "CONNECT" 参数(IP、端口、Unit ID)填错,或连接 ID 重复导致冲突。
- 多线程上位机同一连接并发写时,Transaction ID 必须唯一递增,否则响应对不上号。
八注意事项
实战经验。
✅
先 ping 再抓包。排查顺序永远是:ping 通 → 端口通 → 抓包看报文 → 再怀疑协议细节,别一上来就盯字节。
✅
复用长连接。轮询周期短(如 100ms)时保持一条长连接,反复建连断开会显著增加延迟和 CPU 开销。
⚠️
Length 字段算错 = 设备不认。Length 是从 Unit ID 开始到报文尾的字节数,不含 MBAP 头;多算少算 7 字节是新手最常见错误。
⚠️
502 端口权限。Linux 下 <1024 端口需要 root/特权启动,自写服务监听 502 记得提权或用 systemd 的 CapabilityBoundingSet。
⚠️
UDP 别乱用。Modbus UDP 也存在但无可靠传输、无重传,只有特殊场合用;工业现场默认 TCP。
没有匹配的内容,换个关键词试试。