Python3 Windows平台PING测试并把结果画图方便对比分析


'''
2019-03-21

程序运行说明
测试部分:通过windows自身ping程序运行60秒获取结果,保存为本地文本文件(日志文件)
画图部分:处理保存在本地的日志文件,画成图显示

使用说明
运行平台:Windows7 & Python3.x
依赖第三方包:matplotlib 包(画图要用到)
安装第三方包:
打开 CMD 输入命令 pip install matplotlib 会自动安装 matplotlib 包

BUG:
0、双击运行无效,请使用python IDLE打开,再F5运行
1、测试运行后,如果直接关闭GUI窗口,可能造成后台进程不能终止。请点击停止按钮,等待程序关闭后,再关闭窗口
2、用户输入的参数没有限制类型、范围,不要乱输入
'''

import tkinter
import pickle
import re
import subprocess
from threading import Thread
import time
import os
import time
import logging # 日志
Log = logging.getLogger("__name__") # 获取实例
formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') # 指定logger输出格式
file_handler = logging.FileHandler("net.log") # 日志文件路径
file_handler.setFormatter(formatter)  # 可以通过setFormatter指定输出格式
Log.addHandler(file_handler) # 为logger添加的日志处理器
Log.setLevel(logging.DEBUG) # 设置记录的日志级别

## 程序运行控制的全局字典变量:'S'控制ping程序运行,'测试按钮计数'控制按钮行为
D_S = {'S':1,'测试按钮计数':1}
#print(D_S)

## 开始测试,把测试结果保存到日志文件(开始测试按钮操作函数)
def PING_TEST():
    #print(D_S)
    if D_S['测试按钮计数'] %2 != 0:
        D_S['测试按钮计数'] += 1
        ##print("START 开始测试...")
        text3.insert(1.0, 'START 开始测试...\n')
        D_S['S'] = 1               # 设置为1 允许测试程序运行
        K1 = 输入框2.get()         # 获取输入框的内容
        V1 = 输入框1.get()
        K2 = 输入框4.get()
        V2 = 输入框3.get()
        K3 = 输入框6.get()
        V3 = 输入框5.get()
        K4 = 输入框8.get()
        V4 = 输入框7.get()
        D_任务 = {}                # 准备进行PING测试的任务字典 {'备注':'IP'}
        if V1:
            if K1:
                D_任务[K1] = V1
            else:
                K1 = V1
                D_任务[K1] = V1
        if V2:
            if K2:
                D_任务[K2] = V2
            else:
                K2 = V2
                D_任务[K2] = V2
        if V3:
            if K3:
                D_任务[K3] = V3
            else:
                K3 = V3
                D_任务[K3] = V3
        if V4:
            if K4:
                D_任务[K4] = V4
            else:
                K4 = V4
                D_任务[K4] = V4
    
        #print("准备进行PING测试的任务字典",D_任务)
        text1.delete(1.0, tkinter.END)          # 清除文本框内容
        if len(D_任务) == 0:
            text1.insert(1.0, '请先输入要测试的IP地址')   # 写入内容
            D_S['S'] = 1
            D_S['测试按钮计数'] = 1
        else:
            for i in D_任务:
                text1.insert(1.0, '测试任务 ' + i + ' ' + D_任务[i] + '\n')
            text1.insert(5.0, '测试数据保存在 net.log 文件中\n')
            text1.insert(6.0, '测试程序运行中...\n')

        f = open('PING_TEST_INFO.pkl', 'wb')    # 保存到文件,让后续画图程序读取
        pickle.dump(D_任务, f)
        f.close()
    
        def ping(IP):
            while D_S['S']:
                ##print("线程开始",IP)
                ###text3.insert(tkinter.END, '线程开始 '+IP+'\n')
                ###time.sleep(5)
                
                #print("程序开始", time.time())
                cmd = 'ping -t ' + IP                           # 长PING测试
                win = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
                #print(IP, "子进程PID", win.pid)
        
                #print("程序暂停", time.time())
                time.sleep(60)                                  # 每60秒终止长PING进程,win会计算本次测试结果
                #print("暂停结束", time.time())
        
                #print("开始KILL", time.time())
                os.popen('taskkill /pid:' + str(win.pid))   # windows 需要用自身的命令程序杀死进程
                #print("完成KILL", time.time())
        
                R = win.stdout.read()
                #print("程序完成",time.time())
        
                #print("输出内容")
                #print(R.decode('GBK'))
        
                TXT = R.decode('GBK')
        
                丢包率 = re.search('[0-9]+%',TXT)
                延时统计 = re.search('最短(.*)',TXT)
        
                #print("丢包率",丢包率.group())
                #print("延时统计",延时统计.group())

                if not 延时统计:
                    if 丢包率:
                        INFO = IP + ' ' + 丢包率.group() + ' 最短 = 0ms,最长 = 0ms,平均 = 0ms'
                        Log.info(INFO) # 记录到日志
                        print('100% lost')
                    else:
                        print('ERROR',TXT)
                else:
                    INFO = IP + ' ' + 丢包率.group() + ' ' + 延时统计.group()    # 保存到INFO,准备记录到日志
                    Log.info(INFO) # 记录到日志
                    #print(INFO)
                
                if D_S['S'] == 1:
                    ##print(IP," 测试中\n")
                    text3.insert(tkinter.END, IP + ' 测试中\n')
                else:
                    ##print(IP," 测试终止\n")
                    text3.insert(tkinter.END, IP + ' 测试终止\n')
                
    
        任务IP列表 = []
        for i in D_任务:
            ##print(D_任务[i])
            任务IP列表.append(D_任务[i])
        任务总数 = len(任务IP列表)
        if 任务总数 == 1:
            t0=Thread(target=ping,args=(任务IP列表[0],))
            t0.start()
        elif 任务总数 == 2:
            t0=Thread(target=ping,args=(任务IP列表[0],))
            t1=Thread(target=ping,args=(任务IP列表[1],))
            t0.start()
            t1.start()
        elif 任务总数 == 3:
            t0=Thread(target=ping,args=(任务IP列表[0],))
            t1=Thread(target=ping,args=(任务IP列表[1],))
            t2=Thread(target=ping,args=(任务IP列表[2],))
            t0.start()
            t1.start()
            t2.start()
        elif 任务总数 == 4:
            t0=Thread(target=ping,args=(任务IP列表[0],))
            t1=Thread(target=ping,args=(任务IP列表[1],))
            t2=Thread(target=ping,args=(任务IP列表[2],))
            t3=Thread(target=ping,args=(任务IP列表[3],))
            t0.start()
            t1.start()
            t2.start()
            t3.start()
        else:
            ##print("ERROR 任务总数范围不在 1到4")
            text3.insert(tkinter.END, 'ERROR 任务总数范围不在 1到4 \n')
    else:
        D_S['测试按钮计数'] += 1
        ##print("STOP 停止中...")
        text3.insert(tkinter.END, 'STOP 停止中... \n')
        D_S['S'] = 0
        text1.delete(1.0, tkinter.END)
        text1.insert(1.0, '测试数据保存在 net.log 文件中\n')
        text1.insert(2.0, '测试程序 终止\n')
        '''
        cmd_find_ping = os.popen('tasklist | findstr -i PING') ## 通过Windows自身命令找到PING进程信息
        cmd_txt = cmd_find_ping.read()
        PING_INFO_LIST = re.findall('PING(.*)',cmd_txt) ## 用re处理成列表,方便接下来使用
        print("找到数量",len(PING_INFO_LIST))
        #print("内容",PING_INFO_LIST)
        for i in PING_INFO_LIST:
            #print("每行内容",i)
            print("进程ID",i.split()[1],"开始结束进程")
            os.popen('taskkill.exe /F /pid:' + str(i.split()[1]))
        '''

## 把测试记录画成图查看(画图分析按钮操作函数)
def INFO_IMG():
    D_复选 = {'PLR':0, 'MAX':0, 'AVG':0}
    text2.delete(1.0, tkinter.END)
    if V1.get() == 1:
        D_复选['PLR'] = 1
        text2.insert(1.0, '在图中显示 丢包率\n')
    if V2.get() == 1:
        D_复选['MAX'] = 1
        text2.insert(2.0, '在图中显示 最大延时\n')
    if V3.get() == 1:
        D_复选['AVG'] = 1
        text2.insert(3.0, '在图中显示 平均延时\n')
    if V1.get() + V2.get() + V3.get() == 0:
        print("用户无选择,无Y轴可画")
        text2.insert(1.0, '【警告】Y轴无内容,请勾选显示内容:丢包率/最大延时/平均延时\n')
    #print("D_复选 设置结果", D_复选)
    
    X轴刻度设置 = 输入框9.get()
    if not X轴刻度设置:
        X轴密度降低倍数 = 1
    else:
        X轴密度降低倍数 = int(X轴刻度设置)

    text2.insert(4.0, 'X轴刻度设置:每' + str(X轴密度降低倍数) + '分钟一个刻度\n')
    
    单选结果 = V.get()
    if 单选结果 == 0:
        text2.insert(5.0, '子图排列方式:并排显示子图\n')
    else:
        text2.insert(5.0, '子图排列方式:并列显示子图\n')
    #print("子图排列方式:单选结果",V.get())

    ## 分离各IP数据
    D_各IP信息 = {}                             # {'GW':[[TIME],[PLR],[MAX],[AVG]]}
    def IPs(F,IP,TXT):
        IP_INFO = ''
        re_txt = '(.*)' + IP + '(.*)'
        X = re.finditer(re_txt, TXT)
        L_Time = [] # 时间列表
        for i in X:
            T = i.group()
            IP_INFO += T+'\n'
            L_Time.append(T[11:16])             # 元素类型字符串 '时间点'
        ##print(F,"TEXT done")
        ##print(F,"TIME done")
        #print("L_Time \n",L_Time,"\n")
        #print(IP_INFO)
    
        L_PLR = []  # 丢包率
        L_MAX = []  # 最大延时
        L_AVG = []  # 平均延时
        MS = re.findall('[0-9]+ms',IP_INFO)
        PLR = re.findall('[0-9]+%',IP_INFO)
    
        for x in PLR:
            L_PLR.append(int(x[:-1]))           # 取%前的值,再转成int,保存到列表
        ##print(F,"PLR done")
        
        for y in range(1,len(MS),3):
            L_MAX.append(int(MS[y][:-2]))       # 去掉末尾ms再转int
        ##print(F,"MAX done")
        #print("L_MAX \n",L_MAX,"\n")
    
        for z in range(2,len(MS),3):
            L_AVG.append(int(MS[z][:-2]))
        ##print(F,"AVG done")
        #print("L_AVG \n",L_AVG,"\n")

        LLLL = [L_Time, L_PLR, L_MAX, L_AVG]
        D_各IP信息[F] = LLLL

    ## 读取测试记录文件
    F_Src = 'net.log'
    f = open(F_Src, 'r')
    TXT = f.read()                              # 全部内容保存到内存变量TXT
    #print(TXT,'\n')
    f.close()

    ## 从文件读取要画图的信息
    f = open('PING_TEST_INFO.pkl', 'rb')
    D = pickle.load(f)                          # D = {'GW':'192.168.1.1', 'DNS':'114.114.114.114', 'USA':'8.8.8.8'}
    ##print("本次画图内容",type(D), D)
    f.close()

    for i in D:
        text2.insert(6.0, '开始画图:' + i + ' ' + D[i] + '\n')
        IPs(i, D[i], TXT)                       # 传入新文件名,要分离的IP数据,整个源文件内容

    import matplotlib.pyplot as plt
    import matplotlib.ticker as ticker

    ## 为了作图方便,把字典的key单独存为一个列表
    L = []          # L = ['GW','DNS','USA']
    for i in D:
        L.append(i)

    # 画出图形
    图数量 =  len(L)
    if 图数量 > 1:
        if 单选结果 == 0:
            fig, ax = plt.subplots(1,图数量, sharex=True, sharey=True)    # 1行多列(并排显示子图),统一X和Y轴刻度,方便横向对比
        else:
            fig, ax = plt.subplots(图数量,1, sharex=True, sharey=True)    # 多行1列(并列显示子图),统一X和Y轴刻度,方便纵向对比
        AX_List = ax.ravel()                                              # 子图列表:AX_List[0]第一个子图,AX_List[1]第二个子图...

        for i in range(0, 图数量):
            L_L = D_各IP信息[L[i]]             # L_L内容 = [时间列表,丢包率列表,最大延时列表,平均延时列表]
            L_TIME = L_L[0]     # 时间作为X轴
            L_PLR = L_L[1]      # 丢包率作为其中一个Y轴,单位%(百分比)
            L_MAX = L_L[2]      # 最大延时为其中一个Y轴,单位(ms)
            L_AVG = L_L[3]      # 平均延时为其中一个Y轴,单位(ms)

            if D_复选['PLR'] == 1:
                AX_List[i].plot(L_TIME,L_PLR,label='PLR(%)')    # 在图中画出丢包率(范围0-100)
            if D_复选['MAX'] == 1:
                AX_List[i].plot(L_TIME,L_MAX,label='MAX(ms)')   # 在图中画出最大延时,可以看波动幅度,但遇到太大的会看不清其他值
            if D_复选['AVG'] == 1:
                AX_List[i].plot(L_TIME,L_AVG,label='AVG(ms)')   # 在图中画出平均延时
            AX_List[i].xaxis.set_major_locator(ticker.MultipleLocator(X轴密度降低倍数))  # 当X轴取值太多时会显示太密集,这里设置每30个值显示1个
            AX_List[i].legend()                         # 显示图例label
            AX_List[i].set_title(L[i])                  # 设置每个子图各自标题
            if 单选结果 == 0:                           # 如果并排显示
                AX_List[i].set_xlabel('Time')           # 每个图显示X轴标识
            #AX_List[i].set_ylabel('MS or %')           # 设置Y轴标识
        if 单选结果 == 1:                               # 如果并列显示
            plt.xlabel('Time')                          # 只让最后一张图显示X轴标识
        plt.show()  # 显示制作好的图

    elif 图数量 == 1:
        L_L = D_各IP信息[L[0]]
        L_TIME = L_L[0]
        L_PLR = L_L[1]
        L_MAX = L_L[2]
        L_AVG = L_L[3]
        fig, ax = plt.subplots(1,1)
        if D_复选['PLR'] == 1:
            ax.plot(L_TIME,L_PLR,label='PLR(%)')
        if D_复选['MAX'] == 1:
            ax.plot(L_TIME,L_MAX,label='MAX(ms)')
        if D_复选['AVG'] == 1:
            ax.plot(L_TIME,L_AVG,label='AVG(ms)')
        ax.xaxis.set_major_locator(ticker.MultipleLocator(X轴密度降低倍数))
        plt.legend()
        plt.xlabel('Time')
        plt.title(L[0])
        plt.show()
    else:
        ##print("图数量 ERROR")
        text3.insert(tkinter.END, '图数量 ERROR \n')


## GUI 界面设置
top = tkinter.Tk()
top.wm_title("Windows PING")    # 图形窗口标题
top.geometry("720x650+50+60")   # 图像窗口初始大小及位置

## 框架布局
frame_root = tkinter.Frame(top)

frame_1 = tkinter.Frame(frame_root)
frame_2 = tkinter.Frame(frame_root)
frame_3 = tkinter.Frame(frame_root)

frame_4 = tkinter.Frame(frame_root)
frame_5 = tkinter.Frame(frame_root)
frame_6 = tkinter.Frame(frame_root)

frame_7 = tkinter.Frame(frame_root)

## 测试部分的用户参数处理
测试 = tkinter.Label(frame_1,text="第一步,测试网络").grid(row=0,column=0,columnspan=4,sticky='W')

备注1 = tkinter.Label(frame_2,text="IP1:").grid(row=1,column=0,sticky='W')
备注2 = tkinter.Label(frame_2,text="备注").grid(row=1,column=2,sticky='W')
备注3 = tkinter.Label(frame_2,text="IP2:").grid(row=2,column=0,sticky='W')
备注4 = tkinter.Label(frame_2,text="备注").grid(row=2,column=2,sticky='W')
备注5 = tkinter.Label(frame_2,text="IP3:").grid(row=3,column=0,sticky='W')
备注6 = tkinter.Label(frame_2,text="备注").grid(row=3,column=2,sticky='W')
备注7 = tkinter.Label(frame_2,text="IP4:").grid(row=4,column=0,sticky='W')
备注8 = tkinter.Label(frame_2,text="备注").grid(row=4,column=2,sticky='W')

输入框1 = tkinter.Entry(frame_2)
输入框2 = tkinter.Entry(frame_2)
输入框3 = tkinter.Entry(frame_2)
输入框4 = tkinter.Entry(frame_2)
输入框5 = tkinter.Entry(frame_2)
输入框6 = tkinter.Entry(frame_2)
输入框7 = tkinter.Entry(frame_2)
输入框8 = tkinter.Entry(frame_2)
输入框1.grid(row=1,column=1,sticky='W')
输入框2.grid(row=1,column=3,sticky='W')
输入框3.grid(row=2,column=1,sticky='W')
输入框4.grid(row=2,column=3,sticky='W')
输入框5.grid(row=3,column=1,sticky='W')
输入框6.grid(row=3,column=3,sticky='W')
输入框7.grid(row=4,column=1,sticky='W')
输入框8.grid(row=4,column=3,sticky='W')

测试按钮 = tkinter.Button(frame_3,text='开始测试/结束测试',command=PING_TEST).grid(row=5,column=0,columnspan=4,sticky='W')
text1 = tkinter.Text(frame_3,width='50',height=9)
text1.grid(row=6,column=0,columnspan=4,sticky='W')

## 画图部分的用户参数处理
画图部分 = tkinter.Label(frame_4,text="第二步,画图分析结果").grid(row=15,column=0,sticky='W')

tkinter.Label(frame_5,text="Y轴显示内容选择     ").grid(row=0,column=0,sticky='W')
tkinter.Label(frame_5,text="多图排列方式选择    ").grid(row=0,column=1,sticky='W')
tkinter.Label(frame_5,text="X轴刻度设置").grid(row=0,column=2,columnspan=3,sticky='W')
V1 = tkinter.IntVar()
V2 = tkinter.IntVar()
V3 = tkinter.IntVar()
复选1 = tkinter.Checkbutton(frame_5,text='显示丢包率', variable=V1)
复选1.select() # 默认选中
复选1.grid(row=1,column=0,sticky='W')
复选2 = tkinter.Checkbutton(frame_5,text='显示最大延时', variable=V2)
复选2.select() # 默认选中
复选2.grid(row=2,column=0,sticky='W')
复选3 = tkinter.Checkbutton(frame_5,text='显示平均延时', variable=V3)
复选3.select() # 默认选中
复选3.grid(row=3,column=0,sticky='W')

tkinter.Label(frame_5,text="每",width=2).grid(row=1,column=2,sticky='W')
输入框9 = tkinter.Entry(frame_5,width=3)
输入框9.grid(row=1,column=3,sticky='W')
tkinter.Label(frame_5,text="分钟一个刻度").grid(row=1,column=4,sticky='W')
tkinter.Label(frame_5,text="默认值:1").grid(row=2,column=2,columnspan=3,sticky='W')

V = tkinter.IntVar()
## value=0 默认选中
单选1 = tkinter.Radiobutton(frame_5,text="并排显示", value=0, variable=V).grid(row=1, column=1, sticky='W')
单选2 = tkinter.Radiobutton(frame_5,text="并列显示", value=1, variable=V).grid(row=2, column=1, sticky='W')

画图按钮 = tkinter.Button(frame_6,text='画图分析',command=INFO_IMG).grid(row=0,column=0,sticky='W')
text2 = tkinter.Text(frame_6,width='50',height=9)
text2.grid(row=1,column=0,sticky='W')

text3 = tkinter.Text(frame_7,width='50',height=42)
text3.grid(row=0,column=0,sticky='W')

## 框架的位置布局
frame_1.grid(row=0,column=0,sticky='W')
frame_2.grid(row=1,column=0,sticky='W')
frame_3.grid(row=2,column=0,sticky='W')
frame_4.grid(row=3,column=0,sticky='W')
frame_5.grid(row=4,column=0,sticky='W')
frame_6.grid(row=5,column=0,sticky='W')
frame_7.grid(row=0,column=1,rowspan=6,sticky='WN')
frame_root.grid(row=0,column=0,sticky='W')

top.mainloop()

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值