定制相关数据的展示之后,还需要实现一些功能便于告知用户当前IP地址实际占用情况
需求包括:
1、多线程并发执行对每个IP地址的操作
2、规则:(表字段包括:ip地址、ip使用状态、使用人ID、使用人用户名、备注信息、非法使用天数、无法连接天数)
①若当前IP属于空闲,实际情况:ping通 —> 表示被非法使用,则非法使用天数+1;ping不通 —> 正常情况,因为不被使用,非法使用天数=0,表示已经恢复正常状态
②若当前IP属于使用中,实际情况:ping不通 —> 表示已经不被使用,无法连接天数+1;ping通 —> 正常情况,因为正在使用,无法连接天数=0,表示已经恢复正常状态
③若当前IP属于空闲,若无法连接天数>0,则执行无法连接天数=0,因为无法连接属于正常状况,清除之前的遗留数据;
④若当前IP属于使用中,若非法使用天数>0,则执行非法使用天数=0,因为能连接属于正常状况,清除之前的遗留数据;
所以这里的非法使用天数、无法连接天数都是讲究连续性的,偶尔一两天的不正常状态可能是断电断网/临时借用一两小时,如果连续7天或者20天告警说明是真的没有通知的情况下使用了或者IP已经不被使用了。
views.py
凡是被标注【#把print改成写入日志】的都是当前调试打印出来观察的,之后计划改成写入日志的
1 from mysiteapp.models import ipaddr_info 2 # Create your views here. 3 import subprocess 4 import threading 5 6 7 # 检查IP是否被占用 8 def get_ping_result(ip): 9 cmd_str = "ping {0} -n 4 -w 600".format(ip) 10 DETACHED_PROCESS = 0x00000008 # 不创建cmd窗口 11 try: 12 subprocess.run(cmd_str, creationflags=DETACHED_PROCESS, check=True) # 仅用于windows系统 13 except subprocess.CalledProcessError as err: 14 print("ping不通"+ip) #把print改成写入日志 15 return 0 16 else: 17 print("ping通"+ip) # 把print改成写入日志 18 return 1 19 20 #处理规则 21 def ip_status_alarm(ip): 22 x = get_ping_result(ip) 23 try: 24 ipobj = ipaddr_info.objects.get(ipaddr=ip) 25 except ipaddr_info.DoesNotExist: 26 print("Address does not exit!") 27 else: 28 if ipobj.ipstatus == 0: 29 print("0,空闲", ip) #把print改成写入日志 30 if x == 1: 31 print("1,ping通", ip) # 把print改成写入日志 32 # 取出connect_alarm_num告警数,+1,存回数据库 33 connect_alarm_num0 = ipobj.connect_alarm_num + 1 34 ipaddr_info.objects.filter(ipaddr=ip).update(connect_alarm_num=connect_alarm_num0) 35 else: 36 print("1,ping不通", ip) # 把print改成写入日志 37 ipaddr_info.objects.filter(ipaddr=ip).update(connect_alarm_num=0) 38 if ipobj.disconnect_alarm_num > 0: 39 # 如果disconnect_alarm_num告警数>0,置为0 40 ipaddr_info.objects.filter(ipaddr=ip).update(disconnect_alarm_num=0) 41 else: 42 print("1,使用中", ip)#把print改成写入日志 43 if x == 0: 44 print("1,ping不通", ip) # 把print改成写入日志 45 # 取出disconnect_alarm_num告警数,+1 46 disconnect_alarm_num1 = ipobj.disconnect_alarm_num + 1 47 ipaddr_info.objects.filter(ipaddr=ip).update(disconnect_alarm_num=disconnect_alarm_num1) 48 else: 49 print("1,ping通", ip) # 把print改成写入日志 50 ipaddr_info.objects.filter(ipaddr=ip).update(disconnect_alarm_num=0) 51 if ipobj.connect_alarm_num > 0: 52 # 如果connect_alarm_num告警数>0,置为0 53 ipaddr_info.objects.filter(ipaddr=ip).update(connect_alarm_num=0) 54 55 56 # 使用多线程 57 def start_ping(startip, endip): 58 stip = startip.split('.') 59 enip = endip.split('.') 60 tmp_ip = stip 61 a = 1 62 pthread_list = [] 63 for i in range(int(stip[3]), int(enip[3]) + 1): 64 tmp_ip[3] = str(i) 65 ip = '.'.join(tmp_ip) 66 print("多线程拼接ip是否成功"+ip) #改为写入日志 67 pthread_list.append(threading.Thread(target=ip_status_alarm, args=(ip,))) 68 for item in pthread_list: 69 # item.setDaemon(False) 70 print("启动第几个线程:", a) # 改为写入日志 71 a = a + 1 72 item.start() 73 for item in pthread_list: 74 item.join() 75 76 # 导入Python标准库中的Thread模块 77 # from threading import Thread 78 # 创建一个线程,args: 线程执行方法接收的参数,该属性是一个元组,如果只有一个参数也需要在末尾加逗号。 79 # mthread = threading.Thread(target=function_name, args=(function_parameter1, function_parameterN)) 80 # join ()方法:主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后,才可以接着往下执行,那么在调用这个线程时可以使用被调用线程的join方法。 81 # setDaemon()方法。主线程A中,创建了子线程B,并且在主线程A中调用了B.setDaemon(),这个的意思是,把主线程A设置为守护线程,这时候,要是主线程A执行结束了,就不管子线程B是否完成,一并和主线程A退出.这就是setDaemon方法的含义,这基本和join是相反的。 82 # 此外,还有个要特别注意的:必须在start() 方法调用之前设置,如果不设置为守护线程,程序会被无限挂起。
test.py
比较啰嗦的测试代码,就不精简了。。。。
这里使用了两种测试情况:
① 1.1.1.1是被定义为空闲的IP,但实际可以ping通,而且disconnect_alarm_num(无法连接天数)有残留数据的测试用例
预期结果:connect_alarm_num(非法使用天数)+1、disconnect_alarm_num(无法连接天数)=0
②2.2.2.2是被定义为使用中的IP,但实际ping不通,而且connect_alarm_num(非法使用天数)有残留数据的测试用例
预期结果:disconnect_alarm_num(无法连接天数)+1、connect_alarm_num(非法使用天数)=0
还可以增加测试用例
① 3.3.3.3是被定义为空闲的IP,且实际ping不通,但connect_alarm_num(非法使用天数)有非0数据的测试用例
预期结果:connect_alarm_num(非法使用天数)=0、disconnect_alarm_num(无法连接天数)=0
②4.4.4.4是被定义为使用中的IP,且实际可以ping通,但disconnect_alarm_num(无法连接天数)有残留数据的测试用例
预期结果:disconnect_alarm_num(无法连接天数)=0、connect_alarm_num(非法使用天数)=0
from django.test import TestCase, TransactionTestCase from mysiteapp import views from mysiteapp.models import ipaddr_info # Create your tests here. class start_ping_test(TransactionTestCase): def setUp(self): ipaddr_info.objects.create(ipaddr="1.1.1.1", ipstatus="0", disconnect_alarm_num=5) ipaddr_info.objects.create(ipaddr="2.2.2.2", ipstatus="1", connect_alarm_num=5) startip='1.1.1.1' endip='2.2.2.2' stip = startip.split('.') enip = endip.split('.') tmp_ip = stip for i in range(int(stip[3]), int(enip[3]) + 1): tmp_ip[3] = str(i) ip = '.'.join(tmp_ip) ipobj = ipaddr_info.objects.get(ipaddr=ip) print("这是开始:", ipobj.ipaddr, ipobj.ipstatus, ipobj.disconnect_alarm_num, ipobj.connect_alarm_num) def test_ping(self): startip = '1.1.1.1' endip = '2.2.2.2' views.start_ping(startip, endip) #TestCase情况下,从主函数进去,调用子函数的时候查无数据 # views.ip_status_alarm(startip) #直接从子函数进去,才有数据 # views.ip_status_alarm(endip) def tearDown(self): for item in ipaddr_info.objects.all(): print("这是结束:", item.ipaddr, item.ipstatus, item.disconnect_alarm_num, item.connect_alarm_num)
执行结果: