资讯动态

从零手搓SNMP温湿度采集:OID定位、MIB解析与Python自动化实战

发布时间:2026/10/16 10:05:56 来源:尧图企业网站定制
1. 为什么我要从零手搓一套SNMP采集机房动环监控这个事说大不大说小不小。你如果只是盯着几台服务器看温度那随便找个带屏幕的温湿度计往机柜上一贴就完事了。但一旦机柜数量上到十几个、几十个分布在不同的楼层甚至不同的楼宇靠人肉巡检就彻底不现实了。我最早接触这块的时候试过用USB温湿度记录仪便宜是便宜但每个设备都得插电脑导出数据而且没法实时告警。后来也考虑过走Modbus RTU转TCP的方案但布线成本高而且很多老机房根本没有预留485总线。最后绕来绕去还是回到了SNMP这条路上。原因很简单绝大多数企业级温湿度变送器都自带RJ45网口支持SNMP协议你只要给它配个IP剩下的就是网管软件的事了。而且SNMP是网络设备管理的通用语言交换机、路由器、UPS、精密空调都在用学会一套就能通吃。这篇文章就是把我从零搭建SNMP采集温湿度数据的完整过程记录下来包括OID怎么找、MIB怎么用、数据怎么读、读不到怎么排查。如果你手头正好有一台支持SNMP的温湿度变送器或者你正准备给机房加一套环境监控这篇笔记应该能帮你省下不少翻文档的时间。先说一下我的测试环境免得后面讲的东西对不上号。我用的是一台常见的壁挂式温湿度变送器带LCD屏和RJ45网口支持SNMP v1/v2c/v3温度量程-20~60℃湿度量程0~100%RH精度分别是±0.5℃和±3%RH。采集端我用的是一台Linux服务器装了net-snmp工具集后面也会提到用Python的pysnmp库来做自动化采集。整个调试过程大概花了一个下午其中大部分时间都耗在找OID和排查community配置上所以这两块我会讲得特别细。2. SNMP采集的整体设计思路拆解2.1 为什么选SNMP而不是Modbus或HTTP轮询在动手之前先把方案选型的逻辑理清楚这样后面遇到问题你才知道该往哪个方向调。温湿度采集常见的协议就三种Modbus、SNMP、HTTP API。Modbus最便宜但需要额外的串口服务器或者网关而且每个厂商的寄存器地址定义都不一样换一个品牌就得重新对文档。HTTP API最灵活但很多工业级变送器根本不支持而且HTTP轮询的开销比SNMP大得多不适合高频采集。SNMP的优势在于它是为网络管理而生的协议UDP 161端口请求响应模型开销极小。一个GET请求过去设备回一个GET RESPONSE整个过程就几个数据包。而且SNMP有标准的MIB结构虽然温湿度这类环境参数不在标准MIB里但厂商通常会提供私有MIB文件你导入之后就能看到可读的OID名称不用对着数字瞎猜。另外SNMP v2c支持一次请求多个OIDGetBulk采集效率比Modbus轮询高不少。当然SNMP也有坑最大的问题就是OID不统一。同样是温度A厂商可能是.1.3.6.1.4.1.XXXX.1.1.1.0B厂商可能是.1.3.6.1.4.1.YYYY.2.3.4.0完全没有规律。所以这篇文章的核心价值就是教你怎么快速定位到正确的OID而不是给你一个固定的OID列表——因为那个列表换个设备就没用了。2.2 采集架构的确定我的采集架构很简单分三层设备层、采集层、存储展示层。设备层就是温湿度变送器本身配好IP和SNMP参数之后就不用管了。采集层是一台Linux服务器跑一个Python脚本每隔60秒用SNMP GET请求拉一次数据。存储展示层我用的InfluxDB加Grafana这个不是本文重点但我会在最后简单提一下数据怎么落库。为什么采集间隔定60秒因为温湿度变化本身就很慢你就算每秒采一次数据曲线也不会有明显区别反而增加设备和网络的负担。60秒对于机房环境监控来说完全够用告警响应时间也在可接受范围内。如果你有特殊需求比如要监测空调出风口的温度波动可以缩短到10秒但一般没必要。注意SNMP默认走UDP协议不保证数据包一定到达。如果你的网络环境丢包率较高建议在采集脚本里加超时重试机制一般重试2次、超时3秒就够用了。2.3 需要提前准备的软硬件清单在开始之前你需要准备这些东西。硬件方面一台支持SNMP的温湿度变送器、一根网线、一台Linux服务器或者任何能跑Python的机器。软件方面net-snmp工具集包括snmpget、snmpwalk、snmpbulkwalk、Python 3环境、pysnmp库。如果你用的是Windows也可以装net-snmp的Windows版本命令基本一样。网络方面确保采集服务器和变送器在同一个网段或者路由可达。变送器的IP地址最好固定要么在设备上配静态IP要么在DHCP服务器上做MAC绑定。我见过太多因为IP变了导致采集断掉的情况排查半天才发现是DHCP租约到期换了地址。3. 核心细节解析与实操要点3.1 变送器端的SNMP配置拿到变送器之后第一件事不是急着用snmpwalk去扫而是先把设备本身的SNMP参数配好。大多数变送器都有一个Web配置页面你用浏览器访问它的IP就能进去。如果设备没有Web页面那就需要用厂商提供的配置工具或者通过串口命令行配置。在Web页面里你需要关注这几个参数SNMP版本、Community字符串、Trap目标地址可选、SNMP端口默认161。SNMP版本建议选v2c因为v1不支持GetBulkv3配置又太复杂v2c在安全性和便利性之间平衡得最好。Community字符串相当于一个密码默认通常是public但强烈建议你改成自定义的比如monitor2024之类的。虽然SNMP v2c的Community是明文传输的但在内网环境下改掉默认值能挡住大部分扫描器的自动探测。Trap目标地址是设备主动上报异常时用的比如温度超过阈值设备会主动发一个Trap包给采集服务器。这个功能很有用但需要采集端也配置Trap接收器。我建议先把GET采集跑通再考虑Trap。实操心得有些变送器的Web页面保存配置后需要重启才生效而且重启过程中SNMP服务会中断十几秒。所以配置完不要马上测试等设备完全启动后再操作。3.2 用snmpwalk摸清设备的OID树配置好设备端之后下一步就是用snmpwalk把设备的整个OID树扫一遍。这个命令会遍历设备上所有可用的OID输出可能很长但这是找到温湿度OID最直接的方法。snmpwalk -v 2c -c monitor2024 192.168.1.100如果设备响应正常你会看到一大堆输出格式大概是这样的SNMPv2-MIB::sysDescr.0 STRING: Temperature Humidity Sensor V2.1 SNMPv2-MIB::sysObjectID.0 OID: SNMPv2-SMI::enterprises.12345.1.1 DISMAN-EVENT-MIB::sysUpTimeInstance Timeticks: (123456) 0:20:34.56 SNMPv2-MIB::sysContact.0 STRING: adminexample.com SNMPv2-MIB::sysName.0 STRING: TH-Sensor-01 ...前面这些是标准MIB里的系统信息不是我们要找的。温湿度数据通常在enterprises分支下面也就是.1.3.6.1.4.1开头的OID。你可以用grep过滤一下snmpwalk -v 2c -c monitor2024 192.168.1.100 | grep enterprises这样输出就清爽多了。你会看到类似这样的内容SNMPv2-SMI::enterprises.12345.1.1.1.0 STRING: TH-Sensor SNMPv2-SMI::enterprises.12345.1.1.2.0 INTEGER: 25 SNMPv2-SMI::enterprises.12345.1.1.3.0 INTEGER: 58 SNMPv2-SMI::enterprises.12345.1.1.4.0 INTEGER: 1这里25和58很可能就是温度和湿度但单位是什么是摄氏度还是华氏度湿度是百分比还是原始值光看数字猜不出来必须结合厂商的MIB文件来确认。3.3 MIB文件的导入与OID名称解析MIB文件就是设备的“字典”它把数字OID映射成人类可读的名称。厂商通常会在官网提供MIB文件下载文件名一般是XXXX-MIB.txt或XXXX.mib。拿到MIB文件后你需要把它放到net-snmp的MIB目录下通常是/usr/share/snmp/mibs/。sudo cp VENDOR-MIB.txt /usr/share/snmp/mibs/然后在使用snmpwalk时加上-m参数指定MIB文件或者用-M指定MIB目录snmpwalk -v 2c -c monitor2024 -m VENDOR-MIB 192.168.1.100如果MIB文件正确加载了输出就会变成这样VENDOR-MIB::temperature.0 INTEGER: 25 VENDOR-MIB::humidity.0 INTEGER: 58 VENDOR-MIB::tempUnit.0 INTEGER: celsius看到temperature和humidity这两个名字就说明MIB导入成功了。但这里有个细节要注意MIB文件里的OID定义必须和设备的实际OID完全对应。有些厂商的MIB文件版本和固件版本不匹配导入后名称对不上这时候你就得手动对比MIB文件里的定义和设备实际返回的OID。常见坑MIB文件里的温度OID可能是.1.3.6.1.4.1.12345.1.1.2.0但设备实际返回的是.1.3.6.1.4.1.12345.1.1.2.1差了一个数字。这种情况通常是固件升级后OID变了但MIB文件没更新。解决办法是直接用数字OID去GET不要依赖MIB名称。3.4 温度值的单位换算与精度处理找到OID之后还有一个容易被忽略的问题原始值的单位换算。很多变送器为了节省传输字节会把温度值乘以10之后再发送。比如实际温度是25.3℃设备返回的是253。如果你直接把这个值当温度用就会得到253℃这种离谱的结果。怎么判断是否需要除以10看MIB文件里的描述。如果MIB里写的是INTEGER类型并且描述里有unit: 0.1 celsius或者scale: 10之类的字样那就需要除以10。如果MIB里写的是Gauge32或者INTEGER但没有缩放说明那可能就是直接值。湿度也是同样的道理。有些设备返回58表示58%RH有些返回580表示58.0%RH。我遇到过一台设备温度返回253湿度返回580两个都需要除以10。也遇到过温度返回25湿度返回58都是直接值。所以不要假设一定要看MIB文档或者用已知环境验证。验证方法很简单拿一个校准过的温湿度计放在变送器旁边等读数稳定后对比。如果SNMP读到的值是25温湿度计显示25.3那说明设备返回的是整数摄氏度精度到1℃。如果SNMP读到的值是253温湿度计显示25.3那就需要除以10。4. 实操过程与核心环节实现4.1 用snmpget精确读取温湿度OID摸清OID之后就可以用snmpget来精确读取了。假设温度OID是.1.3.6.1.4.1.12345.1.1.2.0湿度OID是.1.3.6.1.4.1.12345.1.1.3.0命令如下snmpget -v 2c -c monitor2024 192.168.1.100 .1.3.6.1.4.1.12345.1.1.2.0 .1.3.6.1.4.1.12345.1.1.3.0输出SNMPv2-SMI::enterprises.12345.1.1.2.0 INTEGER: 253 SNMPv2-SMI::enterprises.12345.1.1.3.0 INTEGER: 580一次GET请求可以带多个OID这样比分开两次请求效率高。如果你要采集的OID比较多比如还有电池电压、信号强度等都可以加在后面。4.2 Python脚本实现自动化采集命令行测试通过之后就可以写Python脚本做自动化采集了。我用的是pysnmp库安装很简单pip install pysnmp下面是一个最小可用的采集脚本from pysnmp.hlapi import * def get_snmp_data(ip, community, oids): results {} for oid in oids: errorIndication, errorStatus, errorIndex, varBinds next( getCmd(SnmpEngine(), CommunityData(community, mpModel1), # mpModel1 表示 v2c UdpTransportTarget((ip, 161), timeout3, retries2), ContextData(), ObjectType(ObjectIdentity(oid))) ) if errorIndication: print(fError: {errorIndication}) return None elif errorStatus: print(fError: {errorStatus.prettyPrint()}) return None else: for varBind in varBinds: results[oid] varBind[1].prettyPrint() return results if __name__ __main__: ip 192.168.1.100 community monitor2024 oids [ 1.3.6.1.4.1.12345.1.1.2.0, # 温度 1.3.6.1.4.1.12345.1.1.3.0, # 湿度 ] data get_snmp_data(ip, community, oids) if data: temp_raw int(data[1.3.6.1.4.1.12345.1.1.2.0]) humi_raw int(data[1.3.6.1.4.1.12345.1.1.3.0]) temperature temp_raw / 10.0 humidity humi_raw / 10.0 print(f温度: {temperature}°C, 湿度: {humidity}%RH)这个脚本每次运行采集一次数据。如果你要持续采集可以在外面套一个while True循环加time.sleep(60)。但更优雅的做法是用schedule库或者直接写进crontab。实操心得pysnmp的getCmd默认是同步阻塞的如果你要同时采集几十台设备建议用异步模式或者多线程。不过对于十几台设备的场景同步循环完全够用没必要过度设计。4.3 数据落库与可视化采集到的数据我一般直接写进InfluxDB因为它的时序特性很适合这种场景。写入的代码很简单from influxdb_client import InfluxDBClient, Point from influxdb_client.client.write_api import SYNCHRONOUS client InfluxDBClient(urlhttp://localhost:8086, tokenyour-token, orgyour-org) write_api client.write_api(write_optionsSYNCHRONOUS) point Point(environment) \ .tag(device, TH-Sensor-01) \ .field(temperature, temperature) \ .field(humidity, humidity) write_api.write(bucketmonitoring, recordpoint)Grafana那边配置一个InfluxDB数据源然后画两条曲线就完事了。温度用红色湿度用蓝色再设个阈值线超过就变黄。这套组合我用下来很稳数据保留策略设成30天磁盘占用几乎可以忽略。4.4 采集频率与超时参数的调优前面提到采集间隔定60秒但超时和重试参数也需要调。默认的timeout1秒和retries0在某些网络环境下不够用尤其是变送器本身处理能力较弱的时候。我一般设成timeout3、retries2这样即使偶尔丢一个包也能在两次重试内拿到数据。但重试也不是越多越好。如果你设了retries5而设备恰好宕机了那每次采集都会卡15秒以上整个采集周期就被拖长了。所以超时和重试要配合采集间隔来设总耗时不能超过采集间隔的一半。比如60秒采集一次那超时加重试的总时间最好控制在10秒以内。5. 常见问题与排查技巧实录5.1 SNMP连接超时的排查思路这是最常见的问题snmpget返回Timeout: No Response from 192.168.1.100。排查顺序如下排查步骤命令预期结果可能问题检查网络连通性ping 192.168.1.100有回包网络不通或IP错误检查SNMP端口nc -u 192.168.1.100 161无报错端口被防火墙拦截检查Communitysnmpget -v 2c -c public ...有响应Community配置错误检查SNMP版本snmpget -v 1 -c ...有响应版本不匹配检查设备ACL查看设备Web配置允许采集端IP设备端做了IP限制我遇到最多的情况是Community字符串配错了。有些设备的Web页面保存后不会立即生效需要点“应用”或者重启。还有一种情况是设备端配了SNMP ACL只允许特定IP访问而采集服务器的IP不在白名单里。避坑技巧如果你不确定Community是什么可以先试试public和private这两个默认值。如果都不行就只能重置设备或者翻配置文档了。5.2 OID返回noSuchObject的解决方法snmpget返回No Such Object available on this agent at this OID说明这个OID在设备上不存在。可能的原因有三个OID写错了、MIB版本不对、设备固件不支持这个OID。解决办法是先用snmpwalk扫一遍enterprises分支看看设备实际返回了哪些OID。然后拿这些OID和MIB文件里的定义对比找到对应的那个。如果MIB文件里定义的OID在设备上不存在那可能是固件版本太老需要升级固件。还有一种情况是OID的末尾.0的问题。有些OID是标量需要加.0有些是表格需要加索引。比如.1.3.6.1.4.1.12345.1.1.2是标量实际读取时要写成.1.3.6.1.4.1.12345.1.1.2.0。如果你漏了.0就会返回noSuchObject。5.3 温度值明显异常的排查如果读到的温度是253或者-1000这种明显不合理的值先别急着怀疑设备坏了。按这个顺序排查确认单位换算253可能是25.3℃需要除以10。确认符号位有些设备用-1000表示传感器故障-2000表示未校准。确认量程如果设备量程是-20~60℃那-1000肯定不是正常温度值。确认OID你可能读到了错误的OID比如读到了湿度值或者状态寄存器。我遇到过一台设备温度OID返回的值一直是32767查了MIB才知道这是“传感器未连接”的故障码。所以MIB文件里的枚举值定义一定要看不能只看OID名称。5.4 采集脚本长时间运行的稳定性问题Python脚本跑几天之后可能会因为内存泄漏或者网络异常而挂掉。解决办法有两个一是用systemd或者supervisor做进程守护挂了自动重启二是在脚本里加异常捕获和日志记录方便排查问题。import logging logging.basicConfig(filenamesnmp_collector.log, levellogging.INFO) try: data get_snmp_data(ip, community, oids) if data: # 处理数据 pass else: logging.warning(f采集失败: {ip}) except Exception as e: logging.error(f异常: {e})日志文件建议按天切割不然时间长了会占满磁盘。用logrotate配置一下就行很简单。5.5 常见问题速查表现象可能原因解决方法Timeout: No Response网络不通、Community错误、ACL限制逐项排查先用ping测试No Such ObjectOID错误、MIB不匹配、固件不支持用snmpwalk扫描实际OID温度值异常单位未换算、故障码、OID错误查MIB定义对比已知环境采集脚本崩溃内存泄漏、网络异常、未捕获异常加守护进程和异常捕获数据断断续续网络丢包、设备响应慢增加超时和重试检查网络质量Community认证失败字符串错误、版本不匹配确认v1/v2c/v3和对应参数6. 一些关于SNMP采集的零散经验SNMP v3比v2c安全得多它支持认证和加密但配置也复杂得多。你需要配用户名、认证协议MD5或SHA、认证密码、加密协议DES或AES、加密密码。如果你的环境对安全要求不高v2c完全够用。但如果你的采集流量会经过不可信网络那还是上v3。另外有些变送器支持SNMP Trap主动上报比如温度超过阈值时主动发一个Trap包。这个功能在告警场景下很有用因为不需要采集端轮询就能第一时间知道异常。但Trap是UDP单包不保证到达所以通常还是配合轮询一起用。最后说一个我踩过的坑变送器的SNMP服务在设备重启后可能需要几十秒才能就绪。如果你在设备刚上电就开始采集前几次请求可能会超时。所以采集脚本最好加一个启动延迟或者把超时重试设得宽松一点。这个细节在设备文档里通常不会写但实际部署时很容易遇到。数据落库这块如果你不想用InfluxDB也可以用MySQL或者SQLite。但时序数据用关系型数据库存查询效率会随着数据量增长而下降。InfluxDB的压缩率很高30天的温湿度数据也就几十MB非常省空间。Grafana的告警功能也很完善可以配邮件或者Webhook通知比你自己写告警逻辑省事得多。采集频率方面我再啰嗦一句不要盲目追求高频采集。温湿度变化本身就很慢60秒一次已经能捕捉到所有有意义的变化。如果你采得太频繁不仅增加设备负担还会产生大量冗余数据后期查询和分析都麻烦。我见过有人设成1秒采集一次结果一天下来几百万条数据Grafana画图都卡。后来改成60秒曲线一模一样数据量少了60倍。关于OID的稳定性不同批次的同一型号设备OID可能不一样。我遇到过同一厂商同一型号的两台变送器一台温度OID是.1.3.6.1.4.1.12345.1.1.2.0另一台是.1.3.6.1.4.1.12345.1.2.2.0。原因是固件版本不同。所以不要假设同型号设备的OID一定相同每台设备上线前都要用snmpwalk确认一遍。这个工作量不大但能避免很多后期排查的麻烦。如果你要采集的设备数量比较多建议做一个设备清单表格记录每台设备的IP、Community、温度OID、湿度OID、单位换算系数。这样后面加设备或者换设备的时候直接查表就行不用重新扫OID。这个表格用CSV或者YAML存都行Python脚本读进来批量采集。devices: - ip: 192.168.1.100 community: monitor2024 temp_oid: 1.3.6.1.4.1.12345.1.1.2.0 humi_oid: 1.3.6.1.4.1.12345.1.1.3.0 temp_scale: 0.1 humi_scale: 0.1 - ip: 192.168.1.101 community: monitor2024 temp_oid: 1.3.6.1.4.1.12345.1.2.2.0 humi_oid: 1.3.6.1.4.1.12345.1.2.3.0 temp_scale: 1.0 humi_scale: 1.0这样脚本就通用了加设备只需要改YAML文件不用动代码。这个做法我从第一次部署就沿用到现在省了很多重复劳动。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑