import 'dart:collection'; class PacketLossStatistics { static final PacketLossStatistics _instance = PacketLossStatistics._internal(); factory PacketLossStatistics() => _instance; PacketLossStatistics._internal(); // 记录每个messageId的分包信息 // key: messageId, value: {totalPackets, receivedPackets} final Map _packetsMap = HashMap(); // 配置参数 int _maxCapacity = 300; // 最大容量为300条记录 int _timeoutMs = 30000; // 默认超时时间为30秒 // 统计信息 int _totalMessages = 0; // 总消息数 int _lostMessages = 0; // 丢包的消息数 int _totalPackets = 0; // 总分包数 int _lostPackets = 0; // 丢失的分包数 // 记录分包数据 void recordPacket(int messageId, int currentIndex, int totalPackets) { // 定期清理超时记录 _cleanupExpiredPackets(); // 检查容量限制 _checkCapacityLimit(); if (!_packetsMap.containsKey(messageId)) { _packetsMap[messageId] = PacketInfo(totalPackets); _totalMessages++; _totalPackets += totalPackets; } else { // 更新时间戳 _packetsMap[messageId]!.timestamp = DateTime.now().millisecondsSinceEpoch; } _packetsMap[messageId]!.receivedPackets.add(currentIndex); // 如果收到了该messageId的最后一个包,进行统计 if (currentIndex == totalPackets) { _checkPacketLoss(messageId); } } // 清理超时的记录 void _cleanupExpiredPackets() { final currentTime = DateTime.now().millisecondsSinceEpoch; final expiredMessageIds = []; _packetsMap.forEach((messageId, info) { // 如果记录超时,添加到待清理列表 if (currentTime - info.timestamp > _timeoutMs) { expiredMessageIds.add(messageId); // 统计丢包 _lostMessages++; _lostPackets += (info.totalPackets - info.receivedPackets.length); } }); // 移除超时记录 for (var messageId in expiredMessageIds) { _packetsMap.remove(messageId); } } // 检查并确保不超过最大容量 void _checkCapacityLimit() { if (_packetsMap.length <= _maxCapacity) { return; } // 如果超过容量限制,按时间戳排序并删除最旧的记录 var entries = _packetsMap.entries.toList() ..sort((a, b) => a.value.timestamp.compareTo(b.value.timestamp)); // 计算需要移除的数量(移除25%的旧记录,至少保证有一定空间) int removeCount = (_packetsMap.length * 0.25).ceil(); // 移除并统计丢包 for (int i = 0; i < removeCount && i < entries.length; i++) { var entry = entries[i]; _lostMessages++; _lostPackets += (entry.value.totalPackets - entry.value.receivedPackets.length); _packetsMap.remove(entry.key); } } // 检查丢包情况 void _checkPacketLoss(int messageId) { final info = _packetsMap[messageId]!; // 检查是否有丢失的包 int received = info.receivedPackets.length; if (received < info.totalPackets) { _lostMessages++; _lostPackets += (info.totalPackets - received); } // 清理该messageId的记录,避免内存泄漏 _packetsMap.remove(messageId); } // 获取丢包率统计信息 PacketLossInfo getStatistics() { if (_totalMessages == 0 || _totalPackets == 0) { return PacketLossInfo(0.0, 0.0); } // 计算消息级别的丢包率 double messageLossRate = (_lostMessages / _totalMessages) * 100; // 计算分包级别的丢包率 double packetLossRate = (_lostPackets / _totalPackets) * 100; return PacketLossInfo(messageLossRate, packetLossRate); } // Getter和Setter,允许外部调整参数 int get maxCapacity => _maxCapacity; set maxCapacity(int value) { if (value > 0) { _maxCapacity = value; // 设置新容量后立即检查 _checkCapacityLimit(); } } int get timeoutMs => _timeoutMs; set timeoutMs(int value) { if (value > 0) { _timeoutMs = value; // 设置新超时后立即清理 _cleanupExpiredPackets(); } } // 获取当前未完成记录数 int get pendingRecordsCount => _packetsMap.length; // 重置统计数据 void reset() { _packetsMap.clear(); _totalMessages = 0; _lostMessages = 0; _totalPackets = 0; _lostPackets = 0; } } // 分包信息类 class PacketInfo { final int totalPackets; final Set receivedPackets = HashSet(); int timestamp; // 添加时间戳字段,记录最后更新时间 PacketInfo(this.totalPackets) : timestamp = DateTime.now().millisecondsSinceEpoch; } // 丢包统计信息类 class PacketLossInfo { final double messageLossRate; // 消息丢失率 final double packetLossRate; // 分包丢失率 PacketLossInfo(this.messageLossRate, this.packetLossRate); @override String toString() { return 'Message Loss Rate: ${messageLossRate.toStringAsFixed(2)}%, Packet Loss Rate: ${packetLossRate.toStringAsFixed(2)}%'; } }