app-starlock/lib/talk/starChart/handle/other/packet_loss_statistics.dart

177 lines
4.9 KiB
Dart
Raw Normal View History

2025-04-18 10:33:51 +08:00
import 'dart:collection';
class PacketLossStatistics {
static final PacketLossStatistics _instance =
PacketLossStatistics._internal();
factory PacketLossStatistics() => _instance;
PacketLossStatistics._internal();
// 记录每个messageId的分包信息
// key: messageId, value: {totalPackets, receivedPackets}
final Map<int, PacketInfo> _packetsMap = HashMap();
// 配置参数
int _maxCapacity = 300; // 最大容量为300条记录
int _timeoutMs = 30000; // 默认超时时间为30秒
2025-04-18 10:33:51 +08:00
// 统计信息
int _totalMessages = 0; // 总消息数
int _lostMessages = 0; // 丢包的消息数
int _totalPackets = 0; // 总分包数
int _lostPackets = 0; // 丢失的分包数
// 记录分包数据
void recordPacket(int messageId, int currentIndex, int totalPackets) {
// 定期清理超时记录
_cleanupExpiredPackets();
// 检查容量限制
_checkCapacityLimit();
2025-04-18 10:33:51 +08:00
if (!_packetsMap.containsKey(messageId)) {
_packetsMap[messageId] = PacketInfo(totalPackets);
_totalMessages++;
_totalPackets += totalPackets;
} else {
// 更新时间戳
_packetsMap[messageId]!.timestamp = DateTime.now().millisecondsSinceEpoch;
2025-04-18 10:33:51 +08:00
}
_packetsMap[messageId]!.receivedPackets.add(currentIndex);
// 如果收到了该messageId的最后一个包进行统计
if (currentIndex == totalPackets) {
_checkPacketLoss(messageId);
}
}
// 清理超时的记录
void _cleanupExpiredPackets() {
final currentTime = DateTime.now().millisecondsSinceEpoch;
final expiredMessageIds = <int>[];
_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);
}
}
2025-04-18 10:33:51 +08:00
// 检查丢包情况
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;
2025-04-18 10:33:51 +08:00
// 重置统计数据
void reset() {
_packetsMap.clear();
_totalMessages = 0;
_lostMessages = 0;
_totalPackets = 0;
_lostPackets = 0;
}
}
// 分包信息类
class PacketInfo {
final int totalPackets;
final Set<int> receivedPackets = HashSet<int>();
int timestamp; // 添加时间戳字段,记录最后更新时间
2025-04-18 10:33:51 +08:00
PacketInfo(this.totalPackets)
: timestamp = DateTime.now().millisecondsSinceEpoch;
2025-04-18 10:33:51 +08:00
}
// 丢包统计信息类
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)}%';
}
}