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'初始化数据库 {数据库文件名} 失败')