概述

这学期网络管理课程大作业选题有两个,选了编程实现snmp管理的GUI软件这个。。

项目主要使用pyqt6,pysnmp这两个库,关于这两个库的文档直接看官方的就好。

这篇文章主要记录一下注意事项以及踩坑等等,代码就不给出了,写的简直就是一坨shit。。。所以不适合py小白来看(虽然我也是小白

实现过程

在pycharm中创建external tools,分别为QT Designer,PyUIC,Pyrcc,步骤和pyqt5中差不多一样,注意路径是pyqt6的,先用designer创建ui文件,设计好后在pycharm中使用pyuic转换为py文件,再新建一个主程序的文件,用于写实现函数,之后将生成的GUI文件导入到实现文件中,新建类等等,这些是比较基础的了,不说了

关于pysnmp的使用可以看官方文档,相关文档地址在文章末尾给出。

相关细节与踩坑

getBulk操作

根据官方的文档https://docs.lextudio.com/pysnmp/v7.1/docs/hlapi/v3arch/asyncio/manager/cmdgen/bulkcmd

这在bulk_cmd的定义中使用了await,虽然这是交互式命令行,但定义函数的语法和IDE中是差不多的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> import asyncio
>>> from pysnmp.hlapi.v3arch.asyncio import *
>>>
>>> async def run():
... errorIndication, errorStatus, errorIndex, varBinds = await bulk_cmd(
... SnmpEngine(),
... CommunityData('public'),
... await UdpTransportTarget.create(('demo.pysnmp.com', 161)),
... ContextData(),
... 0, 2,
... ObjectType(ObjectIdentity('SNMPv2-MIB', 'system'))
... )
... print(errorIndication, errorStatus, errorIndex, varBinds)
>>>
>>> asyncio.run(run())
(None, 0, 0, [[ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.1.0')), DisplayString('SunOS zeus.pysnmp.com 4.1.3_U1 1 sun4m'))], [ObjectType(ObjectIdentity(ObjectName('1.3.6.1.2.1.1.2.0')), ObjectIdentifier('1.3.6.1.4.1.424242.1.1'))]])
>>>

如果像之正常的get一样await定义的函数,这时就会有两个await,会有这样的返回结果,而非报错:
object tuple can't be used in 'await' expression

只需要把定义时的await去掉就行

与ComboBox.currentIndexChanged.connect的方法参数问题

具体问题就是,在我的选项卡切换时会出现卡死闪退情况,经过注释发现问题是出现在向ComboBox中additem这个地方,但是我这里add进去的只有两个,不是因为数据很多造成的,打开调试器看一眼,下面就是出现问题的地方。。

原因是,只要切换选项卡就会触发这个函数,然而第一次切换时这个comboBox中什么都没有,自然就不存在previousText,会报错,我是直接将这俩参数删去了,也用不着。。

QComboBox删除所有行

这个问题还是容易解决的,一开始我是使用:

1
self.ui.resultTable.clear()

但这只是将每一行的内容清除,行还是存在的

然后想到removeRow:

1
2
3
4
self.ui.resultTable.clear()
count = self.ui.resultTable.rowCount()
for i in range(count):
self.ui.resultTable.removeRow(i)

但是实际删除的速度太慢了,点击完清楚按钮还剩下好几行。。

直接:

1
self.ui.resultTable.setRowCount(0)

使用snmpset

Ubuntu的snmpd.conf配置

物品的Ubuntu在配置完需要重启虚拟机,重启服务是不行的。

set实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
async def run():
errorIndication, errorStatus, errorIndex, varBinds = await set_cmd(
SnmpEngine(),
CommunityData(writecommunity, mpModel=1),
await UdpTransportTarget.create((ip, int(port))),
ContextData(),
ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysName', 0), OctetString('test'))
)
print(errorIndication)
print(errorStatus)
print(errorIndex)
for varBind in varBinds:
print(varBind)

这里要注意的是ObjectType的第二个参数应该是对应类型的数据,比如要设置字符串类型,就不能只写“test”,要加上OctetString(),这种类型包括(在pysnmp.proto..rfc1902中):

在异步函数中使用QDialog(),报与异步相关错

我是将comboBox的currentTextChanged信号与一个异步函数connect了,这个函数是要实现snmp的相关语句,所有必须是异步,我这里是要输入set的参数,因为要输入多个参数,所有弹出了一个dialog(),而不是QInputDialog,这个只能输入一行,写了个form,加了ok,cancel按钮,on按钮的clicked信号与实现发送set命令的函数connect,这时要显示这个dialog,不能使用exec(),要用show()或者setVisible(True)

trap接收相关问题

使用Pysnmp官方代码:

https://docs.lextudio.com/pysnmp/v7.1/examples/v1arch/asyncio/manager/ntfrcv/transport-tweaks

在我的GUI中新建一个线程,启动这个代码,但是要加上:

1
2
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)

我一开始开在了localhost上,用Ubuntu测试trap,但是怎么发也收不到,卡了挺长时间,但是看ip时,忽然意识到虚拟机的网段和localhost是不一样的。。。所以开启的ip应该是和虚拟机处于同一网段的ip,而不是localhost。。被自己蠢笑了。。。

相关文档

pysnmp官方文档:https://docs.lextudio.com/snmp/

弹出弹窗输入文本:https://developer.aliyun.com/article/1637732

总结

  1. 官方文档是真的很重要,基本上所有用法都写出来了,如果发现没有哪一个函数的用法,那大概率就是还没有找到。。
  2. pysnmp的优点在于Mib对象解析,代理段与管理端都能胜任,就不需要对兼容性担心太多,并且官方文档有很多示例,对初学者很友好(
  3. 这个程序写出来有点像shit。。但是比我上一次用pyqt好很多了,上一次直接在pyuic生产的py文件中写,导致每次打开项目时,我写的那些代码都被覆盖掉了,这次我选择把生产的gui.py导入到程序中。
  4. 还是得找个时间学一下qt,pyqt在有些方面还是不如qt….