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

177 lines
4.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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秒
// 统计信息
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 = <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);
}
}
// 检查丢包情况
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<int> receivedPackets = HashSet<int>();
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)}%';
}
}