首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >SNMP 与 Modbus TCP 双协议并行:网口温湿度变送器在监控网络中的端口冲突复盘

SNMP 与 Modbus TCP 双协议并行:网口温湿度变送器在监控网络中的端口冲突复盘

原创
作者头像
盛世宏博科技
发布2026-09-22 11:48:30
发布2026-09-22 11:48:30
330
举报

SNMP 与 Modbus TCP 双协议并行:网口温湿度变送器在监控网络中的端口冲突复盘

近期在调试一套工业环境监控系统时,遇到了关于 Modbus 连接保持的问题。现场部署了一批 恒湿净化设备(包括 @恒湿消毒净化一体机 等),主要用来维持特定环境的温湿度指标。在长时间运行后,发现设备偶尔会掉线。把 SNMP 和 Modbus TCP 做成"双协议并行"之后,系统上线初期一切正常,但运行两周后开始出现间歇性连接拒绝、SNMP 超时、Modbus 寄存器读不全的诡异现象。排查到最后,根因不是代码 bug,而是端口冲突 + MCU 资源耗尽 + 网络栈行为叠加——这篇把完整复盘写出来。


一、故障现象:两周后开始"抽风"

代码语言:javascript
复制
时间线:
  Day 1–3:正常,86 台传感器 Modbus TCP 轮询 OK,SNMP Trap 秒级推送
  Day 4–7:偶发,约 3–5 台传感器 Modbus 读超时,重试后恢复
  Day 8–10:加剧,每天上午 10 点左右集中爆发,持续 15–30 分钟后自愈
  Day 11–14:全天不稳定,约 20% 传感器 Modbus 连接被 RST,SNMP Trap 丢包率飙升

诡异之处

  • 不是全部同时挂,是"一批一批地挂"
  • 上午 10 点集中爆发 → 恰好是恒湿机集中启动 + 新风系统切换时段
  • ping 通,但 502 端口连不上
  • SNMP Trap 偶尔能收到,但 snmpwalk 超时
  • 重启传感器 → 恢复几分钟 → 又挂

二、排查过程:从应用层一路追到 MCU

第一轮:以为是网络问题

代码语言:javascript
复制
检查项:
  ✅ 交换机端口无 error、无 CRC
  ✅ 无广播风暴(交换机开启风暴抑制)
  ✅ POE 供电正常(电压 48V,电流正常)
  ✅ 网线无松动
  ✅ VLAN 配置正确,无 ACL 拦截

→ 网络层排除。

第二轮:以为是网关轮询太快

代码语言:javascript
复制
检查项:
  ✅ 并发 30,每台 30s 一轮
  ✅ 超时 1.5s,重试 3 次
  ✅ 没有频繁建连/断连(长连接复用)

→ 轮询参数排除。

第三轮:Wireshark 抓包,发现端倪

代码语言:javascript
复制
抓包发现的关键帧:

1. TCP 三次握手正常
2. Modbus 请求发出
3. 传感器响应:TCP ZeroWindow(接收窗口为 0)
4. 网关重试 → TCP Retransmission
5. 传感器:TCP RST, ACK → 连接被重置

同时段 UDP:
  SNMP Trap 帧到达,但传感器没有响应 snmpwalk 的 GetRequest

关键线索TCP ZeroWindow + SNMP 无响应 → MCU 侧接收缓冲区满了,处理不过来。

第四轮:登录传感器 Web 管理(部分型号支持)

代码语言:javascript
复制
系统信息页:
  CPU: 168MHz (STM32F407)
  RAM: 192KB (实际可用 ~128KB,其余被 LWIP + 应用占用)
  TCP Connections: 4/4 (已满!)
  UDP Sockets: 2/2 (已满!)
  Free Heap: 2.1KB (危险水位)

根因浮出水面:MCU 资源耗尽,TCP 连接池满了,新的 Modbus 连接被 RST;SNMP 的 UDP 接收缓冲区也满了,GetRequest 被丢弃。


三、根因分析:三个问题叠加

问题 1:TCP 连接池被"半连接"占满

代码语言:javascript
复制
场景还原:
  网关 A(Modbus 轮询) → 长连接,正常
  网关 B(SCADA 系统)  → 也连了同一批传感器(之前没发现)
  运维笔记本             → 偶尔 snmpwalk,每次新建 TCP 连接(SNMP over TCP?不,但 Web 管理用 TCP:80)

  → 4 个 TCP 连接槽位被占:
     Slot 1: 网关 A 长连接(正常)
     Slot 2: 网关 B 长连接(之前不知道)
     Slot 3: Web 管理界面(有人开着没关)
     Slot 4: SNMP Trap 的某种内部 TCP 回调(固件 bug)

为什么之前没发现:网关 B 是旧系统,一直连着这些传感器做 SCADA 展示,但没人告诉新系统。两套系统同时轮询,连接池直接打满。

问题 2:SNMP Trap 和 Modbus TCP 抢 LWIP 的 pbuf 池

代码语言:javascript
复制
LWIP 配置:
  PBUF_POOL_SIZE = 16
  PBUF_POOL_BUFSIZE = 256

场景:
  上午 10 点,恒湿机启动 → 温湿度波动 → 触发 SNMP Trap
  → 86 台传感器同时发 UDP Trap
  → 每台 Trap 帧 82 bytes + IP/TCP/UDP 头 ≈ 150 bytes
  → 86 × 150 = 12.9KB,看起来不大

  但!LWIP 的 pbuf 是固定大小的:
    16 个 pbuf × 256 bytes = 4KB 总池
    Modbus TCP 响应需要 pbuf(每个连接约 2–3 个 pbuf)
    SNMP Trap 需要 pbuf(每个 UDP 帧 1 个 pbuf)
    同时到达时,pbuf 池耗尽 → Modbus 响应分配不到内存 → ZeroWindow

问题 3:恒湿机启动时的"微环境震荡"

代码语言:javascript
复制
上午 10 点恒湿机启动 → 局部气流扰动 → 温湿度快速变化
→ 传感器采样频率自动提高(部分型号有"快速响应模式")
→ 采样间隔从 1s 变成 200ms
→ 内部计算负载增加
→ LWIP 接收中断被延迟
→ TCP 窗口更新不及时 → ZeroWindow

四、解决方案:四管齐下

方案 1:清理"隐形连接"

代码语言:javascript
复制
1. 找到网关 B(SCADA),停止对这 86 台传感器的轮询
2. 传感器 Web 管理页面加会话超时(15 分钟自动踢出)
3. 固件升级:修复 SNMP Trap 内部 TCP 回调的 bug(联系厂商)

方案 2:LWIP 参数调优

代码语言:javascript
复制
// 调整前
#define PBUF_POOL_SIZE          16
#define PBUF_POOL_BUFSIZE       256
#define MEMP_NUM_TCP_PCB        4
#define MEMP_NUM_UDP_PCB        2
#define TCP_WND                 4096
#define TCP_SND_BUF             4096

// 调整后
#define PBUF_POOL_SIZE          32        // 翻倍
#define PBUF_POOL_BUFSIZE       512       // 翻倍(适应 Modbus TCP 大帧)
#define MEMP_NUM_TCP_PCB        2         // 限制 TCP 连接数,宁可拒绝也不要撑死
#define MEMP_NUM_UDP_PCB        4         // UDP 多给点(Trap 用)
#define TCP_WND                 2048      // 缩小窗口,避免接收方缓冲区溢出
#define TCP_SND_BUF             2048
#define TCP_MSS                 256        // 减小 MSS,分片更细

关键思路:不是"越大越好",而是限制 TCP 连接数 + 给 UDP 更多 pbuf + 缩小 TCP 窗口避免撑死接收方

方案 3:网关侧限流

代码语言:javascript
复制
# 网关侧加 SNMP Trap 接收速率限制
import asyncio
from asyncio import Semaphore

TRAP_RATE_LIMIT = 20  # 每秒最多处理 20 个 Trap
trap_semaphore = Semaphore(TRAP_RATE_LIMIT)

async def on_trap_received(frame):
    async with trap_semaphore:
        await process_trap(frame)
        await asyncio.sleep(0.05)  # 50ms 间隔,给 MCU 喘息时间

方案 4:恒湿机联动错峰

代码语言:javascript
复制
恒湿机启动策略从"统一启动"改为"分批启动":
  - 8 台恒湿机,每台间隔 2 分钟
  - 避免所有传感器同时进入"快速响应模式"
  - 边缘网关在恒湿机启动时段临时降低轮询频率(从 30s → 60s)

五、端口冲突的 5 种真实场景

复盘过程中,整理了现场常见的"端口冲突"类型:

冲突类型

现象

根因

解决

多主站抢 TCP 连接​

Modbus 间歇性 RST

MCU 连接池满

限制主站数量,或用 RTU 转 TCP 网关做"一主多从"

SNMP Trap 和 Modbus 抢 pbuf​

ZeroWindow + Trap 丢包

LWIP 内存池不足

调大 pbuf + 限制 Trap 速率

Web 管理和 Modbus 端口冲突​

打开 Web 页面后 Modbus 变慢

同一 TCP 栈,Web 占连接

加 Web 会话超时,或 Web 走独立端口

SNMP GetRequest 和 Trap 共用 UDP 端口​

snmpwalk 超时

固件 bug:GetRequest 处理阻塞 Trap 发送

固件升级,或 Get 和 Trap 用不同端口

交换机端口安全限制​

传感器 MAC 被交换机封锁

交换机端口安全策略(MAC 数量限制)

调整交换机端口安全策略


六、预防措施:上线前必做的 6 项检查

  1. 端口扫描nmap -sT -p 1-65535 <sensor_ip> 确认开放端口和协议
  2. 连接数测试:用 nctelnet 同时开 N 个连接到 502 端口,看第几个被拒
  3. pbuf 监控:如果传感器支持 SNMP 或 Web 管理,看系统资源页的 Free Heap
  4. Trap 风暴测试:模拟 86 台同时发 Trap,看 Modbus 是否受影响
  5. 长稳测试:连续跑 72 小时,监控 TCP 重传率和 RST 包数量
  6. 多主站检测:用 Wireshark 抓包,确认只有预期的主站在轮询

七、一句话总结

SNMP 和 Modbus TCP 双协议并行不是"开两个端口"那么简单,MCU 的 TCP 连接池、LWIP 的 pbuf 内存池、以及外部系统的"隐形连接"都会成为瓶颈。​ 排错时别只看应用层,Wireshark 的 ZeroWindowRST 才是真正的线索。上线前做连接数压测和 pbuf 监控,比事后救火省十倍时间。

物联网 #Modbus #TCP/IP #UDP #POE供电 #腾讯云 #Wireshark #Python #InfluxDB #以太网温湿度传感器 #网口温湿度变送器 #机房监控


下一篇候选:

  1. 《LWIP 协议栈调优实战:pbuf 池大小、TCP 窗口与 UDP 缓冲区在温湿度变送器中的参数配置》
  2. 《多主站共存方案:SCADA 与边缘网关如何通过 Modbus TCP 网关实现"一主多从"》
  3. 《传感器固件逆向:从 Wireshark 抓包到寄存器映射表还原的完整流程》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • SNMP 与 Modbus TCP 双协议并行:网口温湿度变送器在监控网络中的端口冲突复盘
    • 一、故障现象:两周后开始"抽风"
    • 二、排查过程:从应用层一路追到 MCU
      • 第一轮:以为是网络问题
      • 第二轮:以为是网关轮询太快
      • 第三轮:Wireshark 抓包,发现端倪
      • 第四轮:登录传感器 Web 管理(部分型号支持)
    • 三、根因分析:三个问题叠加
      • 问题 1:TCP 连接池被"半连接"占满
      • 问题 2:SNMP Trap 和 Modbus TCP 抢 LWIP 的 pbuf 池
      • 问题 3:恒湿机启动时的"微环境震荡"
    • 四、解决方案:四管齐下
      • 方案 1:清理"隐形连接"
      • 方案 2:LWIP 参数调优
      • 方案 3:网关侧限流
      • 方案 4:恒湿机联动错峰
    • 五、端口冲突的 5 种真实场景
    • 六、预防措施:上线前必做的 6 项检查
    • 七、一句话总结
  • 物联网 #Modbus #TCP/IP #UDP #POE供电 #腾讯云 #Wireshark #Python #InfluxDB #以太网温湿度传感器 #网口温湿度变送器 #机房监控
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档