

实验室环境监控的抓包点通常有三个位置,根据排查目的选择:
抓包点 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
采集服务器本地网卡 | 验证应用层问题、确认请求是否发出 | 无需额外设备,Wireshark 直接抓 | 看不到交换机/传感器侧细节 |
交换机端口镜像 | 完整观察传感器与采集端双向流量 | 能抓到所有经过交换机的包 | 需交换机支持镜像功能 |
传感器接入端口镜像 | 排查传感器侧收发异常 | 最接近传感器,定位最准 | 需要目标端口的镜像 |
实验室搭建阶段推荐:直接用采集服务器本地抓包 + 交换机镜像传感器端口,双管齐下。

□ 交换机支持端口镜像(SPAN/Mirror),确认镜像源和目的端口
□ 采集服务器安装 Wireshark(建议 4.x 版本)
□ 传感器上电,PoE 端口协商正常(Link UP,无 CRC 错误)
□ 采集端能 Ping 通传感器(先确认网络层可达)
□ 记录传感器 IP、端口(默认 502)、从站 ID(默认 1)
□ 记录传感器寄存器映射表(地址、数据类型、缩放因子)# 只抓传感器 IP 的流量(替换为你实际的传感器 IP)
host 192.168.100.50
# 抓传感器 IP 的 TCP 流量(Modbus TCP 走 TCP)
host 192.168.100.50 and tcp
# 抓传感器 IP 的 TCP 502 端口流量
host 192.168.100.50 and tcp port 502
# 如果同时抓多台传感器
host 192.168.100.50 or host 192.168.100.51 or host 192.168.100.52
# 或更简洁
net 192.168.100.0/24 and tcp port 502# Modbus TCP 协议
modbus
# TCP 502 端口
tcp.port == 502
# 特定传感器
ip.addr == 192.168.100.50
# 组合:指定传感器的 Modbus TCP 流量
ip.addr == 192.168.100.50 and tcp.port == 502
# 只看 Modbus 请求(采集端 → 传感器)
ip.dst == 192.168.100.50 and modbus
# 只看 Modbus 响应(传感器 → 采集端)
ip.src == 192.168.100.50 and modbus
# TCP 重传包
tcp.analysis.retransmission
# TCP 重复 ACK
tcp.analysis.duplicate_ack
# TCP 零窗口
tcp.zero_window
# TCP 连接重置
tcp.flags.reset == 1
# 连接建立/断开
tcp.flags.syn == 1
tcp.flags.fin == 11. 打开 Wireshark,选择采集端网卡(或连接镜像端口的网卡)
2. 设置捕获过滤器(可选,减少无关流量):
host 192.168.100.50 and tcp port 502
3. 点击 Start 开始抓包
4. 在采集端触发一次 Modbus TCP 读取(如 Modbus Poll 或采集软件读寄存器)
5. 停止抓包,保存为 .pcapng 文件Modbus TCP 报文由 MBAP 头(7 字节)+ PDU(协议数据单元) 组成:
┌─────────────────────────────────────────────────────────┐
│ MBAP Header(7 字节) │
├──────────┬──────────┬──────────┬────────────────────────┤
│ 事务标识 │ 协议标识 │ 长度 │ 单元标识(从站地址) │
│ TID │ PID │ Length │ Unit ID │
│ 2 字节 │ 2 字节 │ 2 字节 │ 1 字节 │
│ (0001) │ (0000) │ (0006) │ (01) │
├──────────┼──────────┼──────────┼────────────────────────┤
│ PDU(协议数据单元) │
├──────────┬──────────────────────────────────────────────┤
│ 功能码 │ 数据 │
│ Function │ Data │
│ 1 字节 │ N 字节 │
│ (03) │ (寄存器地址、数量等) │
└──────────┴──────────────────────────────────────────────┘关键区别:Modbus RTU 用 CRC16 校验(2 字节),Modbus TCP 去掉了 CRC,改用 MBAP 头中的 Length 字段 来界定帧边界。
请求报文(采集端 → 传感器):
十六进制: 00 01 00 00 00 06 01 03 00 00 00 02逐字节解析:
字节 | 值(hex) | 含义 |
|---|---|---|
0-1 | 00 01 | TID(Transaction ID)事务标识 = 1 |
2-3 | 00 00 | PID(Protocol ID)协议标识 = 0(标准 Modbus) |
4-5 | 00 06 | Length = 6(后面有 6 字节:Unit ID 1 + PDU 5) |
6 | 01 | Unit ID = 1(从站地址) |
7 | 03 | 功能码 = 0x03(读保持寄存器) |
8-9 | 00 00 | 起始地址 = 0(对应寄存器 40001) |
10-11 | 00 02 | 寄存器数量 = 2(读 2 个寄存器:温度 + 湿度) |
注意:起始地址 0 对应寄存器编号 40001,这是 0-based 与 1-based 的对应关系。如果采集软件配的是 40001,实际发送的地址是 0。
正常响应报文(传感器 → 采集端):
十六进制: 00 01 00 00 00 07 01 03 04 09 38 02 2A逐字节解析:
字节 | 值(hex) | 含义 |
|---|---|---|
0-1 | 00 01 | TID = 1(与请求对应) |
2-3 | 00 00 | PID = 0 |
4-5 | 00 07 | Length = 7(Unit ID 1 + PDU 6) |
6 | 01 | Unit ID = 1 |
7 | 03 | 功能码 = 0x03 |
8 | 04 | 字节数 = 4(返回 2 个寄存器 × 2 字节 = 4 字节) |
9-10 | 09 38 | 寄存器值 1 = 0x0938 = 2360(温度 = 2360 × 0.1 = 23.6℃) |
11-12 | 02 2A | 寄存器值 2 = 0x022A = 554(湿度 = 554 × 0.1 = 55.4%RH) |
验证计算:

异常报文(传感器 → 采集端):
十六进制: 00 01 00 00 00 05 01 83 02字节 | 值(hex) | 含义 |
|---|---|---|
0-1 | 00 01 | TID = 1 |
2-3 | 00 00 | PID = 0 |
4-5 | 00 05 | Length = 5 |
6 | 01 | Unit ID = 1 |
7 | 83 | 功能码 + 0x80 = 0x83(异常标志) |
8 | 02 | 异常码 = 0x02(非法数据地址) |
常见异常码:
异常码 | 含义 | 可能原因 |
|---|---|---|
01 | 非法功能码 | 传感器不支持该功能码 |
02 | 非法数据地址 | 寄存器地址超出范围 |
03 | 非法数据值 | 寄存器数量过多或值不合法 |
04 | 从站设备故障 | 传感器内部错误 |
Frame 42: 74 bytes on wire (592 bits)
Ethernet II, Src: 00:0c:29:aa:bb:01, Dst: 00:0c:29:cc:dd:02
Internet Protocol Version 4, Src: 192.168.100.100, Dst: 192.168.100.50
Transmission Control Protocol, Src Port: 49152, Dst Port: 502, Seq: 1, Ack: 1
Modbus/TCP
Transaction Identifier: 0x0001
Protocol Identifier: 0x0000
Length: 6
Unit Identifier: 1
Function Code: 3 (Read Holding Registers)
Reference Number: 0
Word Count: 2Frame 44: 74 bytes on wire (592 bits)
Ethernet II, Src: 00:0c:29:cc:dd:02, Dst: 00:0c:29:aa:bb:01
Internet Protocol Version 4, Src: 192.168.100.50, Dst: 192.168.100.100
Transmission Control Protocol, Src Port: 502, Dst Port: 49152, Seq: 1, Ack: 13
Modbus/TCP
Transaction Identifier: 0x0001
Protocol Identifier: 0x0000
Length: 7
Unit Identifier: 1
Function Code: 3 (Read Holding Registers)
Byte Count: 4
Data
Register 0 (40001): 0x0938 (2360) → 23.6
Register 1 (40002): 0x022A (554) → 55.4IO Graph(流量图):
Wireshark → Statistics → IO Graph
- 设置 Y 轴为 "Packets/s"
- 时间刻度 1s 或 100ms
- 观察采集周期是否均匀
- 如果发现采集间隔忽长忽短,可能是网络拥塞或采集端调度问题Conversations(会话统计):
Wireshark → Statistics → Conversations → TCP
- 查看采集端与传感器的 TCP 会话
- 关注:数据包数量、字节数、持续时间
- 如果发现某个会话有大量重传包,说明该链路有问题Expert Information(专家信息):
Wireshark → Analyze → Expert Information
- 红色/黄色警告重点关注
- 常见问题:重传、乱序、零窗口、连接重置抓包现象:只看到 SYN,没有 SYN-ACK
No. Source Destination Protocol Info
1 192.168.100.100 192.168.100.50 TCP 49152 → 502 [SYN]
2 192.168.100.100 192.168.100.50 TCP 49152 → 502 [SYN]
3 192.168.100.100 192.168.100.50 TCP 49152 → 502 [SYN]判断:传感器 IP 不可达或 502 端口未监听。可能是传感器未上电、IP 配置错误、防火墙拦截。
抓包现象:三次握手成功,但 Modbus 请求后无响应
No. Source Destination Protocol Info
1 192.168.100.100 192.168.100.50 TCP [SYN]
2 192.168.100.50 192.168.100.100 TCP [SYN, ACK]
3 192.168.100.100 192.168.100.50 TCP [ACK]
4 192.168.100.100 192.168.100.50 Modbus/TCP [TCP segment of a reassembled PDU]
5 (无响应,3秒后出现超时重传)判断:传感器 Modbus TCP 服务未启用,或从站 ID 不匹配。登录传感器 Web 界面确认 Modbus TCP 已开启,从站 ID 与采集端一致。
响应报文功能码为 0x83,异常码为 0x02(非法数据地址)判断:采集端请求的寄存器地址超出传感器支持的范围。核对传感器寄存器映射表,确认地址是 0-based 还是 1-based。
No. Source Destination Protocol Info
10 192.168.100.100 192.168.100.50 TCP [TCP Retransmission] 502→49152
15 192.168.100.100 192.168.100.50 TCP [TCP Retransmission] 502→49152
22 192.168.100.100 192.168.100.50 TCP [TCP Retransmission] 502→49152判断:网络链路质量差,可能是网线问题、交换机端口 CRC 错误、或电磁干扰。检查交换机端口统计、更换网线、确认屏蔽层接地。
No. Source Destination Protocol Info
8 192.168.100.50 192.168.100.100 TCP 502 → 49152 [RST, ACK]判断:传感器主动关闭连接。可能是采集端连接数超过传感器上限、或传感器内部看门狗复位。限制采集端并发连接数,检查传感器日志。
# 抓 UDP 流量
udp
# 抓指定端口的 UDP
udp port 8888
# 抓指定传感器的 UDP
ip.addr == 192.168.100.50 and udp以常见的 24 字节 UDP 告警报文为例:
十六进制: AA 55 00 00 00 64 66 78 9A BC 00 0A 09 38 02 2A 00 01 12 D6 00 00 00 00 3F 8E字节 | 值(hex) | 含义 |
|---|---|---|
0-1 | AA 55 | 帧头 |
2-5 | 00 00 00 64 | 设备 ID = 100 |
6-9 | 66 78 9A BC | 时间戳(Unix time) |
10-11 | 00 0A | 序列号 = 10 |
12-13 | 09 38 | 温度 = 2360 → 23.6℃ |
14-15 | 02 2A | 湿度 = 554 → 55.4%RH |
16-17 | 00 01 | 状态字 = bit0 高温告警 |
18-19 | 12 D6 | 电源电压 = 4822 → 48.22V |
20-21 | 00 00 | RSSI(未使用) |
22-23 | 3F 8E | CRC16 校验值 |
Wireshark 中可以通过"解码为"(Decode As)将 UDP 端口关联为自定义协议,但私有格式通常需要手动解析或用脚本处理。
from scapy.all import *
from scapy.layers.inet import TCP
def analyze_modbus_pcap(pcap_file):
packets = rdpcap(pcap_file)
for pkt in packets:
if pkt.haslayer(TCP):
tcp = pkt[TCP]
# 检查是否是 Modbus TCP(端口 502)
if tcp.dport == 502 or tcp.sport == 502:
payload = bytes(tcp.payload)
if len(payload) >= 8:
tid = int.from_bytes(payload[0:2], 'big')
pid = int.from_bytes(payload[2:4], 'big')
length = int.from_bytes(payload[4:6], 'big')
unit_id = payload[6]
func_code = payload[7]
print(f"TID={tid:04x} PID={pid:04x} Len={length} "
f"Unit={unit_id} Func=0x{func_code:02x}")
# 解析响应中的数据
if len(payload) > 9 and func_code == 0x03 and tcp.sport == 502:
byte_count = payload[8]
data_bytes = payload[9:9+byte_count]
for i in range(0, byte_count, 2):
reg_val = int.from_bytes(data_bytes[i:i+2], 'big')
print(f" 寄存器 {i//2}: 0x{reg_val:04x} = {reg_val} ({reg_val*0.1}℃)")
analyze_modbus_pcap("lab_capture.pcapng")from scapy.all import *
from collections import deque
# 保存最近 100 个 TID,用于检测响应是否匹配
recent_tids = deque(maxlen=100)
def packet_callback(pkt):
if pkt.haslayer(TCP):
tcp = pkt[TCP]
payload = bytes(tcp.payload)
# 检测 Modbus TCP 请求
if tcp.dport == 502 and len(payload) >= 8:
tid = int.from_bytes(payload[0:2], 'big')
func_code = payload[7]
recent_tids.append(tid)
print(f"[REQ] TID={tid} Func=0x{func_code:02x}")
# 检测异常响应
if tcp.sport == 502 and len(payload) >= 9:
func_code = payload[7]
if func_code > 0x80:
err_code = payload[8]
print(f"[ERR] TID={int.from_bytes(payload[0:2],'big')} "
f"Exception=0x{err_code:02x}")
# 开始抓包(需要 root/admin 权限)
sniff(filter="tcp port 502", prn=packet_callback, store=0)□ 传感器 PoE 供电正常(交换机端口状态、功耗)
□ 传感器 IP 可达(Ping 延迟 < 2ms,0% 丢包)
□ TCP 502 端口可达(Telnet / nc 测试)
□ 交换机端口无 CRC 错误、无丢包
□ 端口速率协商正确(100M/1000M Full Duplex)□ Wireshark 抓到完整的三次握手
□ Modbus TCP 请求报文格式正确(MBAP 头 + PDU)
□ 传感器响应正常(功能码 0x03,数据字节数正确)
□ 数据解析正确(与标准温湿度计比对,偏差 ≤ 0.5℃/≤3%RH)
□ 无异常响应(无 0x80+ 功能码)
□ 无 TCP 重传(或重传率 < 0.1%)
□ 无 TCP 连接重置□ 连续采集 24h,在线率 100%
□ 数据曲线平滑,无跳变
□ 拔网线 5s/30s 后恢复,自动重连成功
□ 传感器重启后配置保持,自动上线
□ Wireshark 抓包文件归档(含时间戳、传感器 IP)问题 | 后果 | 正确做法 |
|---|---|---|
抓包点选错 | 看不到关键报文 | 服务器本地 + 交换机镜像双管齐下 |
不设置捕获过滤器 | 抓包文件过大,分析困难 | 限定 sensor IP + TCP 502 |
只抓请求不看响应 | 无法判断传感器是否响应 | 双向报文都要抓 |
不保存 pcap 文件 | 问题无法回溯 | 抓包后立即保存归档 |
MBAP 头 TID 不匹配 | 请求与响应无法对应 | 按 TID 配对分析 |
地址偏移理解错误 | 读错寄存器 | 抓包中确认实际地址字节 |
忽略 TCP 重传统计 | 链路问题被掩盖 | 用 Expert Information 检查 |
抓包是实验室搭建阶段最有价值的排障手段。 一次完整的抓包能告诉你:连接是否建立、请求是否正确、响应是否正常、数据是否准确、链路是否可靠。 记住 Modbus TCP 报文的三要素:MBAP 头(TID/PID/Length/UnitID)+ 功能码 + 数据,对着十六进制逐字节解析,问题无所遁形。 实验室阶段把抓包流程跑顺、把报文结构吃透,到了现场遇到任何通讯问题,你都能靠一个 pcap 文件快速定位。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。