uric 发表于 2020-8-1 15:59

首次发帖,新手使用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版,目前已有初稿,待后续完善后更新,参考图如下:


uric 发表于 2020-8-1 16:11

Menguy 发表于 2020-8-1 16:06
我觉得网址加ping值看着会舒服一点

不同的用途需要重新设计输出内容,我这边工作经常会碰到确认一个网段有多少IP未使用这种需求,ping的延时可以通过subprocess.Popen方法来获取stdout的内容,代码里根据需求处理就可以了。

uric 发表于 2020-8-7 10:34

梦想QCJ 发表于 2020-8-7 08:30
这个工具是独立运行吗?

GUI版本打包后可独立运行,不过体积有点大,38M左右,手动滑稽{:1_907:}
稍后我上传个打包后的程序吧

uric 发表于 2020-8-1 16:04

忘记说了一点,可以直接使用Pyinstaller打包成exe,此处就不上传成品了,有兴趣的童鞋可以试试。

Menguy 发表于 2020-8-1 16:06

绫音 发表于 2020-8-1 16:20

额学习一下 感谢分享

偶尔平凡 发表于 2020-8-1 16:45

maomaogou 发表于 2020-8-1 16:47

学习一下

战地记者木木子 发表于 2020-8-1 16:48

人生苦短,我用python

wangwanghz 发表于 2020-8-1 16:59

学习学习,谢谢楼主

NOOB玩家 发表于 2020-8-1 17:01

学习了,正在学python
页: [1] 2 3
查看完整版本: 首次发帖,新手使用python实现的群ping小工具,求勿喷。。