diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e429f42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# 虚拟环境 +venv/ +env/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# 日志文件 +logs/ +*.log + +# 配置文件(包含敏感信息) +# config.py + +# 操作系统 +.DS_Store +Thumbs.db + +# 项目特定 +.pytest_cache/ +.coverage +htmlcov/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8862d5c --- /dev/null +++ b/README.md @@ -0,0 +1,241 @@ +# 网络监控项目 + +一个功能完整的网络监控解决方案,持续监控指定IP地址的连接状态,当检测到连续无法连接超过设定阈值时自动执行关机操作。 + +## 功能特性 + +### 核心功能 +- ✅ 持续监控指定IP地址的网络连接状态 +- ✅ 可配置的延迟阈值和ping间隔 +- ✅ 支持Windows、Linux和macOS系统 +- ✅ 自动关机功能(网络断开后) +- ✅ 实时显示连接状态和日志 + +### 高级功能 +- 📝 详细的日志记录系统 +- 🔔 多种通知方式(控制台、桌面、邮件) +- 📊 会话统计和历史记录 +- 🛠️ 完整的工具函数库 +- 📦 模块化的项目结构 + +## 项目结构 + +``` +network-monitor/ +├── network_monitor.py # 核心监控器类 +├── advanced_monitor.py # 高级监控器(带日志和通知) +├── logger.py # 日志记录模块 +├── notifier.py # 通知模块 +├── utils.py # 工具函数模块 +├── config.py # 配置文件 +├── setup.py # 项目初始化脚本 +├── run_monitor.bat # Windows启动脚本 +├── run_monitor.sh # Linux/Mac启动脚本 +├── requirements.txt # Python依赖 +├── .gitignore # Git忽略文件 +└── README.md # 项目文档 +``` + +## 快速开始 + +### 1. 环境要求 +- Python 3.6 或更高版本 +- 无需额外安装依赖(仅使用标准库) +- 可选:安装桌面通知库(见 requirements.txt) + +### 2. 初始化项目 + +```bash +# 运行初始化脚本 +python setup.py +``` + +### 3. 运行监控器 + +#### Windows +```bash +# 使用启动脚本(推荐) +run_monitor.bat + +# 或直接运行 +python network_monitor.py +``` + +#### Linux/Mac +```bash +# 添加执行权限 +chmod +x run_monitor.sh + +# 使用启动脚本(推荐) +./run_monitor.sh + +# 或直接运行 +python3 network_monitor.py +``` + +### 4. 使用高级监控模式 + +```bash +# 基础模式 +python network_monitor.py + +# 高级模式(带日志和通知) +python advanced_monitor.py +``` + +## 使用方法 + +### 命令行参数 + +```bash +python network_monitor.py [IP地址] [延迟阈值] [Ping间隔] +``` + +**参数说明:** +- `IP地址`: 要监控的IP地址(默认: 8.8.8.8) +- `延迟阈值`: 连续断开多少秒后关机(默认: 30) +- `Ping间隔`: 每隔多少秒执行一次ping(默认: 5) + +**示例:** +```bash +# 使用默认配置 +python network_monitor.py + +# 监控内网网关,60秒后关机,每10秒ping一次 +python network_monitor.py 192.168.1.1 60 10 + +# 高级模式 +python advanced_monitor.py 192.168.1.1 45 5 +``` + +### 修改配置 + +编辑 `config.py` 文件: + +```python +# 目标IP地址 +TARGET_IP = "8.8.8.8" + +# 延迟阈值(秒) +DELAY_THRESHOLD = 30.0 + +# Ping检测间隔(秒) +PING_INTERVAL = 5.0 +``` + +## 输出示例 + +``` +[2026-03-05 10:30:00] 网络监控器已启动 +[2026-03-05 10:30:00] 目标IP: 8.8.8.8 +[2026-03-05 10:30:00] 延迟阈值: 30.0秒 +[2026-03-05 10:30:00] Ping间隔: 5.0秒 +[2026-03-05 10:30:00] 操作系统: Windows +------------------------------------------------------------ +[2026-03-05 10:30:00] 开始监控网络连接... +[2026-03-05 10:30:00] 每 5.0 秒执行一次ping操作 +------------------------------------------------------------ +[2026-03-05 10:30:00] Ping #1 执行完成 → ✓ 连接正常 +[2026-03-05 10:30:00] 等待 5.0 秒后执行下一次ping... +[2026-03-05 10:30:05] Ping #2 执行完成 → ✓ 连接正常 +``` + +## 模块说明 + +### network_monitor.py +核心监控器类,提供基本的网络监控功能。 +- `NetworkMonitor`: 主监控器类 +- `ping_host()`: 执行ping操作 +- `monitor()`: 启动监控循环 +- `shutdown_system()`: 执行系统关机 + +### advanced_monitor.py +高级监控器,集成日志和通知功能。 +- `AdvancedNetworkMonitor`: 继承自NetworkMonitor +- 自动记录所有ping操作 +- 发送连接状态通知 +- 生成详细的统计报告 + +### logger.py +日志记录模块,提供完整的日志功能。 +- `Logger`: 日志记录器类 +- 支持多种事件类型记录 +- 自动保存历史日志 +- 生成统计报告 + +### notifier.py +通知模块,支持多种通知方式。 +- `NotificationManager`: 通知管理器 +- `ConsoleNotifier`: 控制台通知 +- `DesktopNotifier`: 桌面通知(需安装依赖) +- `EmailNotifier`: 邮件通知(需配置SMTP) + +### utils.py +工具函数模块,提供通用工具函数。 +- IP地址验证 +- 主机名解析 +- 端口检测 +- 数据格式化 + +## 注意事项 + +1. **谨慎使用**: 此脚本会在网络断开后执行自动关机,建议先在测试环境验证。 +2. **管理员权限**: Windows上需要管理员权限执行关机命令。 +3. **停止监控**: 按 `Ctrl+C` 可以安全停止监控程序。 +4. **目标IP选择**: 建议使用可靠的公网IP(如8.8.8.8)或内网网关。 +5. **日志目录**: 日志文件保存在 `logs/` 目录下,会自动清理旧日志。 + +## 扩展功能 + +### 启用桌面通知 + +```bash +# Windows +pip install win10toast + +# Linux +pip install notify2 + +# macOS +pip install pync +``` + +然后在代码中设置 `enable_desktop=True`。 + +### 配置邮件通知 + +```python +from notifier import EmailNotifier + +email_notifier = EmailNotifier( + smtp_server="smtp.example.com", + smtp_port=587, + username="your@email.com", + password="your_password", + from_email="from@email.com", + to_email="to@email.com" +) +``` + +## 故障排除 + +### 问题: 无法执行关机命令 +- Windows: 以管理员身份运行 +- Linux/Mac: 检查用户权限 + +### 问题: ping失败 +- 检查IP地址是否正确 +- 检查网络连接 +- 检查防火墙设置 + +### 问题: 依赖安装失败 +- 使用 `pip install -r requirements.txt` +- 确保使用Python 3.6+ + +## 许可证 + +MIT License + +## 贡献 + +欢迎提交问题和拉取请求! diff --git a/advanced_monitor.py b/advanced_monitor.py new file mode 100644 index 0000000..695f7d9 --- /dev/null +++ b/advanced_monitor.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +高级网络监控器 +集成日志记录和通知功能 +""" + +import sys +import time +from datetime import datetime +from typing import Optional + +from network_monitor import NetworkMonitor +from logger import Logger +from notifier import NotificationManager, ConsoleNotifier, DesktopNotifier + + +class AdvancedNetworkMonitor(NetworkMonitor): + """高级网络监控器,继承自基础监控器""" + + def __init__(self, target_ip: str, delay_threshold: float = 30.0, + ping_interval: float = 5.0, enable_logging: bool = True, + enable_notifications: bool = True): + """ + 初始化高级网络监控器 + + Args: + target_ip: 要监控的IP地址 + delay_threshold: 延迟阈值(秒) + ping_interval: ping检测间隔(秒) + enable_logging: 是否启用日志记录 + enable_notifications: 是否启用通知 + """ + super().__init__(target_ip, delay_threshold, ping_interval) + + # 初始化日志记录器 + self.enable_logging = enable_logging + if self.enable_logging: + self.logger = Logger() + print(f"[{self._get_timestamp()}] 日志记录已启用") + + # 初始化通知管理器 + self.enable_notifications = enable_notifications + if self.enable_notifications: + self.notification_manager = NotificationManager( + enable_console=True, + enable_desktop=False # 可设置为True启用桌面通知 + ) + print(f"[{self._get_timestamp()}] 通知功能已启用") + + print("-" * 60) + + def ping_host(self) -> bool: + """执行ping操作并记录日志""" + start_time = time.time() + is_connected = super().ping_host() + latency = (time.time() - start_time) * 1000 # 转换为毫秒 + + if self.enable_logging: + self.logger.log_ping(is_connected, latency) + + return is_connected + + def shutdown_system(self): + """执行系统关机操作并发送通知""" + print(f"\n[{self._get_timestamp()}] !!! 连续{self.delay_threshold}秒无法连接,准备关机 !!!") + + if self.enable_logging: + self.logger.log_shutdown( + f"连续{self.delay_threshold}秒无法连接到 {self.target_ip}" + ) + + if self.enable_notifications: + self.notification_manager.notify_shutdown( + f"连续{self.delay_threshold}秒无法连接到 {self.target_ip}" + ) + + # 保存日志 + if self.enable_logging: + log_file = self.logger.save_session() + print(f"[{self._get_timestamp()}] 日志已保存到: {log_file}") + + # 执行关机 + super().shutdown_system() + + def monitor(self): + """启动网络监控""" + print(f"[{self._get_timestamp()}] 开始高级监控...") + print(f"[{self._get_timestamp()}] 每 {self.ping_interval} 秒执行一次ping操作") + print("-" * 60) + + consecutive_failures = 0 + last_status = None + + try: + while self.is_running: + # 执行ping操作 + is_connected = self.ping_host() + + # 显示ping结果 + status_str = " → ✓ 连接正常" if is_connected else " → ✗ 连接失败" + print(status_str) + + # 状态变化时额外输出日志和通知 + if last_status != is_connected: + if not is_connected: + print(f"[{self._get_timestamp()}] 状态变化: 检测到连接失败") + if self.enable_logging: + self.logger.log_status_change("disconnected") + else: + print(f"[{self._get_timestamp()}] 状态变化: 连接已恢复") + if self.enable_logging: + self.logger.log_status_change("connected") + last_status = is_connected + + if is_connected: + # 连接成功,重置失败计数 + consecutive_failures = 0 + self.failure_start_time = None + else: + # 连接失败 + consecutive_failures += 1 + + if self.failure_start_time is None: + # 第一次失败,记录开始时间 + self.failure_start_time = time.time() + print(f"[{self._get_timestamp()}] 开始记录连接失败时间") + else: + # 计算失败持续时间 + failure_duration = time.time() - self.failure_start_time + remaining_time = self.delay_threshold - failure_duration + + if remaining_time > 0: + print(f"[{self._get_timestamp()}] 连续失败: {consecutive_failures}次, " + f"已持续: {failure_duration:.1f}秒, " + f"剩余: {remaining_time:.1f}秒") + + # 每隔一定时间发送通知 + if int(failure_duration) % 10 == 0 and failure_duration > 0: + if self.enable_notifications: + self.notification_manager.notify_connection_lost( + self.target_ip, failure_duration + ) + + if failure_duration >= self.delay_threshold: + # 超过阈值,执行关机 + self.shutdown_system() + self.is_running = False + break + + # 按照设定的间隔等待下一次ping操作 + print(f"[{self._get_timestamp()}] 等待 {self.ping_interval} 秒后执行下一次ping...") + time.sleep(self.ping_interval) + + except KeyboardInterrupt: + print(f"\n[{self._get_timestamp()}] 用户中断,监控已停止") + print(f"[{self._get_timestamp()}] 总共执行了 {self.ping_count} 次ping操作") + + # 显示统计信息 + if self.enable_logging: + stats = self.logger.get_statistics() + print(f"[{self._get_timestamp()}] 统计信息:") + print(f" - 总ping次数: {stats['total_pings']}") + print(f" - 成功次数: {stats['successful_pings']}") + print(f" - 失败次数: {stats['failed_pings']}") + print(f" - 成功率: {stats['success_rate']}") + print(f" - 运行时长: {stats['session_duration']:.1f}秒") + + # 保存日志 + log_file = self.logger.save_session() + print(f"[{self._get_timestamp()}] 日志已保存到: {log_file}") + + except Exception as e: + print(f"\n[{self._get_timestamp()}] 监控过程中发生错误: {e}") + print(f"[{self._get_timestamp()}] 总共执行了 {self.ping_count} 次ping操作") + + +def main(): + """主函数""" + # 可配置参数 + CONFIG = { + "target_ip": "8.8.8.8", # 默认使用Google DNS + "delay_threshold": 30.0, # 延迟阈值(秒) + "ping_interval": 5.0, # Ping检测间隔(秒) + "enable_logging": True, # 启用日志记录 + "enable_notifications": True # 启用通知 + } + + # 可以通过命令行参数覆盖配置 + if len(sys.argv) > 1: + CONFIG["target_ip"] = sys.argv[1] + if len(sys.argv) > 2: + CONFIG["delay_threshold"] = float(sys.argv[2]) + if len(sys.argv) > 3: + CONFIG["ping_interval"] = float(sys.argv[3]) + + # 创建并启动监控器 + monitor = AdvancedNetworkMonitor( + target_ip=CONFIG["target_ip"], + delay_threshold=CONFIG["delay_threshold"], + ping_interval=CONFIG["ping_interval"], + enable_logging=CONFIG["enable_logging"], + enable_notifications=CONFIG["enable_notifications"] + ) + + monitor.monitor() + + +if __name__ == "__main__": + main() diff --git a/config/config_example.py b/config/config_example.py new file mode 100644 index 0000000..7db8265 --- /dev/null +++ b/config/config_example.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +网络监控配置文件示例 +在此处修改监控参数 +""" + +# 目标IP地址(支持IPv4和IPv6) +TARGET_IP = "8.8.8.8" + +# 延迟阈值(秒) +DELAY_THRESHOLD = 30.0 + +# Ping检测间隔(秒) +PING_INTERVAL = 5.0 + +# 可选参数(保留用于扩展) +MAX_RETRIES = 3 diff --git a/logger.py b/logger.py new file mode 100644 index 0000000..dd2ce8b --- /dev/null +++ b/logger.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +日志记录器模块 +负责记录网络监控的历史数据和异常事件 +""" + +import os +import json +from datetime import datetime +from typing import List, Dict, Any +from pathlib import Path + + +class Logger: + """日志记录器类""" + + def __init__(self, log_dir: str = "logs", max_log_files: int = 10): + """ + 初始化日志记录器 + + Args: + log_dir: 日志文件存储目录 + max_log_files: 最大保留的日志文件数量 + """ + self.log_dir = Path(log_dir) + self.max_log_files = max_log_files + self.current_session_data: List[Dict[str, Any]] = [] + self.session_start_time = datetime.now() + + # 创建日志目录 + self.log_dir.mkdir(parents=True, exist_ok=True) + + # 清理旧日志文件 + self._cleanup_old_logs() + + def _get_log_filename(self) -> str: + """生成日志文件名""" + timestamp = self.session_start_time.strftime("%Y%m%d_%H%M%S") + return f"network_monitor_{timestamp}.log" + + def _cleanup_old_logs(self): + """清理旧的日志文件,保留最近的max_log_files个""" + log_files = sorted( + self.log_dir.glob("network_monitor_*.log"), + key=lambda x: x.stat().st_mtime, + reverse=True + ) + + # 删除超出数量限制的旧日志文件 + for old_log in log_files[self.max_log_files:]: + old_log.unlink() + + def log_event(self, event_type: str, message: str, **kwargs): + """ + 记录事件 + + Args: + event_type: 事件类型(ping, status_change, error等) + message: 事件描述 + **kwargs: 额外的键值对数据 + """ + event = { + "timestamp": datetime.now().isoformat(), + "type": event_type, + "message": message, + **kwargs + } + self.current_session_data.append(event) + + def log_ping(self, success: bool, latency: float = 0.0): + """ + 记录ping结果 + + Args: + success: ping是否成功 + latency: 延迟时间(毫秒) + """ + self.log_event( + "ping", + "Ping操作完成" if success else "Ping操作失败", + success=success, + latency_ms=latency + ) + + def log_status_change(self, status: str, duration: float = None): + """ + 记录状态变化 + + Args: + status: 状态(connected, disconnected) + duration: 持续时间(秒) + """ + message = f"网络状态变化: {status}" + if duration is not None: + message += f" (持续{duration:.1f}秒)" + + self.log_event( + "status_change", + message, + status=status, + duration_seconds=duration + ) + + def log_error(self, error_type: str, error_message: str): + """ + 记录错误 + + Args: + error_type: 错误类型 + error_message: 错误信息 + """ + self.log_event( + "error", + f"{error_type}: {error_message}", + error_type=error_type + ) + + def log_shutdown(self, reason: str): + """ + 记录关机事件 + + Args: + reason: 关机原因 + """ + self.log_event( + "shutdown", + f"系统关机: {reason}", + reason=reason + ) + + def save_session(self): + """保存当前会话的日志到文件""" + log_file = self.log_dir / self._get_log_filename() + + session_summary = { + "session_start": self.session_start_time.isoformat(), + "session_end": datetime.now().isoformat(), + "total_events": len(self.current_session_data), + "events": self.current_session_data + } + + with open(log_file, 'w', encoding='utf-8') as f: + json.dump(session_summary, f, ensure_ascii=False, indent=2) + + return log_file + + def get_statistics(self) -> Dict[str, Any]: + """ + 获取当前会话的统计信息 + + Returns: + 统计数据字典 + """ + total_pings = sum(1 for event in self.current_session_data if event["type"] == "ping") + successful_pings = sum( + 1 for event in self.current_session_data + if event["type"] == "ping" and event["success"] + ) + + return { + "total_pings": total_pings, + "successful_pings": successful_pings, + "failed_pings": total_pings - successful_pings, + "success_rate": f"{(successful_pings / total_pings * 100):.2f}%" if total_pings > 0 else "0%", + "session_duration": (datetime.now() - self.session_start_time).total_seconds() + } diff --git a/notifier.py b/notifier.py new file mode 100644 index 0000000..952bfde --- /dev/null +++ b/notifier.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +通知模块 +负责在重要事件发生时发送通知 +""" + +import sys +import platform +from typing import Optional +from abc import ABC, abstractmethod + + +class Notifier(ABC): + """通知器抽象基类""" + + @abstractmethod + def send(self, title: str, message: str): + """ + 发送通知 + + Args: + title: 通知标题 + message: 通知内容 + """ + pass + + +class ConsoleNotifier(Notifier): + """控制台通知器""" + + def send(self, title: str, message: str): + """在控制台显示通知""" + separator = "=" * 60 + print(f"\n{separator}") + print(f"【{title}】") + print(f"{message}") + print(f"{separator}\n") + + +class DesktopNotifier(Notifier): + """桌面通知器""" + + def __init__(self): + """初始化桌面通知器""" + self.os_type = platform.system().lower() + self.enabled = True + + # 尝试导入通知库 + if self.os_type == "windows": + try: + import win10toast + self.toaster = win10toast.ToastNotifier() + except ImportError: + self.enabled = False + elif self.os_type == "linux": + try: + import notify2 + notify2.init("网络监控器") + except ImportError: + self.enabled = False + elif self.os_type == "darwin": + try: + import pync + except ImportError: + self.enabled = False + + def send(self, title: str, message: str): + """发送桌面通知""" + if not self.enabled: + return + + try: + if self.os_type == "windows": + self.toaster.show_notification( + title, + message, + duration=10 + ) + elif self.os_type == "linux": + import notify2 + notification = notify2.Notification(title, message) + notification.show() + elif self.os_type == "darwin": + import pync + pync.notify(message, title=title) + except Exception as e: + print(f"发送桌面通知失败: {e}") + + +class EmailNotifier(Notifier): + """邮件通知器(示例,需要配置SMTP)""" + + def __init__(self, smtp_server: str = None, smtp_port: int = None, + username: str = None, password: str = None, + from_email: str = None, to_email: str = None): + """ + 初始化邮件通知器 + + Args: + smtp_server: SMTP服务器地址 + smtp_port: SMTP端口 + username: 用户名 + password: 密码 + from_email: 发件人邮箱 + to_email: 收件人邮箱 + """ + self.smtp_server = smtp_server + self.smtp_port = smtp_port + self.username = username + self.password = password + self.from_email = from_email + self.to_email = to_email + self.enabled = all([smtp_server, smtp_port, username, password, from_email, to_email]) + + def send(self, title: str, message: str): + """发送邮件通知""" + if not self.enabled: + print("邮件通知未配置,跳过发送") + return + + try: + import smtplib + from email.mime.text import MIMEText + from email.mime.multipart import MIMEMultipart + + # 创建邮件 + msg = MIMEMultipart() + msg['From'] = self.from_email + msg['To'] = self.to_email + msg['Subject'] = title + + # 添加邮件正文 + msg.attach(MIMEText(message, 'plain', 'utf-8')) + + # 发送邮件 + with smtplib.SMTP(self.smtp_server, self.smtp_port) as server: + server.starttls() + server.login(self.username, self.password) + server.send_message(msg) + + print(f"邮件通知已发送至 {self.to_email}") + + except Exception as e: + print(f"发送邮件通知失败: {e}") + + +class NotificationManager: + """通知管理器""" + + def __init__(self, enable_console: bool = True, enable_desktop: bool = False): + """ + 初始化通知管理器 + + Args: + enable_console: 是否启用控制台通知 + enable_desktop: 是否启用桌面通知 + """ + self.notifiers: list[Notifier] = [] + + if enable_console: + self.notifiers.append(ConsoleNotifier()) + + if enable_desktop: + self.notifiers.append(DesktopNotifier()) + + def add_notifier(self, notifier: Notifier): + """ + 添加通知器 + + Args: + notifier: 通知器实例 + """ + self.notifiers.append(notifier) + + def notify(self, title: str, message: str): + """ + 发送通知到所有通知器 + + Args: + title: 通知标题 + message: 通知内容 + """ + for notifier in self.notifiers: + notifier.send(title, message) + + def notify_connection_lost(self, ip: str, duration: float): + """通知连接丢失""" + self.notify( + "网络连接丢失", + f"无法连接到 {ip}\n已断开 {duration:.1f} 秒" + ) + + def notify_shutdown(self, reason: str): + """通知系统即将关机""" + self.notify( + "系统即将关机", + f"原因: {reason}\n请保存所有工作!" + ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b351897 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +# 网络监控项目依赖 +# Python 3.6+ 仅使用标准库即可运行核心功能 + +# 可选依赖(用于桌面通知) +# Windows: pip install win10toast +win10toast==0.9 + +# Linux: pip install notify2 +notify2==0.3.1 + +# macOS: pip install pync +pync==2.0.0 diff --git a/run_monitor.bat b/run_monitor.bat new file mode 100644 index 0000000..05e15b7 --- /dev/null +++ b/run_monitor.bat @@ -0,0 +1,69 @@ +@echo off +REM Windows批处理脚本 - 启动网络监控器 + +echo ======================================== +echo 网络监控器启动脚本 +echo ======================================== +echo. + +REM 检查Python是否安装 +python --version >nul 2>&1 +if errorlevel 1 ( + echo 错误: 未检测到Python,请先安装Python 3.6或更高版本 + pause + exit /b 1 +) + +echo Python版本: +python --version +echo. + +REM 检查是否有管理员权限(Windows关机需要) +net session >nul 2>&1 +if errorlevel 1 ( + echo 警告: 建议以管理员身份运行此脚本以确保关机功能正常工作 + echo. +) + +REM 选择运行模式 +echo 请选择运行模式: +echo 1. 基础监控模式 (network_monitor.py) +echo 2. 高级监控模式 (advanced_monitor.py) - 带日志和通知 +echo 3. 使用自定义参数 +echo. + +set /p choice="请输入选项 (1/2/3): " + +if "%choice%"=="1" ( + echo. + echo 启动基础监控模式... + echo. + python network_monitor.py +) else if "%choice%"=="2" ( + echo. + echo 启动高级监控模式... + echo. + python advanced_monitor.py +) else if "%choice%"=="3" ( + echo. + set /p target_ip="请输入目标IP地址 (默认: 8.8.8.8): " + if "%target_ip%"=="" set target_ip=8.8.8.8 + + set /p delay="请输入延迟阈值秒数 (默认: 30): " + if "%delay%"=="" set delay=30 + + set /p interval="请输入Ping间隔秒数 (默认: 5): " + if "%interval%"=="" set interval=5 + + echo. + echo 启动监控器: IP=%target_ip%, 延迟=%delay秒, 间隔=%interval秒 + echo. + python network_monitor.py %target_ip% %delay% %interval% +) else ( + echo 无效选项,使用默认启动... + python network_monitor.py +) + +echo. +echo 监控已停止 +pause diff --git a/run_monitor.sh b/run_monitor.sh new file mode 100644 index 0000000..60e8c38 --- /dev/null +++ b/run_monitor.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Linux/macOS Shell脚本 - 启动网络监控器 + +echo "========================================" +echo "网络监控器启动脚本" +echo "========================================" +echo "" + +# 检查Python是否安装 +if ! command -v python3 &> /dev/null; then + echo "错误: 未检测到Python3,请先安装Python 3.6或更高版本" + exit 1 +fi + +echo "Python版本:" +python3 --version +echo "" + +# 选择运行模式 +echo "请选择运行模式:" +echo "1. 基础监控模式 (network_monitor.py)" +echo "2. 高级监控模式 (advanced_monitor.py) - 带日志和通知" +echo "3. 使用自定义参数" +echo "" + +read -p "请输入选项 (1/2/3): " choice + +case $choice in + 1) + echo "" + echo "启动基础监控模式..." + echo "" + python3 network_monitor.py + ;; + 2) + echo "" + echo "启动高级监控模式..." + echo "" + python3 advanced_monitor.py + ;; + 3) + echo "" + read -p "请输入目标IP地址 (默认: 8.8.8.8): " target_ip + target_ip=${target_ip:-8.8.8.8} + + read -p "请输入延迟阈值秒数 (默认: 30): " delay + delay=${delay:-30} + + read -p "请输入Ping间隔秒数 (默认: 5): " interval + interval=${interval:-5} + + echo "" + echo "启动监控器: IP=$target_ip, 延迟=$delay秒, 间隔=$interval秒" + echo "" + python3 network_monitor.py "$target_ip" "$delay" "$interval" + ;; + *) + echo "无效选项,使用默认启动..." + python3 network_monitor.py + ;; +esac + +echo "" +echo "监控已停止" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..e900cfb --- /dev/null +++ b/setup.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +项目设置脚本 +用于初始化和配置项目 +""" + +import os +import sys + + +def create_directories(): + """创建必要的目录结构""" + directories = [ + "logs", + "logs/backup", + "config", + ] + + for directory in directories: + os.makedirs(directory, exist_ok=True) + print(f"[OK] 创建目录: {directory}") + + +def create_example_config(): + """创建示例配置文件""" + example_config = """#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +\"\"\" +网络监控配置文件示例 +在此处修改监控参数 +\"\"\" + +# 目标IP地址(支持IPv4和IPv6) +TARGET_IP = "8.8.8.8" + +# 延迟阈值(秒) +DELAY_THRESHOLD = 30.0 + +# Ping检测间隔(秒) +PING_INTERVAL = 5.0 + +# 可选参数(保留用于扩展) +MAX_RETRIES = 3 +""" + + config_file = "config/config_example.py" + with open(config_file, 'w', encoding='utf-8') as f: + f.write(example_config) + + print(f"[OK] 创建示例配置: {config_file}") + + +def print_welcome_message(): + """打印欢迎信息""" + print("=" * 60) + print("网络监控项目 - 初始化设置") + print("=" * 60) + print() + + +def print_completion_message(): + """打印完成信息""" + print() + print("=" * 60) + print("项目初始化完成!") + print("=" * 60) + print() + print("快速开始:") + print(" Windows: run_monitor.bat") + print(" Linux/Mac: chmod +x run_monitor.sh && ./run_monitor.sh") + print() + print("或直接运行:") + print(" 基础模式: python network_monitor.py") + print(" 高级模式: python advanced_monitor.py") + print() + print("命令行参数:") + print(" python network_monitor.py <延迟阈值> ") + print() + + +def main(): + """主函数""" + print_welcome_message() + + # 创建目录结构 + print("创建目录结构...") + create_directories() + + # 创建示例配置 + print() + print("创建示例配置文件...") + create_example_config() + + print() + print("[OK] 所有设置完成!") + + print_completion_message() + + +if __name__ == "__main__": + main() diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..3f8abc9 --- /dev/null +++ b/utils.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +工具函数模块 +提供项目所需的通用工具函数 +""" + +import socket +import re +from typing import Optional + + +def validate_ip_address(ip: str) -> bool: + """ + 验证IP地址格式是否正确 + + Args: + ip: IP地址字符串 + + Returns: + bool: 如果IP地址格式正确返回True,否则返回False + """ + # IPv4正则表达式 + ipv4_pattern = r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$' + + # IPv6正则表达式(简化版) + ipv6_pattern = r'^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::$|^:(?::)+(?:[0-9a-fA-F]{1,4})?$' + + return bool(re.match(ipv4_pattern, ip) or re.match(ipv6_pattern, ip)) + + +def validate_hostname(hostname: str) -> bool: + """ + 验证主机名格式是否正确 + + Args: + hostname: 主机名字符串 + + Returns: + bool: 如果主机名格式正确返回True,否则返回False + """ + if len(hostname) > 253: + return False + + if hostname[-1] == ".": + hostname = hostname[:-1] + + allowed = re.compile(r"^(?!-)[A-Z0-9-]{1,63}(? Optional[str]: + """ + 解析主机名为IP地址 + + Args: + hostname: 主机名 + + Returns: + IP地址字符串,解析失败返回None + """ + try: + ip_address = socket.gethostbyname(hostname) + return ip_address + except socket.gaierror: + return None + + +def is_port_open(host: str, port: int, timeout: float = 2.0) -> bool: + """ + 检查指定主机的端口是否开放 + + Args: + host: 主机地址 + port: 端口号 + timeout: 超时时间(秒) + + Returns: + bool: 端口开放返回True,否则返回False + """ + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + sock.close() + return result == 0 + except Exception: + return False + + +def format_bytes(bytes_size: int) -> str: + """ + 格式化字节大小为可读字符串 + + Args: + bytes_size: 字节数 + + Returns: + 格式化后的字符串 + """ + for unit in ['B', 'KB', 'MB', 'GB', 'TB']: + if bytes_size < 1024.0: + return f"{bytes_size:.2f} {unit}" + bytes_size /= 1024.0 + return f"{bytes_size:.2f} PB" + + +def format_duration(seconds: float) -> str: + """ + 格式化时长为可读字符串 + + Args: + seconds: 秒数 + + Returns: + 格式化后的字符串 + """ + if seconds < 60: + return f"{seconds:.1f}秒" + elif seconds < 3600: + minutes = seconds / 60 + return f"{minutes:.1f}分钟" + elif seconds < 86400: + hours = seconds / 3600 + return f"{hours:.1f}小时" + else: + days = seconds / 86400 + return f"{days:.1f}天" + + +def safe_divide(numerator: float, denominator: float, default: float = 0.0) -> float: + """ + 安全除法,避免除以零 + + Args: + numerator: 分子 + denominator: 分母 + default: 除零时的默认返回值 + + Returns: + 除法结果或默认值 + """ + try: + return numerator / denominator if denominator != 0 else default + except Exception: + return default + + +def clamp(value: float, min_value: float, max_value: float) -> float: + """ + 将数值限制在指定范围内 + + Args: + value: 输入值 + min_value: 最小值 + max_value: 最大值 + + Returns: + 限制后的值 + """ + return max(min_value, min(value, max_value))