feat(app): 初始化家庭网络监控Flutter应用基本结构
- 添加Flutter项目基础文件与配置,包括.gitignore和analysis_options.yaml - 配置Android相关文件及Gradle构建脚本支持 - 新增设备状态与网络状态数据模型及相关枚举 - 实现网络检测及网速测试服务 - 创建监控状态管理Provider,实现设备状态管理和自动刷新机制 - 编写主界面HomeScreen,包括设备列表、网速仪表盘及基础交互 - 添加资源文件支持应用图标和启动画面 - 配置项目元数据文件,支持Flutter迁移及版本控制 - 新增项目README,提供入门指引和相关资源链接
This commit is contained in:
119
home_monitor/lib/services/network_service.dart
Normal file
119
home_monitor/lib/services/network_service.dart
Normal file
@@ -0,0 +1,119 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import '../models/models.dart';
|
||||
|
||||
/// 网络检测服务
|
||||
class NetworkService {
|
||||
static final NetworkService _instance = NetworkService._internal();
|
||||
factory NetworkService() => _instance;
|
||||
NetworkService._internal();
|
||||
|
||||
/// Ping指定主机
|
||||
Future<int?> ping(String host, {int timeout = 5000}) async {
|
||||
try {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
// 尝试建立TCP连接来检测
|
||||
final socket = await Socket.connect(
|
||||
host,
|
||||
80,
|
||||
timeout: Duration(milliseconds: timeout),
|
||||
);
|
||||
|
||||
stopwatch.stop();
|
||||
socket.destroy();
|
||||
|
||||
return stopwatch.elapsedMilliseconds;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 检测设备是否在线
|
||||
Future<DeviceStatus> checkDevice(DeviceStatus device) async {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
try {
|
||||
final socket = await Socket.connect(
|
||||
device.ip,
|
||||
device.port,
|
||||
timeout: const Duration(seconds: 5),
|
||||
);
|
||||
|
||||
stopwatch.stop();
|
||||
socket.destroy();
|
||||
|
||||
return device.copyWith(
|
||||
state: DeviceState.online,
|
||||
latency: stopwatch.elapsedMilliseconds,
|
||||
lastCheck: DateTime.now(),
|
||||
errorMessage: null,
|
||||
);
|
||||
} on SocketException catch (e) {
|
||||
return device.copyWith(
|
||||
state: DeviceState.offline,
|
||||
latency: null,
|
||||
lastCheck: DateTime.now(),
|
||||
errorMessage: e.message,
|
||||
);
|
||||
} catch (e) {
|
||||
return device.copyWith(
|
||||
state: DeviceState.unknown,
|
||||
latency: null,
|
||||
lastCheck: DateTime.now(),
|
||||
errorMessage: e.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 批量检测设备
|
||||
Future<List<DeviceStatus>> checkAllDevices(List<DeviceStatus> devices) async {
|
||||
final results = await Future.wait(
|
||||
devices.map((device) => checkDevice(device)),
|
||||
);
|
||||
return results;
|
||||
}
|
||||
|
||||
/// 检测网络连通性(通过多个公共DNS)
|
||||
Future<bool> checkInternetConnection() async {
|
||||
final hosts = [
|
||||
'8.8.8.8', // Google DNS
|
||||
'114.114.114.114', // 114 DNS
|
||||
'223.5.5.5', // 阿里 DNS
|
||||
];
|
||||
|
||||
for (final host in hosts) {
|
||||
final latency = await ping(host);
|
||||
if (latency != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 获取本地IP地址
|
||||
Future<String> getLocalIp() async {
|
||||
try {
|
||||
final interfaces = await NetworkInterface.list(
|
||||
type: InternetAddressType.IPv4,
|
||||
);
|
||||
|
||||
for (final interface in interfaces) {
|
||||
for (final addr in interface.addresses) {
|
||||
if (!addr.isLoopback) {
|
||||
return addr.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略错误
|
||||
}
|
||||
return '未知';
|
||||
}
|
||||
|
||||
/// 测量到指定主机的延迟
|
||||
Future<int> measureLatency(String host) async {
|
||||
final latency = await ping(host);
|
||||
return latency ?? -1;
|
||||
}
|
||||
}
|
||||
3
home_monitor/lib/services/services.dart
Normal file
3
home_monitor/lib/services/services.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
// 服务层导出文件
|
||||
export 'network_service.dart';
|
||||
export 'speed_test_service.dart';
|
||||
128
home_monitor/lib/services/speed_test_service.dart
Normal file
128
home_monitor/lib/services/speed_test_service.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
import 'dart:async';
|
||||
import 'package:dio/dio.dart';
|
||||
import '../models/models.dart';
|
||||
import 'network_service.dart';
|
||||
|
||||
/// 网速测试服务
|
||||
class SpeedTestService {
|
||||
static final SpeedTestService _instance = SpeedTestService._internal();
|
||||
factory SpeedTestService() => _instance;
|
||||
SpeedTestService._internal();
|
||||
|
||||
final Dio _dio = Dio();
|
||||
|
||||
// 测试文件URL(可配置)
|
||||
static const _testUrls = [
|
||||
'https://speed.cloudflare.com/__down?bytes=10000000', // 10MB
|
||||
'https://speed.hetzner.de/100MB.bin',
|
||||
];
|
||||
|
||||
/// 测试下载速度
|
||||
Future<double> testDownloadSpeed({int testDurationSeconds = 5}) async {
|
||||
double totalBytes = 0;
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
try {
|
||||
final response = await _dio.get<List<int>>(
|
||||
_testUrls[0],
|
||||
options: Options(
|
||||
responseType: ResponseType.bytes,
|
||||
receiveTimeout: Duration(seconds: testDurationSeconds + 2),
|
||||
),
|
||||
onReceiveProgress: (received, total) {
|
||||
totalBytes = received.toDouble();
|
||||
},
|
||||
);
|
||||
|
||||
stopwatch.stop();
|
||||
|
||||
// 计算速度 (Mbps)
|
||||
final seconds = stopwatch.elapsedMilliseconds / 1000;
|
||||
final mbps = (totalBytes * 8) / (seconds * 1000000);
|
||||
|
||||
return mbps;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 测试上传速度(简化版,通过POST测试)
|
||||
Future<double> testUploadSpeed({int testDurationSeconds = 5}) async {
|
||||
// 生成测试数据 (1MB)
|
||||
final testData = List.generate(1024 * 1024, (i) => i % 256);
|
||||
final stopwatch = Stopwatch()..start();
|
||||
|
||||
try {
|
||||
await _dio.post(
|
||||
'https://speed.cloudflare.com/__up',
|
||||
data: testData,
|
||||
options: Options(
|
||||
sendTimeout: Duration(seconds: testDurationSeconds + 2),
|
||||
),
|
||||
);
|
||||
|
||||
stopwatch.stop();
|
||||
|
||||
final seconds = stopwatch.elapsedMilliseconds / 1000;
|
||||
final mbps = (testData.length * 8) / (seconds * 1000000);
|
||||
|
||||
return mbps;
|
||||
} catch (e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 完整网速测试
|
||||
Future<NetworkStatus> runFullTest() async {
|
||||
final networkService = NetworkService();
|
||||
|
||||
// 检测连接
|
||||
final isConnected = await networkService.checkInternetConnection();
|
||||
if (!isConnected) {
|
||||
return NetworkStatus(
|
||||
isConnected: false,
|
||||
lastCheck: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
// 获取本地IP
|
||||
final localIp = await networkService.getLocalIp();
|
||||
|
||||
// 测量延迟
|
||||
final latency = await networkService.measureLatency('8.8.8.8');
|
||||
|
||||
// 测试下载速度
|
||||
final downloadSpeed = await testDownloadSpeed();
|
||||
|
||||
// 测试上传速度
|
||||
final uploadSpeed = await testUploadSpeed();
|
||||
|
||||
return NetworkStatus(
|
||||
isConnected: true,
|
||||
downloadSpeed: downloadSpeed,
|
||||
uploadSpeed: uploadSpeed,
|
||||
latency: latency,
|
||||
localIp: localIp,
|
||||
lastCheck: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
/// 快速网络检测(仅检测连通性和延迟)
|
||||
Future<NetworkStatus> quickCheck() async {
|
||||
final networkService = NetworkService();
|
||||
|
||||
final isConnected = await networkService.checkInternetConnection();
|
||||
final localIp = await networkService.getLocalIp();
|
||||
final latency = isConnected
|
||||
? await networkService.measureLatency('8.8.8.8')
|
||||
: -1;
|
||||
|
||||
return NetworkStatus(
|
||||
isConnected: isConnected,
|
||||
latency: latency,
|
||||
localIp: localIp,
|
||||
lastCheck: DateTime.now(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user