pysnmp 中的异步代码未按预期响应
asyncio code in pysnmp is not responding as expected
我是 pysnmp 库的新手。我尝试了 snmplabs 文档中提供的示例代码,并进行了一些修改,如下所示。
import asyncio
from pysnmp.hlapi.asyncio import *
@asyncio.coroutine
def run(host,oid):
errorIndication, errorStatus, errorIndex, varBinds = yield from getCmd(
SnmpEngine(),
CommunityData('public'),
UdpTransportTarget((host, 161)),
ContextData(),
ObjectType(ObjectIdentity(oid))
)
print(errorIndication, errorStatus, errorIndex, varBinds)
asyncio.get_event_loop().run_until_complete(run('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
print("asynch_1")
asyncio.get_event_loop().run_until_complete(run('198.155.104.8','1.3.6.1.2.1.1.1.0'))
print("asynch_2")
asyncio.get_event_loop().run_until_complete(run('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
print("asynch_3")
在上面我尝试查询不同代理的get-command。其中“198.155.104.8”是一个不存在的虚拟代理ip。
我希望输出为
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fdaa071e400 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fcf8c88 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fdaa085e7b8 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fdaa07a1fd0 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa085e780 consts 0, 255>> encoding iso-8859-1 payload [Linux zeus 4.8.6...11 CDT 2016 i686]>)]
asynch_1
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fda9fba2da0 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fbaa828 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fda9fac1c88 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fda9f9e5cf8 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa36e4048 consts 0, 255>> encoding iso-8859-1 payload [Cisco Internetwo...5:14 by kellythw]>)]
asynch_3
No SNMP response received before timeout 0 0 []
asynch_2
由于没有引用“198.155.104.8”的代理,代码不应在第二个请求中等待,它应该打印第三个请求。
但我得到的输出如下所示
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fdaa071e400 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fcf8c88 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fdaa085e7b8 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fdaa07a1fd0 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa085e780 consts 0, 255>> encoding iso-8859-1 payload [Linux zeus 4.8.6...11 CDT 2016 i686]>)]
asynch_1
No SNMP response received before timeout 0 0 []
asynch_2
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fda9fba2da0 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fbaa828 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fda9fac1c88 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fda9f9e5cf8 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa36e4048 consts 0, 255>> encoding iso-8859-1 payload [Cisco Internetwo...5:14 by kellythw]>)]
asynch_3
因为我是 snmp 的新手。我无法通过使用异步代码一次查询多个代理的解决方案。
请帮助理解问题。如果以错误的方式编写代码,也会纠正我的代码。
任何帮助都将不胜感激。
提前致谢
将阐明为什么 run_until_complete()
会阻止您的代码执行。
简而言之,您必须为循环创建一个任务列表(协程),然后 运行 它会异步收集在一起。
使用 modern async / await syntax (Python 3.5+) 你的重构代码看起来像这样:
import asyncio
from pysnmp.hlapi.asyncio import *
async def run(host,oid):
errorIndication, errorStatus, errorIndex, varBinds = await getCmd(
SnmpEngine(),
CommunityData('public'),
UdpTransportTarget((host, 161)),
ContextData(),
ObjectType(ObjectIdentity(oid))
)
print(errorIndication, errorStatus, errorIndex, varBinds)
async def main():
tasks = []
tasks.append(run('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
tasks.append(run('198.155.104.8','1.3.6.1.2.1.1.1.0'))
tasks.append(run('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
results = await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
请看this example by Ilya Etingof @ github
As a side note: it's better to keep a single, reusable SnmpEngine object within your script/thread. This object is expensive to initialized, it holds various caches so re-creating it slows down pysnmp a great deal. (с) etingof
该建议大大提高了性能(快约 3 倍)。
下面是另一个版本的代码,带有额外的错误处理并返回可读的结果。
import asyncio
import pysnmp.hlapi.asyncio as snmp
async def get(host,oid):
result = []
try:
snmp_engine = snmp.SnmpEngine()
response = await snmp.getCmd(snmp_engine,
snmp.CommunityData('public'),
snmp.UdpTransportTarget((host, 161)),
snmp.ContextData(),
snmp.ObjectType(snmp.ObjectIdentity(oid)))
errorIndication, errorStatus, errorIndex, varBinds = response
if errorIndication:
print(f'{host}: errorIndication: {errorIndication}')
elif errorStatus:
print('{}: {} at {}'.format(host, errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
result.append([x.prettyPrint() for x in varBind])
snmp_engine.transportDispatcher.closeDispatcher()
except Exception as err:
print (f'Error at SNMP get() due to {err}')
finally:
print(f'Get {host}, {oid}: {result}')
return result
async def main():
tasks = []
tasks.append(get('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
tasks.append(get('198.155.104.8','1.3.6.1.2.1.1.1.0'))
tasks.append(get('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
results = await asyncio.gather(*tasks)
print(f'main() results: {results}')
if __name__ == '__main__':
asyncio.run(main())
如需更多了解 asyncio,请参阅以下教程:
- An Introduction to Asynchronous Programming in Python
- Async IO in Python: A Complete Walkthrough
- asyncio — Asynchronous I/O
祝福。
我是 pysnmp 库的新手。我尝试了 snmplabs 文档中提供的示例代码,并进行了一些修改,如下所示。
import asyncio
from pysnmp.hlapi.asyncio import *
@asyncio.coroutine
def run(host,oid):
errorIndication, errorStatus, errorIndex, varBinds = yield from getCmd(
SnmpEngine(),
CommunityData('public'),
UdpTransportTarget((host, 161)),
ContextData(),
ObjectType(ObjectIdentity(oid))
)
print(errorIndication, errorStatus, errorIndex, varBinds)
asyncio.get_event_loop().run_until_complete(run('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
print("asynch_1")
asyncio.get_event_loop().run_until_complete(run('198.155.104.8','1.3.6.1.2.1.1.1.0'))
print("asynch_2")
asyncio.get_event_loop().run_until_complete(run('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
print("asynch_3")
在上面我尝试查询不同代理的get-command。其中“198.155.104.8”是一个不存在的虚拟代理ip。 我希望输出为
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fdaa071e400 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fcf8c88 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fdaa085e7b8 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fdaa07a1fd0 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa085e780 consts 0, 255>> encoding iso-8859-1 payload [Linux zeus 4.8.6...11 CDT 2016 i686]>)]
asynch_1
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fda9fba2da0 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fbaa828 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fda9fac1c88 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fda9f9e5cf8 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa36e4048 consts 0, 255>> encoding iso-8859-1 payload [Cisco Internetwo...5:14 by kellythw]>)]
asynch_3
No SNMP response received before timeout 0 0 []
asynch_2
由于没有引用“198.155.104.8”的代理,代码不应在第二个请求中等待,它应该打印第三个请求。
但我得到的输出如下所示
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fdaa071e400 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fcf8c88 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fdaa085e7b8 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fdaa07a1fd0 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa085e780 consts 0, 255>> encoding iso-8859-1 payload [Linux zeus 4.8.6...11 CDT 2016 i686]>)]
asynch_1
No SNMP response received before timeout 0 0 []
asynch_2
None 0 0 [ObjectType(ObjectIdentity(<ObjectName value object at 0x7fda9fba2da0 tagSet <TagSet object at 0x7fdaa4760828 tags 0:0:6> payload [1.3.6.1.2.1.1.1.0]>), <DisplayString value object at 0x7fda9fbaa828 tagSet <TagSet object at 0x7fdaa4760400 tags 0:0:4> subtypeSpec <ConstraintsIntersection object at 0x7fda9fac1c88 consts <ValueSizeConstraint object at 0x7fdaa4710f28 consts 0, 65535>, <ValueSizeConstraint object at 0x7fda9f9e5cf8 consts 0, 255>, <ValueSizeConstraint object at 0x7fdaa36e4048 consts 0, 255>> encoding iso-8859-1 payload [Cisco Internetwo...5:14 by kellythw]>)]
asynch_3
因为我是 snmp 的新手。我无法通过使用异步代码一次查询多个代理的解决方案。
请帮助理解问题。如果以错误的方式编写代码,也会纠正我的代码。
任何帮助都将不胜感激。
提前致谢
run_until_complete()
会阻止您的代码执行。
简而言之,您必须为循环创建一个任务列表(协程),然后 运行 它会异步收集在一起。
使用 modern async / await syntax (Python 3.5+) 你的重构代码看起来像这样:
import asyncio
from pysnmp.hlapi.asyncio import *
async def run(host,oid):
errorIndication, errorStatus, errorIndex, varBinds = await getCmd(
SnmpEngine(),
CommunityData('public'),
UdpTransportTarget((host, 161)),
ContextData(),
ObjectType(ObjectIdentity(oid))
)
print(errorIndication, errorStatus, errorIndex, varBinds)
async def main():
tasks = []
tasks.append(run('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
tasks.append(run('198.155.104.8','1.3.6.1.2.1.1.1.0'))
tasks.append(run('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
results = await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(main())
请看this example by Ilya Etingof @ github
As a side note: it's better to keep a single, reusable SnmpEngine object within your script/thread. This object is expensive to initialized, it holds various caches so re-creating it slows down pysnmp a great deal. (с) etingof
该建议大大提高了性能(快约 3 倍)。 下面是另一个版本的代码,带有额外的错误处理并返回可读的结果。
import asyncio
import pysnmp.hlapi.asyncio as snmp
async def get(host,oid):
result = []
try:
snmp_engine = snmp.SnmpEngine()
response = await snmp.getCmd(snmp_engine,
snmp.CommunityData('public'),
snmp.UdpTransportTarget((host, 161)),
snmp.ContextData(),
snmp.ObjectType(snmp.ObjectIdentity(oid)))
errorIndication, errorStatus, errorIndex, varBinds = response
if errorIndication:
print(f'{host}: errorIndication: {errorIndication}')
elif errorStatus:
print('{}: {} at {}'.format(host, errorStatus.prettyPrint(), errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
else:
for varBind in varBinds:
result.append([x.prettyPrint() for x in varBind])
snmp_engine.transportDispatcher.closeDispatcher()
except Exception as err:
print (f'Error at SNMP get() due to {err}')
finally:
print(f'Get {host}, {oid}: {result}')
return result
async def main():
tasks = []
tasks.append(get('demo.snmplabs.com','1.3.6.1.2.1.1.1.0'))
tasks.append(get('198.155.104.8','1.3.6.1.2.1.1.1.0'))
tasks.append(get('snmp.live.gambitcommunications.com','1.3.6.1.2.1.1.1.0'))
results = await asyncio.gather(*tasks)
print(f'main() results: {results}')
if __name__ == '__main__':
asyncio.run(main())
如需更多了解 asyncio,请参阅以下教程:
- An Introduction to Asynchronous Programming in Python
- Async IO in Python: A Complete Walkthrough
- asyncio — Asynchronous I/O
祝福。