使用PySnmp异步遍历SNMP表仅返回首条记录,求排查方案
我来帮你排查这个问题!你的代码只返回第一条记录的核心原因是每次调用nextCmd时都使用了同一个初始OID起点,导致每次都重新从SNMPv2-MIB::system的第一个子节点开始查询,而不是从上一次的位置继续遍历后续节点。
问题拆解
- 重复使用初始OID:你的
while True循环里,每次调用nextCmd都传入ObjectType(ObjectIdentity('SNMPv2-MIB', 'system')),这会让SNMP请求每次都从system节点的第一个子对象(比如sysDescr)开始,自然每次都返回相同的第一条记录。 - 缺少遍历终止条件:没有检查何时停止遍历,即使后续没有更多节点,循环也会一直执行。
- 对象类型误解:额外提一句,
SNMPv2-MIB::system是标量对象组,不是真正的SNMP表(比如IF-MIB::ifTable才是典型的表结构)。如果你的目标是采集表数据,需要替换对应的OID。
修复后的代码
下面是调整后的代码,我顺便换成了PySnmp更推荐的async/await语法,同时修复了遍历逻辑:
import asyncio from pysnmp.hlapi.asyncio import * async def run(): snmp_engine = SnmpEngine() # 初始化查询的OID起点 current_oids = [ObjectType(ObjectIdentity('SNMPv2-MIB', 'system'))] while True: errorIndication, errorStatus, errorIndex, varBinds = await nextCmd( snmp_engine, CommunityData('public'), UdpTransportTarget(('demo.pysnmp.com', 161)), ContextData(), *current_oids, # 传入上一次的查询起点,保证遍历连续性 lexicographicMode=False # 限制只在当前OID分支下遍历,避免跳转到无关节点 ) # 处理错误情况 if errorIndication: print(errorIndication) break elif errorStatus: print(f'{errorStatus.prettyPrint()} at {errorIndex and varBinds[int(errorIndex)-1][0] or "?"}') break # 没有更多结果时退出循环 if not varBinds: break # 打印当前批次的结果 for varBind in varBinds: print(f'{varBind[0].prettyPrint()} = {varBind[1].prettyPrint()}') # 更新下一次查询的起点为当前返回的最后一个OID current_oids = [ObjectType(varBind[0]) for varBind in varBinds] asyncio.get_event_loop().run_until_complete(run())
关键修改说明
- 保存查询起点:用
current_oids变量记录上一次返回的OID,每次调用nextCmd时传入这个变量,确保查询从上一次的位置继续向后遍历。 - 添加终止逻辑:检查错误信息和空结果,及时退出循环,避免无效的重复请求。
- lexicographicMode=False:限制查询范围在当前OID分支内,不会跳到其他MIB的无关节点。
如果要采集真正的SNMP表
如果你的目标是采集表数据(比如接口状态表ifTable),只需要替换初始OID即可:
current_oids = [ObjectType(ObjectIdentity('IF-MIB', 'ifTable'))]
内容的提问来源于stack exchange,提问作者Krisz
相关产品推荐
相关产品推荐

