首次发帖,新手使用python实现的群ping小工具,求勿喷。。
本帖最后由 uric 于 2020-8-8 09:48 编辑====================8.7打包文件================================
说实话python打包确实比较难受,要么体积巨大,要么就是支持不好,我打包过程中发现很奇怪的问题,因多线程主要使用subprocess,pyinstaller支持非常不好,加上-w参数打包成单一文件会发现执行特别缓慢(正常执行3s左右,无窗口单文件执行约30s),但是打包时不加-w参数时正常,比较遗憾,如果是代码层面问题,请大神不吝指导;
成品地址:
https://wwa.lanzouj.com/b0c2mdwzc
密码:52pj
其中:
PingGUI_V3未打包版.zip 此文件使用nuitka进行打包,UI部分编译为C代码,UI响应较快,但因nuitka不支持打包成单一文件,故提供压缩包,解压后点击pingGUIV3.exe执行即可,推荐使用。
PingGUI_CON.exe 此文件为使用pyinstaller进行打包,未添加-w参数,故为单一带console,UI响应较慢,大家自选
====================8.6更新GUI=================================
首先放入demo图片,使用pyqt5,界面使用pyqt5designer设计,使用pyuic转成.py文件:
准备工作:
1、安装pyqt5和pyqt5-tools(建议使用venv环境,避免污染系统python版本)
2、设计UI界面,本次主要选用label实现IP展示,文本框和按钮使用水平布局,IP显示区域使用grid布局,整体上使用垂直布局,可直接使用pyqt5designer加载ping.ui查看或修改,如图:
3、界面代码和业务代码已拆分成2个py文件,其中ping.py为UI文件,pingGUI为业务代码文件,本次重点展示业务代码:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
from PyQt5.QtCore import pyqtSlot, QThread, pyqtSignal
from ping import Ui_pingWindow
import threading
import subprocess
import time
from queue import Queue
# 定义sucess列表、工作进程数和初始化队列
ipSuccess = []
Work_Thread = 254
ipQueue = Queue()
# 初始化主窗口类
class pingWindow(QMainWindow, Ui_pingWindow):
def __init__(self, parent=None):
super(pingWindow, self).__init__(parent)
self.setupUi(self)
# 初始化多线程对象
self.thread = Work_QThread()
# 按钮点击后传给work函数
self.ping.clicked.connect(self.work)
# 接收到信号后传递给goStop函数
self.thread.trigger.connect(self.goStop)
# 初始化状态栏信息
self.statusbar.showMessage("请按照提示信息操作...")
# 执行前清除上一次显示结果
def clear_color(self):
# 清除旧颜色,默认颜色为灰色,background-color: rgb(217, 217, 217) 灰色
for i in range(1, 255):
ui_default = 'ui.ip_' + \
str(i) + '.setStyleSheet("background-color: rgb(217, 217, 217)")'
# 使用eval执行字符串命令/赋值
eval(ui_default)
# 点击按钮后的操作
def work(self):
a = ui.ip_line.text()
if len(a) > 0 and len(a.split('.')) == 4 and a.split('.')[-1] == '':
# 调用清除颜色的函数
self.clear_color()
# 多线程调用/执行
self.thread.start()
# 任务执行时将ping按钮设置成不可用
self.ping.setEnabled(False)
else:
QMessageBox.information(ui, "提示信息", "检测到输入信息不正确,请输入正确的IP网段信息。")
# 多线程执行完毕后调用gostop函数
def goStop(self):
# 任务结束后恢复按钮可用
self.ping.setEnabled(True)
QMessageBox.information(ui, "提示信息", "操作已成功执行。")
# 多线程ping主函数,注意不需要传入self函数
def pingIp():
# 消费队列里的IP地址
while not ipQueue.empty():
ip = ipQueue.get()
# 跟cli一样,linux或macos注意修改为:ping -c 2 -W 5
cmd = 'ping -n 2 -w 5 %s' % ip
# 此处未使用管道,直接使用temp临时文件,加快处理速度
# out_temp = tempfile.TemporaryFile(mode='w+')
# fileno = out_temp.fileno()
# p = subprocess.call(cmd, stdout=fileno, stderr=fileno)
# 判断返回值是0(0代表命令成功执行)
# if p == 0:
# 成功返回0,将从队列中遍历的IP信息存入成功列表
# ipSuccess.append(ip)
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
p = subprocess.Popen(cmd, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True, startupinfo=si)
p.communicate()
# print(p.returncode)
if p.returncode == 0:
ipSuccess.append(ip)
# 任务逻辑和主窗口进程拆分,防止出现未响应或程序执行时主界面假死
class Work_QThread(QThread):
trigger = pyqtSignal()
def __init__(self):
super(Work_QThread, self).__init__()
@pyqtSlot()# 防止多次执行
def run(self):
start_time = time.time()
ui.statusbar.showMessage("程序执行中...")
a = ui.ip_line.text()
for i in range(1, 255):
ipQueue.put(a + str(i))
# 获取网段信息并加入队列
threads = []
for i in range(Work_Thread):
# 多线程调用pingIP主函数
thread = threading.Thread(target=pingWindow.pingIp)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
# 可以ping通的存入sucess列表
for i in ipSuccess:
ip_green = 'ip_' + str(i.split(a))
ui_info = 'ui.' + ip_green + \
'.setStyleSheet("background-color:green")'# 修改UI标签背景为绿色
eval(ui_info)
time_info = format(time.time() - start_time, '.2f')
statusbar_info = '在线台数:' + \
str(len(ipSuccess)) + ' '*5+'执行耗时:' + time_info + 's'
# 显示状态栏信息
ui.statusbar.showMessage(statusbar_info)
# 清除列表,避免重复统计
ipSuccess.clear()
# 发送信号
self.trigger.emit()
if __name__ == '__main__':
# 初始化PyQt5窗口
app = QApplication(sys.argv)
ui = pingWindow()
ui.show()
sys.exit(app.exec_())
4、所有文件以附件提供,可使用pyinstaller编译成exe,但实测不加-w参数可正常执行,但是有cmd窗口,加上-w后存在无法执行的情况,这个问题待后续更新解决方案,暂时可不加-w打包,请各位大神不吝指导,非常感谢。
====================以下为cli版本================================
主要用于是批量ping一个C网段,多线程执行,速度一般在2-5s之内返回结果,激进的话可以调整ping次数为1提示速度,不过容易出现误差;
网络工程师或运维工程师应该会有用,本人萌新首次发帖,此代码杂乱不堪,为python练手之作,求勿喷{:1_889:}{:1_889:}{:1_889:},如有大神不吝指导,非常感谢!{:1_893:}{:1_893:}{:1_893:}
直接上代码:
#!/usr/bin/python3
# coding:utf-8
import sys
import threading
import subprocess
import time
from queue import Queue
from optparse import OptionParser
# 初始化变量,ipSucess为存储可以ping通的IP列表,Work_Thread为后台工作进程数,ipQueue为执行命令的队列
ipSuccess = []
Work_Thread = 254
ipQueue = Queue()
def main(a):
start_time = time.time()
# 初始化列表,主要用来存放渲染为绿色的IP信息,"\033[92m \033[0m"
ip_p = []
# 默认全部渲染为灰色,同时因为x.x.x.0/24为网络号,无实质意义,替换为空
for i in range(0, 255):
t = '\033[90m' + str(i) + '\033[0m'
ip_p.append(t)
ip_p = '\033[91m' + '' + '\033[0m'
# 判断命令行参数-n 或 --net后的字符串是否符合要求,此处判断存在漏洞,需完善
if len(a) > 0 and len(a.split('.')) == 4 and a.split('.')[-1] == '':
# 拼接符合要求的数据并放入队列
for i in range(1, 255):
ipQueue.put(a + str(i))
# 初始化线程池,并多线程调用pingIP函数
threads = []
for i in range(Work_Thread):
thread = threading.Thread(target=pingIp)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
# 将可以ping通的IP地址从ipsuccess列表取出并渲染成绿色
for i in ipSuccess:
# print(i)
ip_p)] = '\033[92m' + \
i.split('.')[-1] + '\033[0m'
# 该函数定制最终输出内容的格式,每行16个IP,一共16行,其中0和254去除
def ip_info(ip_p):
print("Ping Results:")
n = 16
for i in range(len(ip_p)):
print('{0:>12}'.format(ip_p), end=' '*2)
if (i + 1) % n == 0:
print('\n', end='')
# 将渲染后的结果进行打印
ip_info(ip_p)
# 打印提示信息,包括在线主机数和脚本执行时间
time_info = format(time.time() - start_time, '.2f')
run_info = a + '在线数:' + \
str(len(ipSuccess)) + '\t' + '执行耗时:' + time_info + 's'
print('\n' + run_info)
# 释放无用资源
ipSuccess.clear()
ip_p.clear()
else:
# 打印cli提示信息
parser.print_help()
# 多线程执行命令,并构建ipsuccess列表
def pingIp():
while not ipQueue.empty():
ip = ipQueue.get()
# 如果为linux或macos,此处cmd应为'ping -c 2 -W 5',命令行参数不太一致
cmd = 'ping -n 2 -w 5 %s' % ip
# 如果为linux或macos,此处subprocess.call参数需在后面补充shell=True
res = subprocess.call(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# print(ip, True if res == 0 else False)
# 如果返回值为0,代表ping命令正确返回,此处仅简单判断状态,后续可读取通道信息,获取延时数据,针对延时时长渲染其他的颜色
if res == 0:
ipSuccess.append(ip)
# 从这里开始执行
if __name__ == '__main__':
# 构建命令行参数
parser = OptionParser()
# 本行新增-n或--net参数,参数赋值于变量net
parser.add_option("-n", "--net",
help="for example: ping_cli.py -n 192.168.1.", metavar="net")
(options, args) = parser.parse_args()
if options.net != None:
# 把命令行变量net传给main函数并执行
main(options.net)
else:
# 无法正确获得命令行参数时打印帮助信息并退出程序
parser.print_help()
执行结果如下:
PS:因配色方案为bash颜色方案,直接在cmd执行可能无法正常输出颜色标签,经测试Windows Terminal可完美支持颜色渲染(如上图),Linux和MACOS原生支持颜色输出。
后续计划:更改为GUI版,目前已有初稿,待后续完善后更新,参考图如下:
Menguy 发表于 2020-8-1 16:06
我觉得网址加ping值看着会舒服一点
不同的用途需要重新设计输出内容,我这边工作经常会碰到确认一个网段有多少IP未使用这种需求,ping的延时可以通过subprocess.Popen方法来获取stdout的内容,代码里根据需求处理就可以了。 梦想QCJ 发表于 2020-8-7 08:30
这个工具是独立运行吗?
GUI版本打包后可独立运行,不过体积有点大,38M左右,手动滑稽{:1_907:}
稍后我上传个打包后的程序吧 忘记说了一点,可以直接使用Pyinstaller打包成exe,此处就不上传成品了,有兴趣的童鞋可以试试。 额学习一下 感谢分享 学习一下 人生苦短,我用python 学习学习,谢谢楼主 学习了,正在学python