目标

本文档用于指导在 Linux 环境下完成以下工作:

  • 使用 tcpdump 抓取 Modbus TCP 通信报文
  • 使用 Wireshark 对抓到的 .pcap.pcapng 文件进行分析
  • 通过一个完整的 Modbus 读寄存器示例,掌握请求与响应的拆解方法
  • 快速定位通信失败、超时、异常码、地址错误、寄存器数量错误等问题

本文重点面向 Modbus TCP 场景,即通过 TCP 端口 502 进行通信的情况。


适用场景

以下情况都适合使用本文档的方法:

  • EMS 与 PLC、PCS、BMS、电表、保护装置之间的 Modbus TCP 联调
  • 现场设备“能连通但读不到数据”的问题排查
  • 核对主站下发的寄存器地址、功能码、寄存器数量是否正确
  • 分析从站返回异常码的具体原因
  • 复盘偶发超时、重传、断链、错误响应等网络问题

环境准备

建议准备以下工具:

  • Linux 主机一台
  • tcpdump
  • Wireshark
  • 被抓包的 Modbus TCP 通信链路
  • 具备 sudo 权限的账号

Ubuntu / Debian 可参考:

sudo apt-get update
sudo apt-get install -y tcpdump wireshark

安装完成后可确认版本:

tcpdump --version
wireshark --version

如果当前用户无权限直接打开抓包文件或使用抓包能力,可临时通过 sudo 执行抓包命令。


整体流程

整个操作流程建议按下面顺序执行:

  1. 确认通信网卡、对端 IP、TCP 端口
  2. 使用 tcpdump 抓取 Modbus TCP 报文到文件
  3. 用 Wireshark 打开抓包文件
  4. 使用显示过滤器筛选目标流量
  5. 对照 Modbus 报文字段逐项分析
  6. 根据现象判断是网络问题、协议问题还是业务配置问题

步骤一:确认抓包对象

抓包前,先确认以下信息:

  • 本机使用的是哪块网卡
  • Modbus 对端 IP 是多少
  • 是否确实走 TCP 端口 502
  • 抓包点位于主站侧、从站侧,还是中间交换网络

1. 查看本机网卡

ip -br addr

在这里插入图片描述

如果机器有多张网卡,务必确认哪块网卡承载了现场业务流量。

2. 查看抓包接口列表

sudo tcpdump -D

在这里插入图片描述

输出中通常会列出类似 eth0ens33enp3s0bond0any 等接口名称。

3. 确认 Modbus 连接是否存在

ss -ant | grep ':502'

如果已经建立连接,通常能看到:

  • 客户端临时端口 -> 服务端 502
  • ESTAB 状态表示 TCP 已建立

在这里插入图片描述


步骤二:使用 tcpdump 抓取 Modbus TCP 报文

1. 最常用抓包命令

sudo tcpdump -i eth0 -nn -s 0 -w modbus_tcp.pcap 'tcp port 502'

参数说明:

  • -i eth0:指定抓包网卡,请替换为现场实际网卡
  • -nn:不做主机名和端口名解析,避免输出被解析结果干扰
  • -s 0:抓取完整报文,不截断
  • -w modbus_tcp.pcap:将数据写入文件,供 Wireshark 打开
  • 'tcp port 502':只抓取 Modbus TCP 常用端口数据

2. 抓指定主机与端口

如果只想抓某个设备与本机之间的 Modbus 报文:

sudo tcpdump -i eth0 -nn -s 0 -w modbus_192.168.1.10.pcap 'host 192.168.1.10 and tcp port 502'

3. 抓双向通信并保留完整上下文

若现场可能存在建链失败、重传、RST、异常关闭等情况,建议抓整个会话,而不是只抓应用层片段:

sudo tcpdump -i eth0 -nn -s 0 -w modbus_full_session.pcap 'host 192.168.1.10'

这样在 Wireshark 中可以同时看到:

  • TCP 三次握手
  • Modbus 请求与响应
  • 重传、乱序、RST、FIN

4. 长时间抓包建议

如果现场问题偶发,建议使用轮转文件,避免单文件过大:

sudo tcpdump -i eth0 -nn -s 0 -C 100 -W 10 -w modbus_ring.pcap 'tcp port 502'

参数说明:

  • -C 100:单个文件达到 100 MB 后切换
  • -W 10:最多保留 10 个文件,循环覆盖

5. 抓包结束

抓包过程中按 Ctrl + C 停止。结束时 tcpdump 会输出抓到的数据包统计信息。

在这里插入图片描述

步骤三:使用 Wireshark 打开抓包文件

抓包完成后,启动 Wireshark 并打开文件:

wireshark modbus_tcp.pcap

在这里插入图片描述

也可以直接启动 Wireshark 后,通过图形界面打开抓包文件。

打开后,界面通常分为三部分:

  • 数据包列表区:展示时间、源地址、目的地址、协议、长度、摘要信息
  • 协议树详情区:逐层展开 Frame、Ethernet、IP、TCP、Modbus 等字段
  • 字节区:展示原始十六进制内容,并高亮当前选中字段

在这里插入图片描述


步骤四:在 Wireshark 中过滤 Modbus 报文

Wireshark 分为两类过滤:

  • 抓包过滤器tcpdump 执行时使用,决定“抓什么”
  • 显示过滤器:Wireshark 中使用,决定“看什么”

本文主要关注 Wireshark 的显示过滤器。

1. 显示所有 Modbus 报文

modbus

如果 Wireshark 已正确识别协议,这个过滤器最直接。
在这里插入图片描述

2. 按 TCP 端口过滤

tcp.port == 502

在这里插入图片描述

3. 按 IP 地址过滤

ip.addr == 192.168.3.23

在这里插入图片描述

4. 只看某个方向

ip.src == 192.168.1.100 && ip.dst == 192.168.1.10 && tcp.port == 502

在这里插入图片描述

这个过滤器适合只看主站请求,或只看从站响应。

5. 只看异常与网络问题

tcp.analysis.retransmission
tcp.flags.reset == 1
modbus || tcp.analysis.retransmission || tcp.flags.reset == 1

6. 端口不是 502 时的处理方法

有些测试环境不会使用标准端口 502。如果 Wireshark 没有自动识别成 Modbus,可手动指定:

  1. 选中对应 TCP 报文
  2. 菜单进入 Analyze -> Decode As...
  3. 在对应 TCP 端口上选择 Modbus/TCP
  4. 应用后再使用 modbus 过滤

步骤五:结合示例分析 Modbus 报文

下面用一个典型的 读取保持寄存器 示例说明如何分析。

示例场景

  • 主站 IP:192.168.1.100
  • 从站 IP:192.168.1.10
  • TCP 端口:502
  • 单元标识符(Unit ID):1
  • 功能码:0x03,读取保持寄存器
  • 起始地址:0x0000
  • 读取数量:1

1. 请求报文示例

十六进制内容如下:

00 21 00 00 00 06 01 03 00 00 00 01

拆解如下:

字节位置 字段 含义
0-1 Transaction Identifier 0x0021 事务标识,用于请求响应匹配
2-3 Protocol Identifier 0x0000 Modbus TCP 固定为 0
4-5 Length 0x0006 后续字节长度
6 Unit Identifier 0x01 设备地址 / 单元标识
7 Function Code 0x03 读取保持寄存器
8-9 Starting Address 0x0000 起始地址
10-11 Quantity 0x0001 读取 1 个寄存器

分析结论:

  • 这是一个标准的 Modbus TCP 读保持寄存器请求
  • 主站要求从地址 0 开始读取连续 1 个寄存器
  • Transaction Identifier1,后续响应通常会保持一致

在这里插入图片描述


2. 响应报文示例

十六进制内容如下:

00 21 00 00 00 05 01 03 02 70 f8

拆解如下:

字节位置 字段 含义
0-1 Transaction Identifier 0x0021 与请求匹配
2-3 Protocol Identifier 0x0000 固定为 0
4-5 Length 0x0005 后续字节长度
6 Unit Identifier 0x01 单元标识
7 Function Code 0x03 响应功能码,与请求一致
8 Byte Count 0x02 返回 4 个字节数据
9-10 Register 0 0x0070 十进制 112
11-12 Register 1 0x00f8 十进制 248

分析结论:

  • 响应与请求事务号一致,说明配对正确
  • 返回了 2 个寄存器,共 4 字节,和请求数量一致
  • 两个寄存器的值分别为 100200

在这里插入图片描述


3. 如何在 Wireshark 中看懂这类报文

分析时建议按下面顺序看:

  1. 先看 TCP 层
    • 是否成功三次握手
    • 是否有重传、RST、乱序、零窗口
  2. 再看 MBAP 头
    • Transaction Identifier 是否能和响应匹配
    • Protocol Identifier 是否为 0
    • Length 是否合理
    • Unit Identifier 是否符合设备配置
  3. 最后看 Modbus PDU
    • 功能码是否正确
    • 起始地址是否正确
    • 寄存器数量是否超限
    • 返回字节数是否与寄存器数量一致

如果 Wireshark 协议树能正确展开,一般说明 TCP 层和 Modbus 报文结构至少基本可解析。


4. 异常响应示例

若从站不支持请求的功能、地址错误或数量越界,常见会返回异常响应。例如:

00 03 00 00 00 03 01 83 02

拆解如下:

字段 含义
Transaction Identifier 0x0003 与请求配对
Unit Identifier 0x01 单元标识
Function Code 0x83 异常响应,0x80 + 0x03
Exception Code 0x02 非法数据地址

说明:

  • 正常功能码是 0x03
  • 异常响应时功能码最高位置位,因此变成 0x83
  • 0x02 常表示寄存器地址不存在、越界,或设备不支持该地址范围

常见异常码

异常码 名称 常见原因
0x01 Illegal Function 功能码不支持
0x02 Illegal Data Address 地址错误、寄存器不存在、地址越界
0x03 Illegal Data Value 数量、值或参数非法
0x04 Slave Device Failure 从站内部处理失败

步骤六:定位常见问题

下面给出现场最常见的几类现象以及对应排查思路。

1. 看不到任何 Modbus 报文

排查方向:

  • 抓错网卡
  • 流量不经过当前主机
  • 端口不是 502
  • 防火墙或交换机策略限制
  • 通信根本没有发起

建议操作:

sudo tcpdump -i any -nn -s 0 -w test_any.pcap host 192.168.1.10

先放宽过滤条件确认有没有相关主机流量,再逐步收窄。

2. 能看到 TCP 建链,但没有 Modbus 数据

排查方向:

  • 应用程序连接成功但未发请求
  • 上层程序卡住或等待条件未满足
  • 使用了非 Modbus 协议
  • 端口被复用,但协议不是 Modbus

建议在 Wireshark 中观察:

  • TCP 三次握手之后是否出现 PSH, ACK
  • 载荷是否能被 Decode As Modbus/TCP

3. 有请求,无响应

排查方向:

  • 从站未收到请求
  • 从站收到但未处理
  • 网络单向不通
  • 中间设备丢包
  • 从站处理超时

重点看:

  • 请求发出后是否有 TCP 重传
  • 是否有 ICMP 不可达
  • 是否最终收到 RST

4. 响应是异常码

排查方向:

  • 功能码不支持
  • 寄存器地址写错
  • 地址基准错位
  • 读取数量超限
  • 单元标识符配置错误

工业现场很常见的问题是:

  • 文档地址从 40001 开始描述,但程序里直接用了协议地址 0
  • 或者相反,设备要求协议地址,主站却把文档地址直接发下去了

因此要特别确认:

  • 设备手册中的地址是 协议地址
  • 还是 人类可读的数据模型地址

5. Wireshark 能解包,但数值不对

排查方向:

  • 寄存器高低位组合方式不对
  • 多寄存器拼接时字序不同
  • 设备手册定义的是有符号数,程序按无符号解释
  • 缩放比例未处理,例如真实值为“寄存器值 / 10”

这类问题通常不是网络故障,而是 协议解释或点表配置问题

6. 报文正常,但业务仍报超时

排查方向:

  • 应用层超时时间设置过短
  • 程序在等待错误的事务号
  • 多线程并发访问同一连接导致响应配对错乱
  • 上层日志记录时间与抓包时间不一致

建议同时核对:

  • 程序日志时间
  • 抓包时间戳
  • Transaction Identifier
  • 同一 TCP 流中的请求响应顺序

推荐抓包命令模板

模板 1:标准 Modbus TCP 抓包

sudo tcpdump -i eth0 -nn -s 0 -w modbus_tcp.pcap 'tcp port 502'

模板 2:抓指定设备

sudo tcpdump -i eth0 -nn -s 0 -w modbus_device.pcap 'host 192.168.1.10 and tcp port 502'

模板 3:抓完整会话

sudo tcpdump -i eth0 -nn -s 0 -w modbus_full.pcap 'host 192.168.1.10'

模板 4:长时间轮转抓包

sudo tcpdump -i eth0 -nn -s 0 -C 100 -W 10 -w modbus_ring.pcap 'tcp port 502'

模板 5:先粗抓、后精看

sudo tcpdump -i any -nn -s 0 -w all_traffic.pcap host 192.168.1.10

适合一开始不确定端口、协议、网卡或方向时使用。


最佳实践

  • 抓包时优先使用 -s 0,避免报文被截断
  • 尽量抓到完整会话,包括 TCP 握手和断开过程
  • 抓包文件命名建议包含设备 IP、时间、问题现象
  • 问题偶发时优先使用轮转抓包
  • 分析时先看网络层是否通,再看 Modbus 协议字段是否正确
  • 不要只看“有没有响应”,还要核对响应是不是匹配的事务号
  • 如果端口不是 502,记得在 Wireshark 中使用 Decode As
  • 对照设备手册时,务必确认地址基准和数据类型定义

推荐命名格式:

modbus_192.168.1.10_2026-04-17_读寄存器超时.pcap

附录:常见 Modbus 功能码

功能码 名称 说明
0x01 Read Coils 读线圈
0x02 Read Discrete Inputs 读离散输入
0x03 Read Holding Registers 读保持寄存器
0x04 Read Input Registers 读输入寄存器
0x05 Write Single Coil 写单个线圈
0x06 Write Single Register 写单个寄存器
0x0F Write Multiple Coils 写多个线圈
0x10 Write Multiple Registers 写多个寄存器

总结

使用 tcpdump + Wireshark 分析 Modbus TCP 的核心思路可以概括为三句话:

  1. 先确认流量到底有没有到达
  2. 再确认 Modbus 报文字段到底是不是按协议发送
  3. 最后确认业务点位解释是否和设备手册一致

只要把 网卡、IP、端口、事务号、功能码、地址、数量、异常码 这几个关键点按顺序核对,绝大多数 Modbus TCP 问题都可以较快定位。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐