首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >实验室环境监控搭建:PoE以太网温湿度传感器TCP/IP数据包抓包解析

实验室环境监控搭建:PoE以太网温湿度传感器TCP/IP数据包抓包解析

原创
作者头像
盛世宏博小可
发布于 2026-09-24 13:43:21
发布于 2026-09-24 13:43:21
1630
举报

实验室环境监控搭建:PoE以太网温湿度传感器TCP/IP数据包抓包解析

一、抓包前的准备工作

1. 抓包点选择

实验室环境监控的抓包点通常有三个位置,根据排查目的选择:

抓包点

适用场景

优点

缺点

采集服务器本地网卡

验证应用层问题、确认请求是否发出

无需额外设备,Wireshark 直接抓

看不到交换机/传感器侧细节

交换机端口镜像

完整观察传感器与采集端双向流量

能抓到所有经过交换机的包

需交换机支持镜像功能

传感器接入端口镜像

排查传感器侧收发异常

最接近传感器,定位最准

需要目标端口的镜像

实验室搭建阶段推荐:直接用采集服务器本地抓包 + 交换机镜像传感器端口,双管齐下。

2. 环境准备清单

代码语言:javascript
复制
□ 交换机支持端口镜像(SPAN/Mirror),确认镜像源和目的端口
□ 采集服务器安装 Wireshark(建议 4.x 版本)
□ 传感器上电,PoE 端口协商正常(Link UP,无 CRC 错误)
□ 采集端能 Ping 通传感器(先确认网络层可达)
□ 记录传感器 IP、端口(默认 502)、从站 ID(默认 1)
□ 记录传感器寄存器映射表(地址、数据类型、缩放因子)

二、Wireshark 抓包配置

1. 基础抓包过滤器

代码语言:javascript
复制
# 只抓传感器 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

2. 显示过滤器(抓包后过滤)

代码语言:javascript
复制
# 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 == 1

3. 抓包步骤

代码语言:javascript
复制
1. 打开 Wireshark,选择采集端网卡(或连接镜像端口的网卡)
2. 设置捕获过滤器(可选,减少无关流量):
   host 192.168.100.50 and tcp port 502
3. 点击 Start 开始抓包
4. 在采集端触发一次 Modbus TCP 读取(如 Modbus Poll 或采集软件读寄存器)
5. 停止抓包,保存为 .pcapng 文件

三、Modbus TCP 数据包结构解析

1. 完整报文结构

Modbus TCP 报文由 MBAP 头(7 字节)+ PDU(协议数据单元)​ 组成:

代码语言:javascript
复制
┌─────────────────────────────────────────────────────────┐
│              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 字段​ 来界定帧边界。

2. 读保持寄存器请求(功能码 0x03)

请求报文(采集端 → 传感器):

代码语言:javascript
复制
十六进制:  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。

3. 读保持寄存器响应

正常响应报文(传感器 → 采集端):

代码语言:javascript
复制
十六进制:  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)

验证计算:

  • 温度:0x0938 = 9×256 + 56 = 2304 + 56 = 2360 → 2360 × 0.1 = 23.6℃
  • 湿度:0x022A = 2×256 + 42 = 512 + 42 = 554 → 554 × 0.1 = 55.4%RH

4. 异常响应

异常报文(传感器 → 采集端):

代码语言:javascript
复制
十六进制:  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

从站设备故障

传感器内部错误


四、Wireshark 中 Modbus TCP 报文的实际解析

1. 请求报文在 Wireshark 中的展开

代码语言:javascript
复制
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: 2

2. 响应报文在 Wireshark 中的展开

代码语言:javascript
复制
Frame 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.4

3. 统计与分析技巧

IO Graph(流量图):

代码语言:javascript
复制
Wireshark → Statistics → IO Graph
  - 设置 Y 轴为 "Packets/s"
  - 时间刻度 1s 或 100ms
  - 观察采集周期是否均匀
  - 如果发现采集间隔忽长忽短,可能是网络拥塞或采集端调度问题

Conversations(会话统计):

代码语言:javascript
复制
Wireshark → Statistics → Conversations → TCP
  - 查看采集端与传感器的 TCP 会话
  - 关注:数据包数量、字节数、持续时间
  - 如果发现某个会话有大量重传包,说明该链路有问题

Expert Information(专家信息):

代码语言:javascript
复制
Wireshark → Analyze → Expert Information
  - 红色/黄色警告重点关注
  - 常见问题:重传、乱序、零窗口、连接重置

五、常见抓包场景与解析

场景 1:采集端读不到数据

抓包现象:只看到 SYN,没有 SYN-ACK

代码语言:javascript
复制
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 配置错误、防火墙拦截。

场景 2:连接建立但读不到数据

抓包现象:三次握手成功,但 Modbus 请求后无响应

代码语言:javascript
复制
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 与采集端一致。

场景 3:响应异常(异常码 0x02)

代码语言:javascript
复制
响应报文功能码为 0x83,异常码为 0x02(非法数据地址)

判断:采集端请求的寄存器地址超出传感器支持的范围。核对传感器寄存器映射表,确认地址是 0-based 还是 1-based。

场景 4:TCP 重传严重

代码语言:javascript
复制
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 错误、或电磁干扰。检查交换机端口统计、更换网线、确认屏蔽层接地。

场景 5:连接被重置

代码语言:javascript
复制
No.   Source          Destination     Protocol  Info
8     192.168.100.50  192.168.100.100 TCP       502 → 49152 [RST, ACK]

判断:传感器主动关闭连接。可能是采集端连接数超过传感器上限、或传感器内部看门狗复位。限制采集端并发连接数,检查传感器日志。


六、UDP 报文抓包解析(如有告警推送)

1. 抓包过滤器

代码语言:javascript
复制
# 抓 UDP 流量
udp

# 抓指定端口的 UDP
udp port 8888

# 抓指定传感器的 UDP
ip.addr == 192.168.100.50 and udp

2. 报文解析

以常见的 24 字节 UDP 告警报文为例:

代码语言:javascript
复制
十六进制:  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 端口关联为自定义协议,但私有格式通常需要手动解析或用脚本处理。


七、抓包分析自动化(Python 脚本)

1. 用 scapy 解析 pcap 文件

代码语言:javascript
复制
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")

2. 实时抓包与告警

代码语言:javascript
复制
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)

八、实验室搭建验收清单

1. 网络层验证

代码语言:javascript
复制
□ 传感器 PoE 供电正常(交换机端口状态、功耗)
□ 传感器 IP 可达(Ping 延迟 < 2ms,0% 丢包)
□ TCP 502 端口可达(Telnet / nc 测试)
□ 交换机端口无 CRC 错误、无丢包
□ 端口速率协商正确(100M/1000M Full Duplex)

2. 协议层验证

代码语言:javascript
复制
□ Wireshark 抓到完整的三次握手
□ Modbus TCP 请求报文格式正确(MBAP 头 + PDU)
□ 传感器响应正常(功能码 0x03,数据字节数正确)
□ 数据解析正确(与标准温湿度计比对,偏差 ≤ 0.5℃/≤3%RH)
□ 无异常响应(无 0x80+ 功能码)
□ 无 TCP 重传(或重传率 < 0.1%)
□ 无 TCP 连接重置

3. 稳定性验证

代码语言:javascript
复制
□ 连续采集 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 删除。

目录
  • 实验室环境监控搭建:PoE以太网温湿度传感器TCP/IP数据包抓包解析
  • 一、抓包前的准备工作
    • 1. 抓包点选择
    • 2. 环境准备清单
  • 二、Wireshark 抓包配置
    • 1. 基础抓包过滤器
    • 2. 显示过滤器(抓包后过滤)
    • 3. 抓包步骤
  • 三、Modbus TCP 数据包结构解析
    • 1. 完整报文结构
    • 2. 读保持寄存器请求(功能码 0x03)
    • 3. 读保持寄存器响应
    • 4. 异常响应
  • 四、Wireshark 中 Modbus TCP 报文的实际解析
    • 1. 请求报文在 Wireshark 中的展开
    • 2. 响应报文在 Wireshark 中的展开
    • 3. 统计与分析技巧
  • 五、常见抓包场景与解析
    • 场景 1:采集端读不到数据
    • 场景 2:连接建立但读不到数据
    • 场景 3:响应异常(异常码 0x02)
    • 场景 4:TCP 重传严重
    • 场景 5:连接被重置
  • 六、UDP 报文抓包解析(如有告警推送)
    • 1. 抓包过滤器
    • 2. 报文解析
  • 七、抓包分析自动化(Python 脚本)
    • 1. 用 scapy 解析 pcap 文件
    • 2. 实时抓包与告警
  • 八、实验室搭建验收清单
    • 1. 网络层验证
    • 2. 协议层验证
    • 3. 稳定性验证
  • 九、常见返工点
  • 十、一句话总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档