feat: 添加网络监控项目核心功能
This commit is contained in:
+51
@@ -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/
|
||||
@@ -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
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎提交问题和拉取请求!
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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()
|
||||
}
|
||||
+199
@@ -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请保存所有工作!"
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 "监控已停止"
|
||||
@@ -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 <IP> <延迟阈值> <Ping间隔>")
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print_welcome_message()
|
||||
|
||||
# 创建目录结构
|
||||
print("创建目录结构...")
|
||||
create_directories()
|
||||
|
||||
# 创建示例配置
|
||||
print()
|
||||
print("创建示例配置文件...")
|
||||
create_example_config()
|
||||
|
||||
print()
|
||||
print("[OK] 所有设置完成!")
|
||||
|
||||
print_completion_message()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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}(?<!-)$", re.IGNORECASE)
|
||||
return all(allowed.match(label) for label in hostname.split("."))
|
||||
|
||||
|
||||
def resolve_hostname(hostname: str) -> 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))
|
||||
Reference in New Issue
Block a user