Python3 网络测试,使用多线程每秒PING目标,并记录到SQLite3数据库中,方便后面分析画图


import time
import re
import subprocess
import sqlite3
from threading import Thread

# V1.0
# 双击运行会弹出一个CMD命令框,打印运行情况,CTRL+C不能终止程序(使用鼠标左键单击命令框可以暂停显示,右键单击继续显示)



## 初始化数据库
# 根据IP或域名建立PING延时记录表
# 字段1:时间戳(作为ID)字段2:延时
# 时间戳只精确到秒 int(time.time())
def 初始化数据库(数据库文件名, 任务列表):
    数据库连接对象 = sqlite3.connect(数据库文件名)
    游标对象 = 数据库连接对象.cursor()         # 创建一个游标
    try:
        游标对象.execute('SELECT NAME FROM sqlite_master')      # 查询数据库里全部表的表名
    except Exception as e:
        游标对象.close()
        return(1,e)
    else:
        全部记录 = 游标对象.fetchall()          # [('表名',), ('表名',)]
        L_全部表名 = [i[0] for i in 全部记录]
    
        for i in 任务列表:
            TABLE_NAME = 'PING_' + i.replace('.', '_')      # 表名中不能使用'.'符号
            if TABLE_NAME in L_全部表名:
                print("已存在表", TABLE_NAME)
                try:
                    游标对象.execute(f'PRAGMA table_info ({TABLE_NAME})')
                except Exception as e:
                    游标对象.close()
                    return(1,e)
                else:
                    全部字段 = 游标对象.fetchall()      # 获取全部查询数据记录 全部记录 [(0, 'TIME', 'INT', 0, None, 1), (1, 'MS', 'INT', 0, None, 0)]
                    for 字段 in 全部字段:
                        if 字段[1] == 'TIME':
                            if 字段[2] == 'INT':
                                #print("TIME 字段属性正确", 字段)
                                pass
                            else:
                                e = f'表{TABLE_NAME} 字段TIME 类型不是INT'
                                return(1,e)
                        elif 字段[1] == 'MS':
                            if 字段[2] == 'INT':
                                #print("MS 字段属性正确", 字段)
                                pass
                            else:
                                e = f'表{TABLE_NAME} 字段MS 类型不是INT'
                                return(1,e)
                        else:
                            e = f'表{TABLE_NAME} 没有字段TIME和MS'
                            return(1,e)
            else:
                print("创建表", TABLE_NAME)
                游标对象.execute(f'CREATE TABLE {TABLE_NAME} (TIME INT PRIMARY KEY, MS INT);')
                数据库连接对象.commit()
    return(0,数据库文件名)


## 非查询的SQL语句(执行一条SQL语句)(每次执行都要打开关闭游标)
def DEF_SQL_执行(数据库连接对象,SQL_CMD):
    try:
        游标对象 = 数据库连接对象.cursor()    # 创建一个游标
    except Exception as e:
        ERROR = '创建游标失败' + str(e)
        return(1, ERROR)
    else:
        try:
            游标对象.execute(SQL_CMD)
        except Exception as e:
            ERROR = str(e)
            游标对象.close()
            return(1, ERROR)
        else:
            数据库连接对象.commit()           # 提交更改
            游标对象.close()
            return(0,)


## 每隔1秒创建一个线程用于执行PING命令
def 定时线程(秒, 任务):
    while 1:
        TIME = time.time()
        if TIME - int(TIME) > 0.5:  # 修正因为累计多次后造成的时间偏差
            time.sleep(秒-0.2)
        else:
            time.sleep(秒)
        #print("定时线程", time.time(), "启动新任务线程")
        t=Thread(target=任务线程_生产, args=(任务,))
        t.start()


## 处理PING命令的返回结果
def 任务线程_生产(任务):
    TIME = time.time()
    cmd = 'ping -n 1 ' + 任务
    win = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
    #print("子进程PID", win.pid)
    R = win.stdout.read().decode('GBK')
    RE_S = re.search('[0-9]+ms', R)
    if RE_S:
        MS = RE_S.group()           # 提取PING延时结果
    else:
        MS = '2000ms'               # CMD默认2000ms为超时
    L_PING_INFO.append((任务,TIME,MS))


## 把每个任务的结果保存到数据库(没有按时间顺序写入数据库,谁先完成就先写入谁,分析时读取数据再排序)
def 任务线程_消费(秒,数据库文件名):
    数据库连接对象 = sqlite3.connect(数据库文件名)
    while 1:
        if L_PING_INFO != []:
            元素 = L_PING_INFO.pop(0)
            #print("元素", 元素)
            TABLE_NAME = 'PING_'+ 元素[0].replace('.', '_')
            TIME = int(元素[1])
            MS = 元素[2].replace('ms', '')
            SQL = f'INSERT INTO {TABLE_NAME} (TIME,MS) VALUES ({TIME},{MS})'
            R = DEF_SQL_执行(数据库连接对象,SQL)
            print(SQL, R)
        time.sleep(秒)



## PING结果记录队列 每个元素内容:(IP,启动时间戳,响应延时)
## append() 增加元素
## pop(0) 提取元素
L_PING_INFO = []

数据库文件名 = 'PING.db'
任务列表 = ['baidu.com','8.8.8.8','114.114.114.114']


R = 初始化数据库(数据库文件名, 任务列表)
if R[0] == 0:
    print(f'初始化数据库 {数据库文件名} 成功')
    每秒消费频次 = round(1/len(任务列表),1)
    print("每秒消费频次", 每秒消费频次)
    t2=Thread(target=任务线程_消费, args=(每秒消费频次,数据库文件名))
    t2.start()
    for 任务 in 任务列表:
        t1=Thread(target=定时线程, args=(1,任务))
        t1.start()
else:
    print(f'初始化数据库 {数据库文件名} 失败')

 

你可能感兴趣的:(python,python,队列,数据库,列表)