autool/utils_android/Manager/network_manager.py
2026-06-17 19:44:18 +08:00

265 lines
9.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import uuid
import socket
import time
import logging
import subprocess
import platform
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime, timedelta
from threading import Event
# Configure logging
# logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class NetworkException(Exception):
"""网络异常连续10分钟无网络时抛出"""
def __init__(self, message, mac_address=None, ip_address=None):
self.mac_address = mac_address
self.ip_address = ip_address
super().__init__(message)
# ==========================================
# 1. 简单的网络检测函数(用于 main 循环)
# ==========================================
def get_mac_address():
"""获取本机 MAC 地址"""
mac = uuid.getnode()
return ':'.join(('%012X' % mac)[i:i+2] for i in range(0, 12, 2))
def get_ip_address():
"""获取本机 IP 地址"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
def check_network(host="8.8.8.8", timeout=3):
"""
简单的网络连接检测函数(同步,不抛异常)
使用 ping 命令检测网络连通性
:param host: 目标主机,默认 8.8.8.8 (Google DNS)
:param timeout: 超时时间默认3秒
:return: True 表示网络正常False 表示网络异常
"""
try:
# 根据操作系统选择 ping 参数
if platform.system().lower() == "windows":
# Windows: -n 次数, -w 超时(毫秒)
cmd = ["ping", "-n", "1", "-w", str(timeout * 1000), host]
else:
# Linux/Mac: -c 次数, -W 超时(秒)
cmd = ["ping", "-c", "1", "-W", str(timeout), host]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return result.returncode == 0
except Exception:
return False
def wait_for_network(check_interval=5, max_wait_time=None):
"""
等待网络恢复(阻塞式)
:param check_interval: 检查间隔(秒)
:param max_wait_time: 最大等待时间None 表示无限等待
:return: True 表示网络已恢复False 表示超时
"""
mac = get_mac_address()
ip = get_ip_address()
start_time = datetime.now()
logger.warning(f"网络连接失败,等待网络恢复... (MAC: {mac}, IP: {ip})")
while True:
if check_network():
logger.info(f"网络已恢复正常 (MAC: {mac}, IP: {ip})")
return True
if max_wait_time:
elapsed = (datetime.now() - start_time).total_seconds()
if elapsed >= max_wait_time:
logger.error(f"等待网络恢复超时 ({max_wait_time}秒)")
return False
time.sleep(check_interval)
# ==========================================
# 2. 后台网络监控(用于 run 方法)
# ==========================================
class NetworkWatchdog:
"""后台网络监控使用独立线程检测网络状态断网10分钟后抛出异常"""
def __init__(self, timeout_minutes=10, check_interval=600):
"""
初始化后台网络监控
:param timeout_minutes: 连续无网络超时时间分钟默认10分钟
:param check_interval: 检查间隔默认5秒
"""
self.mac = get_mac_address()
self.ip = get_ip_address()
self.timeout_minutes = timeout_minutes
self.check_interval = check_interval
self.network_lost_time = None # 记录网络断开的开始时间
self._stop_event = Event()
self._executor = ThreadPoolExecutor(max_workers=1)
self._future = None
self._exception = None # 存储监控线程中发生的异常
def _monitor_loop(self):
"""后台监控循环(在独立线程中运行)"""
logger.info(f"网络监控后台线程已启动 (超时: {self.timeout_minutes}分钟)")
try:
while not self._stop_event.is_set():
self.ip = get_ip_address()
if check_network():
if self.network_lost_time is not None:
logger.info(f"网络已恢复正常 (MAC: {self.mac}, IP: {self.ip})")
self.network_lost_time = None
self._stop_event.wait(self.check_interval)
else:
current_time = datetime.now()
if self.network_lost_time is None:
self.network_lost_time = current_time
logger.warning(f"检测到网络断开 (MAC: {self.mac}, IP: {self.ip}),开始计时...")
disconnected_duration = current_time - self.network_lost_time
if disconnected_duration >= timedelta(minutes=self.timeout_minutes):
error_msg = f"网络连续断开超过 {self.timeout_minutes} 分钟"
logger.error(f"{error_msg} (MAC: {self.mac}, IP: {self.ip})")
self._exception = NetworkException(
error_msg,
mac_address=self.mac,
ip_address=self.ip
)
break
logger.warning(
f"网络仍然断开,已持续 {disconnected_duration.total_seconds():.0f}"
f"(MAC: {self.mac}, IP: {self.ip})"
)
self._stop_event.wait(5)
except Exception as e:
logger.error(f"网络监控线程出现异常: {e}")
self._exception = e
finally:
logger.info("网络监控后台线程已停止")
def start(self):
"""启动后台监控"""
if self._future is not None:
logger.warning("网络监控已经在运行中")
return
self._stop_event.clear()
self._exception = None
self._future = self._executor.submit(self._monitor_loop)
def stop(self):
"""停止后台监控"""
if self._future is None:
return
logger.info("正在停止网络监控...")
self._stop_event.set()
# 等待线程结束
try:
self._future.result(timeout=10)
except Exception as e:
logger.error(f"等待监控线程结束时出错: {e}")
self._future = None
def check_and_raise(self):
"""
检查监控线程是否检测到网络异常,如果有则抛出
:raises NetworkException: 当检测到网络连续断开超过指定时间时抛出
"""
if self._exception is not None:
raise self._exception
def shutdown(self):
"""停止监控并关闭线程池"""
self.stop()
self._executor.shutdown(wait=False)
logger.info("网络监控资源已清理")
# ==========================================
# 3. 兼容旧版本的 NetworkMonitor 类
# ==========================================
class NetworkMonitor:
"""
兼容旧版本的 NetworkMonitor 类
内部使用 NetworkWatchdog 实现
"""
def __init__(self, timeout_minutes=10):
self.watchdog = NetworkWatchdog(timeout_minutes=timeout_minutes)
self.mac = self.watchdog.mac
self.ip = self.watchdog.ip
def check_network_with_timeout(self):
"""兼容方法:检查并抛出异常"""
self.watchdog.check_and_raise()
def shutdown(self):
"""兼容方法:关闭资源"""
self.watchdog.shutdown()
if __name__ == "__main__":
print("=== 测试1: 简单网络检测 ===")
mac = get_mac_address()
ip = get_ip_address()
print(f"MAC: {mac}, IP: {ip}")
if check_network():
print("✓ 网络连接正常")
else:
print("✗ 网络连接失败")
print("\n=== 测试2: 后台网络监控 (30秒超时) ===")
watchdog = NetworkWatchdog(timeout_minutes=0.5, check_interval=2) # 30秒超时2秒检查一次
try:
watchdog.start()
print("后台监控已启动,模拟任务执行中...")
# 模拟任务执行
for i in range(20):
time.sleep(2)
print(f"[{i+1}] 任务执行中...")
# 检查是否有网络异常
try:
watchdog.check_and_raise()
except NetworkException as e:
print(f"\n✗ 捕获到网络异常: {e}")
print(f" MAC: {e.mac_address}, IP: {e.ip_address}")
break
else:
print("\n✓ 任务执行完成,无网络异常")
finally:
watchdog.shutdown()