使⽤Python检测局域⽹内IP地址使⽤情况(批量ping⼯具)
在测试环境搭建的过程中,经常需要给服务器分配静态IP地址,由于不清楚当前局域⽹内部哪些IP地址是空闲的,所以经常需要⼀个⼀个的去试,才能到⼀个可⽤的IP。在之前的⼀家公司⼯作的时候,⽤到过⼀个检测IP使⽤情况的⼯具,但是属于内部⼯具,⽆法获取到。于是乎便想,何不⾃⼰开发⼀个呢?
说做便做,开发环境使⽤的是Python3.6+PyQt5. 如果你的环境不⼀样,可能会运⾏失败。
1、界⾯设计
界⾯⽤QtDesigner来画的,先来⼀张原型图如下,每次只能测试⼀个⽹段的IP占⽤情况,0-255个⼩窗格⽤来显⽰IP地址的使⽤情况,默认为灰⾊,程序执⾏后,IP地址已使⽤的显⽰绿⾊,IP地址未被使⽤的显⽰红⾊。
做界⾯的时候,255个⼩窗格画起来实在是要⼈命,于是就仅画出了窗⼝框架,将UI⽂件转成Python源码后,⾃⼰⼿动编写代码来实现255窗格布局。代码⽚段如下:
idlayout = QtWidgets.QGridLayout(self.widget1)
self.label_list = []
list_index = 0
for i in range(1, 17):
for j in range(1, 17):
label = QtWidgets.QLabel(self.widget1)
label.setMinimumSize(QtCore.QSize(32, 15))
label.setStyleSheet("")
label.setAlignment(QtCore.Qt.AlignCenter)
label.setText(anslate("MyPing", str(list_index)))
self.label_list.append(label)
list_index += 1
2、ping功能实现
ping的实现⽅法有多种,最常⽤的当然是通过调⽤系统⾃带的ping功能来实现。
Python来执⾏系统命令的⽅式有os.system(), os.popen(), subprocess等⽅法,在Python3.6的⼿册中表明,subprocess模块是⽤来替代os.system等函数的。因此我们也使⽤subprocess模块来调⽤ping
python3.5中,subprocess增加了⼀个run函数,run函数创建有⼀个⼦进程来运⾏需要执⾏的命令,返回⼀个CompletedProcess实例,
该函数基本上可以处理所有的应⽤场景,run是对subprocess.Popen的⼀层封装。
python3.5以下可以使⽤subprocess.call(), subprocess.check_call()等函数来实现相同的功能,具体可查阅Python⼿册
def get_ping_result(self, ip):
'''
检查对应的IP是否被占⽤
'''
cmd_str = "ping {0} -n 1 -w 600".format(ip)
DETACHED_PROCESS = 0x00000008 # 不创建cmd窗⼝
try:站长工具ping检测
subprocess.run(cmd_str, creationflags=DETACHED_PROCESS, check=True) # 仅⽤于windows系统
except subprocess.CalledProcessError as err:
self._it(False, ip)
else:
self._it(True, ip)
说明:
在默认情况下,使⽤subprocess.run()执⾏ping命令的时候,会弹出⼀个cmd窗⼝,当256个线程⼀起运⾏的时候,满屏的窗⼝,想想都很酸爽。。。
在windows系统下,可以传⼊creationflags参数来使subprocess创建的⼦进程不⽣成console
check参数为True时,函数将检测执⾏结果是否为0(此处0表⽰执⾏成功),⾮零则抛出异常。
3、多线程
在使⽤pyqt进⾏GUI编程的时候,如果涉及到需要长时间后台运⾏的操作,⼀般需要使⽤多线程的⽅式,否则界⾯会阻塞,直到后台运⾏结束,造成程序卡死的假象。
在本程序实现,要实现256个地址的ping操作,如果单线程操作,肯定半天也⽆法得到结果,因此我们为每⼀个IP地址分配⼀个线程,最多256线程并发运⾏,1~2秒的时间即可得到整个⽹段的IP地址占⽤情况
多线程实现核⼼代码如下:
def start_ping(self):
'''
启动多线程
'''
startip = self.().split('.')
endip = ().split('.')
tmp_ip = startip
pthread_list = []
for i in range(int(startip[3]), int(endip[3]) + 1):
tmp_ip[3] = str(i)
ip = '.'.join(tmp_ip)
pthread_list.append(threading.Thread(_ping_result, args=(ip,)))
for item in pthread_list:
item.setDaemon(True)
item.start()
⼦线程通过发射信号的⽅式来通知主程序执⾏结果,最终主程序根据运⾏结果渲染界⾯。
全部源码可到GitHub下载,链接见⽂章头部。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论