定时ping取返回值并绘图

定时ping取返回值并绘图

  前些天一个朋友有要ping交易所前置以及绘制成折线图的需求,帮忙做了两天,感慨颇多,故写篇博客记录一下.

实际需求

  首先,我们的需求是,在window或者linux机器上定时执行ping + 网址 的语句,最终取到平均延迟,然后将这些延迟绘制成折线图.所以分析下来我们需要以下几个模块来实现这个功能.

需求分析

定时功能:

  datetime模块

用window机器远程控制linux机器,并发送指令:

  paramiko模块

绘制折线图:

  matplotlib模块

window机器上取本机的ping数据:

  subprocess模块

那么下面我们逐一分析这些模块,以及怎么样使用,完成最后的需求.

模块简介

datetime模块

相信我们都使用过这个模块,那么我们要实现每天定时来执行程序,就可以用以下方式来实现:

 
 
 
 
 
 
 
 
1
import datetime
知识兔
2
import time
知识兔
3
知识兔
4
def main():
知识兔
5
    while True:
知识兔
6
        while True:
知识兔
7
            now = datetime.datetime.now()# 这里可以取到系统的当前时间
知识兔
8
            if now.hour == 6 and now.minute == 30:# 取当前时间的小时和分钟,这样每天到这个设定好的小时和分钟内的时候我们就会跳出这个内循环,进入到外循环,从而执行主函数
知识兔
9
                # 当然设定时间我们也可以设定秒,但是其实设定到秒的情况下有可能无法进入函数,时间太短系统无法判定
知识兔
10
                break
知识兔
11
            if now.hour == 9 and now.minute == 30:
知识兔
12
                break
知识兔
13
            if now.hour == 12 and now.minute == 30:
知识兔
14
                break
知识兔
15
            if now.hour == 14 and now.minute == 30:
知识兔
16
                break
知识兔
17
            time.sleep(20)
知识兔
18
        # 主函数
知识兔
19
        time.sleep(60)# 这里加入睡眠60秒是为了让主函数不至于在这一分钟内一直执行,仅执行一次就好
知识兔
 
 

subprocess模块

这个模块主要用于python调用系统的cmd窗口并返回结果,具体实现如下.

 
 
 
xxxxxxxxxx
知识兔
1
26
 
 
 
 
1
# encoding=utf-8
知识兔
2
import subprocess # 导入模块,没装的话自己去pip install subprocess
知识兔
3
import sys
知识兔
4
知识兔
5
# 常用编码
知识兔
6
GBK = 'gbk'
知识兔
7
UTF8 = 'utf-8'
知识兔
8
知识兔
9
# 解码方式,一般 py 文件执行为utf-8 ,但是cmd 命令为 gbk
知识兔
10
current_encoding = GBK
知识兔
11
知识兔
12
popen = subprocess.Popen(['ping', 'www.baidu.com'],
知识兔
13
                         stdout=subprocess.PIPE,
知识兔
14
                         stderr=subprocess.PIPE,
知识兔
15
                         bufsize=1)
知识兔
16
知识兔
17
# 重定向标准输出
知识兔
18
while popen.poll() is None:  # None表示正在执行中
知识兔
19
    r = popen.stdout.readline().decode(current_encoding)
知识兔
20
    sys.stdout.write(r)  # 可修改输出方式,比如控制台、文件等
知识兔
21
知识兔
22
# 重定向错误输出
知识兔
23
if popen.poll() != 0:  # 不为0表示执行错误
知识兔
24
    err = popen.stderr.read().decode(current_encoding)
知识兔
25
    sys.stdout.write(err)  # 可修改输出方式,比如控制台、文件等
知识兔
 
 

matplotlib折线图

 
 
 
x
知识兔
 
 
 
 
1
'''
知识兔
2
折线图绘制的时候主要碰到了下面几个问题:
知识兔
3
1. 标签和折线的名称不能使用中文
知识兔
4
解决:导入一个字体模块或者不用中文,用全拼或者英文
知识兔
5
2. 绘图时候要控制图层的大小
知识兔
6
解决: 在刚开始绘图的时候加入plt.figure(figsize=(10, 8)),可以调整图层的大小,后面的(10,8)实际大小是乘以100,也就是1000*800的图片大小
知识兔
7
3. 最后保存图片的时候保存jpg格式出错
知识兔
8
解决:需要额外装一个模块,语句 pip install pillow
知识兔
9
'''
知识兔
10
# 例程如下
知识兔
11
from font_set import font_set# 这里我自己写了一个字体的模块,读者应该没有,可以忽略
知识兔
12
import matplotlib.pyplot as plt
知识兔
13
from pylab import mpl
知识兔
14
知识兔
15
mpl.rcParams['font.sans-serif'] = ['SimHei']  # SimHei是黑体的意思
知识兔
16
知识兔
17
x1 = ['06:00', '12:00', '18:00', '24:00']# 横轴
知识兔
18
y1 = [4, 6, 8, 23]
知识兔
19
z1 = [5, 5, 7, 15]
知识兔
20
a1 = [2, 9, 10, 6]
知识兔
21
知识兔
22
# x = np.random.random_integers(1, 20, 10)
知识兔
23
# # y = range(len(x))
知识兔
24
知识兔
25
知识兔
26
fig = plt.figure(figsize=(10, 8))# 控制图层的大小
知识兔
27
ax = fig.add_subplot(1, 1, 1)
知识兔
28
ax.plot(x1, y1)
知识兔
29
for x, y in zip(x1, y1):
知识兔
30
    plt.text(x, y + 0.3, '%.0f' % y, ha='center', va='bottom', fontsize=10.5)
知识兔
31
ax.plot(x1, z1)
知识兔
32
for x, y in zip(x1, z1):
知识兔
33
    plt.text(x, y + 0.3, '%.0f' % y, ha='center', va='bottom', fontsize=10.5)
知识兔
34
ax.plot(x1, a1)
知识兔
35
for x, y in zip(x1, a1):
知识兔
36
    plt.text(x, y + 0.3, '%.0f' % y, ha='center', va='bottom', fontsize=10.5)
知识兔
37
知识兔
38
plt.xlabel(u'时间', FontProperties=font_set)
知识兔
39
plt.ylabel(u'延迟', FontProperties=font_set)
知识兔
40
plt.title(u"各交易所交易延时", FontProperties=font_set)
知识兔
41
plt.legend([u"中金所", u"上期所", u"大商所"], prop=font_set)
知识兔
42
plt.savefig("1.jpg")# 这里要注意,要先保存再show,如果先show了保存图片就会是空白
知识兔
43
plt.show()
知识兔
 
 

paramiko模块

 
 
 
 
 
 
 
1
'''
知识兔
2
  paramiko模块主要作用是用python来远程连接服务器,发送请求以及取数据,由于使用的是python这样的能够跨平台运行的语言,所以所有python支持的平台,如Linux, Solaris, BSD, MacOS X, Windows等,paramiko都可以支持,因此,如果需要使用SSH从一个平台连接到另外一个平台,进行一系列的操作时,paramiko是最佳工具之一。
知识兔
3
'''
知识兔
4
知识兔
5
class Ping_jifang:# 定义一个ping的类
知识兔
6
知识兔
7
    def __init__(self, host_ip, username, password, command, port=22):
知识兔
8
        self.ssh = paramiko.SSHClient()
知识兔
9
        self.host_ip = host_ip
知识兔
10
        self.username = username
知识兔
11
        self.password = password
知识兔
12
        self.command = command
知识兔
13
        self.port = port
知识兔
14
知识兔
15
    def ssh_jifang(self):
知识兔
16
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
知识兔
17
        try:
知识兔
18
            self.ssh.connect(self.host_ip, self.port, self.username, self.password, timeout=8)
知识兔
19
            return True
知识兔
20
        except Exception as fail:
知识兔
21
            return False
知识兔
22
知识兔
23
    def exec_ssh_command(self):
知识兔
24
        stdin, stdout, stderr = self.ssh.exec_command(self.command)
知识兔
25
        result_all = stdout if stdout else stderr
知识兔
26
        # print(result_all.readlines())
知识兔
27
        return result_all.readline()
知识兔
28
        # return stdout
知识兔
29
        # print(self.command)
知识兔
30
        # result_all = os.popen(self.command)
知识兔
31
        # return result_all
知识兔
32
知识兔
33
    def logout(self):
知识兔
34
        self.ssh.close()
知识兔
35
知识兔
36
def main():
知识兔
37
    print('进入主函数')
知识兔
38
    ip_dit = {
知识兔
39
        "yidong1": {
知识兔
40
            "info": ["ip地址", "用户名", "密码"]
知识兔
41
        },
知识兔
42
        "yidong2": {
知识兔
43
            "info": ["ip地址", "用户名", "密码"]
知识兔
44
        },
知识兔
45
        "shuxun": {
知识兔
46
            "info": ["ip地址", "用户名", "密码"]
知识兔
47
        },
知识兔
48
        "languang": {
知识兔
49
            "info": ["ip地址", "用户名", "密码"]
知识兔
50
        }
知识兔
51
    }
知识兔
52
知识兔
53
    # 这个语句就是我们用当前操作机来发送给linux机器的语句
知识兔
54
    command_ping = "ping 114.114.114.114 -c 100 -i 0.001 -f | grep 'rtt' | awk -F '[ =/]+' '{print $7}'"
知识兔
55
知识兔
56
    for i in ip_dit:
知识兔
57
知识兔
58
        client_ping = Ping_jifang(ip_dit[i]["info"][0], ip_dit[i]["info"][1], ip_dit[i]["info"][2], command_ping)
知识兔
59
        if client_ping.ssh_jifang():
知识兔
60
            result = client_ping.exec_ssh_command()
知识兔
61
            result = eval(result[:-2])# 因为绘图需要列表,列表内要是int或者float数据,所以这里我们切割掉\n,然后用eval去掉引号,从而使列表内是符合要求的可以绘图的数据
知识兔
62
知识兔
63
            # print(i)
知识兔
64
            # print(type(a),yidong2.append(a),yidong2)
知识兔
65
            if i == "yidong1":
知识兔
66
                yidong1.append(result)
知识兔
67
            elif i == "yidong2":
知识兔
68
                yidong2.append(result)
知识兔
69
            elif i == "shuxun":
知识兔
70
                shuxun.append(result)
知识兔
71
            elif i == "languang":
知识兔
72
                languang.append(result)
知识兔
73
            else:
知识兔
74
                pass
知识兔
75
            client_ping.logout()
知识兔
76
知识兔
77
    print(yidong1)
知识兔
78
    print(yidong2)
知识兔
79
    print(shuxun)
知识兔
80
    print(languang)
知识兔
 
 

模块的使用就如上介绍,下面放上在linux和window机器上分别可以使用的完整程序.

window版本程序

 
 
 
xxxxxxxxxx
知识兔
1
112
 
 
1
'''
知识兔
2
此程序是取本机(windows)对于其他网址的ping延迟
知识兔
3
'''
知识兔
4
import subprocess, sys, time, re, datetime
知识兔
5
import numpy as np
知识兔
6
import matplotlib.pyplot as plt
知识兔
7
from matplotlib.font_manager import FontProperties
知识兔
8
from pylab import mpl
知识兔
9
from threading import Thread
知识兔
10
知识兔
11
mpl.rcParams['font.sans-serif'] = ['SimHei']  # SimHei是黑体的意思
知识兔
12
plt.style.use('ggplot')
知识兔
13
知识兔
14
np.random.seed(1)
知识兔
15
知识兔
16
# 字体要导一下,还有别的导字体方法,这只是一种
知识兔
17
font_set = FontProperties(fname=r"D:\\msyh.ttc", size=12)
知识兔
18
知识兔
19
count = 0
知识兔
20
知识兔
21
知识兔
22
# %Y-%m-%d
知识兔
23
def delay(host):
知识兔
24
    popen = subprocess.Popen(['ping', host],
知识兔
25
                             stdout=subprocess.PIPE,
知识兔
26
                             stderr=subprocess.PIPE,
知识兔
27
                             bufsize=1)
知识兔
28
    while popen.poll() is None:
知识兔
29
        r = popen.stdout.readline().decode('gbk')
知识兔
30
        # sys.stdout.write(r)
知识兔
31
知识兔
32
        # 这里是取字段的功能,linux里面应该是按avg取,windows里面是按汉字'平均'取得
知识兔
33
        res = re.findall(r'平均 = (.*?)ms', r)
知识兔
34
        if res:
知识兔
35
            return res[0]
知识兔
36
    if popen.poll() != 0:
知识兔
37
        err = popen.stderr.read()
知识兔
38
        sys.stdout.write(err)
知识兔
39
知识兔
40
知识兔
41
def run():
知识兔
42
    print('进入程序主体')
知识兔
43
    global time_x
知识兔
44
    time_x.append(time_now)
知识兔
45
    res1 = delay('www.qq.com')
知识兔
46
    global lis1
知识兔
47
    lis1.append(eval(res1))
知识兔
48
    res2 = delay('www.baidu.com')
知识兔
49
    global lis2
知识兔
50
    lis2.append(eval(res2))
知识兔
51
    res3 = delay('www.jianshu.com')
知识兔
52
    global lis3
知识兔
53
    lis3.append(eval(res3))
知识兔
54
    res4 = delay('www.runoob.com')
知识兔
55
    global lis4
知识兔
56
    lis4.append(eval(res4))
知识兔
57
知识兔
58
    print(len(lis1))
知识兔
59
    print(lis1)
知识兔
60
    time.sleep(1)
知识兔
61
    if len(lis1) == 4:  # 当取到四个延迟数据,也就是一天过去的时候,会生成折线图
知识兔
62
        print('进入绘图函数')
知识兔
63
        plt.figure(figsize=(10, 8))  # 调整图层大小
知识兔
64
        plt.plot(time_x, lis1, marker='o', mec='b', mfc='w', label=u'QQ')
知识兔
65
        for x, y in zip(time_x, lis1):
知识兔
66
            plt.text(x, y + 0.3, '%.0f' % y, ha='center', va='bottom', fontsize=10.5)
知识兔
67
知识兔
68
        plt.plot(time_x, lis2, marker='v', mec='g', mfc='w', label=u'百度')
知识兔
69
知识兔
70
        plt.plot(time_x, lis3, marker='^', mec='r', mfc='w', label=u'简书')
知识兔
71
        plt.plot(time_x, lis4, marker='s', mec='y', mfc='w', label=u'菜鸟编程')
知识兔
72
        plt.plot([0, 15, 30, 45], "rd")
知识兔
73
        plt.margins(0)
知识兔
74
        plt.subplots_adjust(bottom=0.10)
知识兔
75
        plt.xlabel(u'时间', FontProperties=font_set)  # X轴标签
知识兔
76
        plt.ylabel(u'延迟ms', FontProperties=font_set)  # Y轴标签
知识兔
 
 
77
        plt.title(u"各交易所交易延时", FontProperties=font_set)
知识兔
78
知识兔
79
        plt.grid(True)
知识兔
80
        plt.legend(loc=0)
知识兔
81
        global count
知识兔
82
        count += 1
知识兔
83
        plt.tight_layout()
知识兔
84
        plt.savefig(f"{date}-{count}.jpg")  # 保存的文件名
知识兔
85
        # plt.show()
知识兔
86
        plt.close()  # 这里要注意,一定要关闭当前图层,不然之后画出来的图会和之前的图合并出现
知识兔
87
        print('重置列表')
知识兔
88
        time_x.clear()
知识兔
89
        lis1.clear()
知识兔
90
        lis2.clear()
知识兔
91
        lis3.clear()
知识兔
92
        lis4.clear()
知识兔
93
知识兔
94
知识兔
95
if __name__ == '__main__':
知识兔
96
    # 设定的开始时间,即第一次等于这个时间的时候开始进入程序,得到第一个延迟数据,之后可以一直不关,这个时间会一直保持增长
知识兔
97
    sched_Timer = datetime.datetime(2019, 9, 27, 10, 38, 00)
知识兔
98
知识兔
99
    lis1 = list()
知识兔
100
    lis2 = list()
知识兔
101
    lis3 = list()
知识兔
102
    lis4 = list()
知识兔
103
    time_x = list()
知识兔
104
    while True:
知识兔
105
        date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
知识兔
106
        time_now = time.strftime('%H:%M:%S', time.localtime(time.time()))
知识兔
107
        now = datetime.datetime.now()  # 取到当前系统的时间
知识兔
108
        # if sched_Timer < now < (sched_Timer + datetime.timedelta(seconds=1)):
知识兔
109
        if 1 == 1:
知识兔
110
            t1 = Thread(target=run)  # 子线程
知识兔
111
            t1.start()
知识兔
112
            t1.join()
知识兔
113
            # 这里是延迟时间,即设定为hour=6就是六个小时ping一次数据,minutes=1就是一分钟ping一次,累计四次才会生成一个图片
知识兔
114
            sched_Timer = sched_Timer + datetime.timedelta(minutes=1)
知识兔
115
知识兔
 
 

linux版本程序

 
 
 
 
 
 
 
1
'''
知识兔
2
此程序是本机通过远程linux机器来取不同linux机器的ping的延迟
知识兔
3
'''
知识兔
4
import paramiko
知识兔
5
import time
知识兔
6
import datetime
知识兔
7
import matplotlib.pyplot as plt
知识兔
8
知识兔
9
# font_set = FontProperties(fname=r"D:\\msyh.ttc", size=12)
知识兔
10
# font_set = FontProperties(fname='utf-8', size=12)
知识兔
11
知识兔
12
知识兔
13
class Ping_jifang:
知识兔
14
知识兔
15
    def __init__(self, host_ip, username, password, command, port=22):
知识兔
16
        self.ssh = paramiko.SSHClient()
知识兔
17
        self.host_ip = host_ip
知识兔
18
        self.username = username
知识兔
19
        self.password = password
知识兔
20
        self.command = command
知识兔
21
        self.port = port
知识兔
22
知识兔
23
    def ssh_jifang(self):
知识兔
24
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
知识兔
25
        try:
知识兔
26
            self.ssh.connect(self.host_ip, self.port, self.username, self.password, timeout=8)
知识兔
27
            return True
知识兔
28
        except Exception as fail:
知识兔
29
            return False
知识兔
30
知识兔
31
    def exec_ssh_command(self):
知识兔
32
        stdin, stdout, stderr = self.ssh.exec_command(self.command)
知识兔
33
        result_all = stdout if stdout else stderr
知识兔
34
        # print(result_all.readlines())
知识兔
35
        return result_all.readline()
知识兔
36
        # return stdout
知识兔
37
        # print(self.command)
知识兔
38
        # result_all = os.popen(self.command)
知识兔
39
        # return result_all
知识兔
40
知识兔
41
    def logout(self):
知识兔
42
        self.ssh.close()
知识兔
43
知识兔
44
知识兔
45
def main():
知识兔
46
    print('进入主函数')
知识兔
47
    ip_dit = {
知识兔
48
        "yidong1": {
知识兔
49
            "info": ["10.0.0.99", "root", "1"]
知识兔
50
        },
知识兔
51
        "yidong2": {
知识兔
52
            "info": ["10.221.1.190", "root", "htqh@2019"]
知识兔
53
        },
知识兔
54
        "shuxun": {
知识兔
55
            "info": ["10.225.1.94", "root", "123456"]
知识兔
56
        },
知识兔
57
        "languang": {
知识兔
58
            "info": ["10.121.137.58", "root", "htqh@1234"]
知识兔
59
        }
知识兔
60
    }
知识兔
61
知识兔
62
    command_ping = "ping 114.114.114.114 -c 100 -i 0.001 -f | grep 'rtt' | awk -F '[ =/]+' '{print $7}'"
知识兔
63
知识兔
64
    for i in ip_dit:
知识兔
65
知识兔
66
        client_ping = Ping_jifang(ip_dit[i]["info"][0], ip_dit[i]["info"][1], ip_dit[i]["info"][2], command_ping)
知识兔
67
        if client_ping.ssh_jifang():
知识兔
68
            result = client_ping.exec_ssh_command()
知识兔
69
            result = eval(result[:-2])
知识兔
70
知识兔
71
            # print(i)
知识兔
72
            # print(type(a),yidong2.append(a),yidong2)
知识兔
73
            if i == "yidong1":
知识兔
74
                yidong1.append(result)
知识兔
75
            elif i == "yidong2":
知识兔
76
                yidong2.append(result)
知识兔
77
            elif i == "shuxun":
知识兔
78
                shuxun.append(result)
知识兔
79
            elif i == "languang":
知识兔
80
                languang.append(result)
知识兔
81
            else:
知识兔
82
                pass
知识兔
83
            client_ping.logout()
知识兔
84
知识兔
85
    print(yidong1)
知识兔
86
    print(yidong2)
知识兔
87
    print(shuxun)
知识兔
88
    print(languang)
知识兔
89
知识兔
90
    # 绘图函数
知识兔
91
    if len(yidong2) == 4:  # 当取到四个延迟数据,也就是一天过去的时候,会生成折线图
知识兔
92
        plt.figure(figsize=(10, 8))  # 调整图层大小
知识兔
93
        time_x = ['06:00', '09:00', '12:00', '15:00']
知识兔
94
        date = time.strftime('%Y-%m-%d', time.localtime(time.time()))
知识兔
95
        print('进入绘图函数')
知识兔
96
        # plt.plot(time_x, yidong1, marker='o', mec='b', mfc='w', label=u'QQ')
知识兔
97
        for x, y in zip(time_x, yidong2):
知识兔
98
            plt.text(x, y + 0.3, '%.0f' % y, ha='center', va='bottom', fontsize=10.5)
知识兔
99
        plt.plot(time_x, yidong2, marker='v', mec='g', mfc='w', label=u'shuxun')
知识兔
100
        plt.plot(time_x, shuxun, marker='^', mec='r', mfc='w', label=u'zhongjinsuo')
知识兔
101
        plt.plot(time_x, languang, marker='s', mec='y', mfc='w', label=u'yidong')
知识兔
102
        plt.ylim(0, 20) # 纵坐标范围
知识兔
103
        y = range(0, 20, 1)
知识兔
104
        plt.yticks(y)   # 纵坐标刻度
知识兔
105
        plt.margins(0)
知识兔
106
        plt.subplots_adjust(bottom=0.10)
知识兔
107
        plt.xlabel(u'time')  # X轴标签
知识兔
108
        plt.ylabel(u'ms')  # Y轴标签
知识兔
109
        plt.title(u"timedelate")
知识兔
110
知识兔
111
        plt.legend(loc=0)
知识兔
112
        global count
知识兔
113
        count += 1
知识兔
114
        plt.tight_layout()
知识兔
115
        plt.savefig(f"{date}-{count}.jpg")  # 保存的文件名
知识兔
116
        # plt.show()
知识兔
117
        plt.close()  # 这里要注意,一定要关闭当前图层,不然之后画出来的图会和之前的图合并出现
知识兔
118
        print('重置列表')
知识兔
119
        time_x.clear()
知识兔
120
        yidong1.clear()
知识兔
121
        yidong2.clear()
知识兔
122
        shuxun.clear()
知识兔
123
        languang.clear()
知识兔
124
知识兔
125
知识兔
126
if __name__ == "__main__":
知识兔
127
    yidong1 = []
知识兔
128
    yidong2 = []
知识兔
129
    shuxun = []
知识兔
130
    languang = []
知识兔
131
    count = 0
知识兔
132
    while True:
知识兔
133
        while True:
知识兔
134
            now = datetime.datetime.now()
知识兔
135
            print(f'\r当前时间:{now}', end='')
知识兔
136
            if now.hour == 16 and now.minute == 1:
知识兔
137
                break
知识兔
138
            if now.hour == 16 and now.minute == 15:
知识兔
139
                break
知识兔
140
            if now.hour == 16 and now.minute == 16:
知识兔
141
                break
知识兔
142
            if now.hour == 16 and now.minute == 17:
知识兔
143
                break
知识兔
144
            time.sleep(1)
知识兔
145
        time.sleep(61)
知识兔
146
        main()
知识兔
147
知识兔
 
 
计算机