33# Update by : https://github.com/cppla/ServerStatus, Update date: 20220530
44# 版本:1.0.3, 支持Python版本:2.7 to 3.10
55# 支持操作系统: Linux, OSX, FreeBSD, OpenBSD and NetBSD, both 32-bit and 64-bit architectures
6+ # ONLINE_PACKET_HISTORY_LEN, 探测间隔60s,记录24小时在线率(1440);探测间隔60s,记录7天(10080);探测时间30s,记录24小时(2880)
67# 说明: 默认情况下修改server和user就可以了。丢包率监测方向可以自定义,例如:CU = "www.facebook.com"。
78
89SERVER = "127.0.0.1"
1718PROBEPORT = 80
1819PROBE_PROTOCOL_PREFER = "ipv4" # ipv4, ipv6
1920PING_PACKET_HISTORY_LEN = 100
21+ ONLINE_PACKET_HISTORY_LEN = 10080
2022INTERVAL = 1
2123
2224import socket
25+ import ssl
2326import time
2427import timeit
2528import re
2932import errno
3033import subprocess
3134import threading
32- try :
33- from queue import Queue # python3
34- except ImportError :
35- from Queue import Queue # python2
35+ if sys . version_info . major == 3 :
36+ from queue import Queue
37+ elif sys . version_info . major == 2 :
38+ from Queue import Queue
3639
3740def get_uptime ():
3841 with open ('/proc/uptime' , 'r' ) as f :
@@ -150,6 +153,7 @@ def get_network(ip_version):
150153 'read' : 0 ,
151154 'write' : 0
152155}
156+ monitorServer = {}
153157
154158def _ping_thread (host , mark , port ):
155159 lostPacket = 0
@@ -314,6 +318,91 @@ def get_realtime_data():
314318 ti .daemon = True
315319 ti .start ()
316320
321+
322+ def _monitor_thread (name , host , interval , type ):
323+ lostPacket = 0
324+ packet_queue = Queue (maxsize = ONLINE_PACKET_HISTORY_LEN )
325+ while True :
326+ if name not in monitorServer .keys ():
327+ break
328+ if packet_queue .full ():
329+ if packet_queue .get () == 0 :
330+ lostPacket -= 1
331+ try :
332+ if type == "http" :
333+ address = host .replace ("http://" , "" )
334+ m = timeit .default_timer ()
335+ if PROBE_PROTOCOL_PREFER == 'ipv4' :
336+ IP = socket .getaddrinfo (address , None , socket .AF_INET )[0 ][4 ][0 ]
337+ else :
338+ IP = socket .getaddrinfo (address , None , socket .AF_INET6 )[0 ][4 ][0 ]
339+ monitorServer [name ]["dns_time" ] = int ((timeit .default_timer () - m ) * 1000 )
340+ m = timeit .default_timer ()
341+ k = socket .create_connection ((IP , 80 ), timeout = 6 )
342+ monitorServer [name ]["connect_time" ] = int ((timeit .default_timer () - m ) * 1000 )
343+ m = timeit .default_timer ()
344+ k .sendall ("GET / HTTP/1.2\r \n Host:{}\r \n Connection:close\r \n \r \n " .format (address ).encode ('utf-8' ))
345+ response = b""
346+ while True :
347+ data = k .recv (4096 )
348+ if not data :
349+ break
350+ response += data
351+ http_code = response .decode ('utf-8' ).split ('\r \n ' )[0 ].split ()[1 ]
352+ monitorServer [name ]["download_time" ] = int ((timeit .default_timer () - m ) * 1000 )
353+ k .close ()
354+ if http_code not in ['200' , '204' , '301' , '302' , '401' ]:
355+ raise Exception ("http code not in 200, 204, 301, 302, 401" )
356+ elif type == "https" :
357+ context = ssl ._create_unverified_context ()
358+ address = host .replace ("https://" , "" )
359+ m = timeit .default_timer ()
360+ if PROBE_PROTOCOL_PREFER == 'ipv4' :
361+ IP = socket .getaddrinfo (address , None , socket .AF_INET )[0 ][4 ][0 ]
362+ else :
363+ IP = socket .getaddrinfo (address , None , socket .AF_INET6 )[0 ][4 ][0 ]
364+ monitorServer [name ]["dns_time" ] = int ((timeit .default_timer () - m ) * 1000 )
365+ m = timeit .default_timer ()
366+ k = socket .create_connection ((IP , 443 ), timeout = 6 )
367+ monitorServer [name ]["connect_time" ] = int ((timeit .default_timer () - m ) * 1000 )
368+ m = timeit .default_timer ()
369+ kk = context .wrap_socket (k , server_hostname = address )
370+ kk .sendall ("GET / HTTP/1.2\r \n Host:{}\r \n Connection:close\r \n \r \n " .format (address ).encode ('utf-8' ))
371+ response = b""
372+ while True :
373+ data = kk .recv (4096 )
374+ if not data :
375+ break
376+ response += data
377+ http_code = response .decode ('utf-8' ).split ('\r \n ' )[0 ].split ()[1 ]
378+ monitorServer [name ]["download_time" ] = int ((timeit .default_timer () - m ) * 1000 )
379+ kk .close ()
380+ k .close ()
381+ if http_code not in ['200' , '204' , '301' , '302' , '401' ]:
382+ raise Exception ("http code not in 200, 204, 301, 302, 401" )
383+ elif type == "tcp" :
384+ m = timeit .default_timer ()
385+ if PROBE_PROTOCOL_PREFER == 'ipv4' :
386+ IP = socket .getaddrinfo (host .split (":" )[0 ], None , socket .AF_INET )[0 ][4 ][0 ]
387+ else :
388+ IP = socket .getaddrinfo (host .split (":" )[0 ], None , socket .AF_INET6 )[0 ][4 ][0 ]
389+ monitorServer [name ]["dns_time" ] = int ((timeit .default_timer () - m ) * 1000 )
390+ m = timeit .default_timer ()
391+ k = socket .create_connection ((IP , int (host .split (":" )[1 ])), timeout = 6 )
392+ monitorServer [name ]["connect_time" ] = int ((timeit .default_timer () - m ) * 1000 )
393+ m = timeit .default_timer ()
394+ k .send (b"GET / HTTP/1.2\r \n \r \n " )
395+ k .recv (1024 )
396+ monitorServer [name ]["download_time" ] = int ((timeit .default_timer () - m ) * 1000 )
397+ k .close ()
398+ packet_queue .put (1 )
399+ except Exception as e :
400+ lostPacket += 1
401+ packet_queue .put (0 )
402+ if packet_queue .qsize () > 5 :
403+ monitorServer [name ]["online_rate" ] = 1 - float (lostPacket ) / packet_queue .qsize ()
404+ time .sleep (interval )
405+
317406def byte_str (object ):
318407 '''
319408 bytes to str, str to bytes
@@ -360,6 +449,28 @@ def byte_str(object):
360449 if data .find ("You are connecting via" ) < 0 :
361450 data = byte_str (s .recv (1024 ))
362451 print (data )
452+ monitorServer .clear ()
453+ for i in data .split ('\n ' ):
454+ if "monitor" in i and "type" in i and "{" in i and "}" in i :
455+ jdata = json .loads (i [i .find ("{" ):i .find ("}" )+ 1 ])
456+ monitorServer [jdata .get ("name" )] = {
457+ "type" : jdata .get ("type" ),
458+ "dns_time" : 0 ,
459+ "connect_time" : 0 ,
460+ "download_time" : 0 ,
461+ "online_rate" : 1
462+ }
463+ t = threading .Thread (
464+ target = _monitor_thread ,
465+ kwargs = {
466+ 'name' : jdata .get ("name" ),
467+ 'host' : jdata .get ("host" ),
468+ 'interval' : jdata .get ("interval" ),
469+ 'type' : jdata .get ("type" )
470+ }
471+ )
472+ t .daemon = True
473+ t .start ()
363474
364475 timer = 0
365476 check_ip = 0
@@ -378,7 +489,6 @@ def byte_str(object):
378489 Load_1 , Load_5 , Load_15 = os .getloadavg ()
379490 MemoryTotal , MemoryUsed , SwapTotal , SwapFree = get_memory ()
380491 HDDTotal , HDDUsed = get_hdd ()
381-
382492 array = {}
383493 if not timer :
384494 array ['online' + str (check_ip )] = get_network (check_ip )
@@ -401,8 +511,6 @@ def byte_str(object):
401511 array ['network_tx' ] = netSpeed .get ("nettx" )
402512 array ['network_in' ] = NET_IN
403513 array ['network_out' ] = NET_OUT
404- # todo:兼容旧版本,下个版本删除ip_status
405- array ['ip_status' ] = True
406514 array ['ping_10010' ] = lostRate .get ('10010' ) * 100
407515 array ['ping_189' ] = lostRate .get ('189' ) * 100
408516 array ['ping_10086' ] = lostRate .get ('10086' ) * 100
@@ -412,16 +520,18 @@ def byte_str(object):
412520 array ['tcp' ], array ['udp' ], array ['process' ], array ['thread' ] = tupd ()
413521 array ['io_read' ] = diskIO .get ("read" )
414522 array ['io_write' ] = diskIO .get ("write" )
415-
523+ array [ 'custom' ] = "<br>" . join ( f" { k } \\ t解析: { v [ 'dns_time' ] } \\ t连接: { v [ 'connect_time' ] } \\ t下载: { v [ 'download_time' ] } \\ t在线率: <code> { v [ 'online_rate' ] * 100 :.1f } %</code>" for k , v in monitorServer . items ())
416524 s .send (byte_str ("update " + json .dumps (array ) + "\n " ))
417525 except KeyboardInterrupt :
418526 raise
419527 except socket .error :
528+ monitorServer .clear ()
420529 print ("Disconnected..." )
421530 if 's' in locals ().keys ():
422531 del s
423532 time .sleep (3 )
424533 except Exception as e :
534+ monitorServer .clear ()
425535 print ("Caught Exception:" , e )
426536 if 's' in locals ().keys ():
427537 del s
0 commit comments