2025-01-08 09:14:29 +08:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
2025-01-06 09:52:14 +08:00
|
|
|
|
import 'package:star_lock/talk/startChart/proto/rbcu.pb.dart';
|
|
|
|
|
|
|
|
|
|
|
|
class P2pManage {
|
2025-01-08 09:14:29 +08:00
|
|
|
|
// 常量定义
|
|
|
|
|
|
static const String testMessage = 'Hello'; // 测试消息
|
|
|
|
|
|
static const int localPort = 0; // 绑定本地端口(0 表示由系统分配)
|
|
|
|
|
|
static const Duration connectionTimeout = Duration(seconds: 5); // 连接超时时间
|
|
|
|
|
|
static const List<String> localNetworkPrefixes = [
|
|
|
|
|
|
'192.168.',
|
|
|
|
|
|
'10.',
|
|
|
|
|
|
'172.'
|
|
|
|
|
|
]; // 局域网 IP 前缀
|
2025-01-06 09:52:14 +08:00
|
|
|
|
|
2025-01-08 09:14:29 +08:00
|
|
|
|
RbcuInfo? communicationObjectRbcuInfo;
|
2025-01-06 09:52:14 +08:00
|
|
|
|
|
2025-01-08 09:14:29 +08:00
|
|
|
|
void init() {
|
|
|
|
|
|
// 初始化逻辑
|
2025-01-06 09:52:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析 address 属性,提取对方的 IP 和端口
|
|
|
|
|
|
List<Map<String, String>> parseRemoteAddresses() {
|
|
|
|
|
|
final addresses = communicationObjectRbcuInfo?.address ?? [];
|
|
|
|
|
|
return addresses.map((addr) {
|
|
|
|
|
|
final parts = addr.split(':');
|
|
|
|
|
|
return {'ip': parts[0], 'port': parts[1]};
|
|
|
|
|
|
}).toList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-08 09:14:29 +08:00
|
|
|
|
// 判断是否为局域网 IP
|
|
|
|
|
|
bool _isLocalNetworkIp(String ip) {
|
|
|
|
|
|
for (final prefix in localNetworkPrefixes) {
|
|
|
|
|
|
if (ip.startsWith(prefix)) {
|
|
|
|
|
|
// 处理 172.16.x.x 到 172.31.x.x
|
|
|
|
|
|
if (prefix == '172.') {
|
|
|
|
|
|
final secondOctet = int.tryParse(ip.split('.')[1]) ?? 0;
|
|
|
|
|
|
if (secondOctet >= 16 && secondOctet <= 31) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建 UDP 连接
|
|
|
|
|
|
Future<void> createUdpConnection() async {
|
|
|
|
|
|
final addresses = parseRemoteAddresses();
|
|
|
|
|
|
|
|
|
|
|
|
// 优先使用局域网 IP
|
|
|
|
|
|
addresses.sort((a, b) {
|
|
|
|
|
|
final isALocal = _isLocalNetworkIp(a['ip']!);
|
|
|
|
|
|
final isBLocal = _isLocalNetworkIp(b['ip']!);
|
|
|
|
|
|
if (isALocal && !isBLocal) return -1; // a 是局域网 IP,优先级更高
|
|
|
|
|
|
if (!isALocal && isBLocal) return 1; // b 是局域网 IP,优先级更高
|
|
|
|
|
|
return 0; // 优先级相同
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试连接
|
|
|
|
|
|
for (final addr in addresses) {
|
|
|
|
|
|
final ip = addr['ip']!;
|
|
|
|
|
|
final port = int.parse(addr['port']!);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
final socket = await RawDatagramSocket.bind(
|
|
|
|
|
|
InternetAddress.anyIPv4, localPort); // 绑定本地端口
|
|
|
|
|
|
|
|
|
|
|
|
// 发送测试数据
|
|
|
|
|
|
final testData = testMessage.codeUnits;
|
|
|
|
|
|
socket.send(testData, InternetAddress(ip), port);
|
|
|
|
|
|
|
|
|
|
|
|
// 设置超时时间
|
|
|
|
|
|
final completer = Completer<void>();
|
|
|
|
|
|
|
|
|
|
|
|
// 监听响应
|
|
|
|
|
|
socket.listen((event) {
|
|
|
|
|
|
if (event == RawSocketEvent.read) {
|
|
|
|
|
|
final datagram = socket.receive();
|
|
|
|
|
|
if (datagram != null) {
|
|
|
|
|
|
final response = String.fromCharCodes(datagram.data);
|
|
|
|
|
|
print('收到来自 $ip:$port 的响应: $response');
|
|
|
|
|
|
completer.complete(); // 收到响应,完成 Future
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 等待响应或超时
|
|
|
|
|
|
try {
|
|
|
|
|
|
await completer.future.timeout(connectionTimeout);
|
|
|
|
|
|
print('成功连接到 $ip:$port');
|
|
|
|
|
|
return; // 连接成功,退出循环
|
|
|
|
|
|
} on TimeoutException {
|
|
|
|
|
|
print('连接到 $ip:$port 超时');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
socket.close(); // 关闭 socket
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
print('连接到 $ip:$port 失败: $e');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print('无法连接到任何地址');
|
|
|
|
|
|
}
|
2025-01-06 09:52:14 +08:00
|
|
|
|
}
|