From 539440ed42c2983afb6955ca1786bb5b524f0b5a Mon Sep 17 00:00:00 2001 From: root <295172551@qq.com> Date: Sun, 29 Jun 2025 15:56:09 +0800 Subject: [PATCH] dsda1 --- LTEMvcApp/Models/LTEClient.cs | 483 +++++++++++++++++++++++++++++++--- LTEMvcApp/Models/LTELog.cs | 52 ++++ 2 files changed, 502 insertions(+), 33 deletions(-) diff --git a/LTEMvcApp/Models/LTEClient.cs b/LTEMvcApp/Models/LTEClient.cs index 73d624e..ddb5d0f 100644 --- a/LTEMvcApp/Models/LTEClient.cs +++ b/LTEMvcApp/Models/LTEClient.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using System.Text.RegularExpressions; +using System.Threading; using Newtonsoft.Json; namespace LTEMvcApp.Models; @@ -21,6 +22,13 @@ public class LTEClient /// private const int LOGS_MAX = 2000000; + /// + /// BSR表 - 对应JavaScript中的_bsr_table + /// + private static readonly int[] BsrTable = { + 0, 10, 12, 14, 17, 19, 22, 26, 31, 36, 42, 49, 57, 67, 78, 91, 107, 125, 146, 171, 200, 234, 274, 321, 376, 440, 515, 603, 706, 826, 967, 1132, 1326, 1552, 1817, 2127, 2490, 2915, 3413, 3995, 4677, 5476, 6411, 7505, 8787, 10287, 12043, 14099, 16507, 19325, 22624, 26487, 31009, 36304, 42502, 49759, 58255, 68201, 79846, 93479, 109439, 128125, 150000, 500000 + }; + #endregion #region 正则表达式 @@ -768,47 +776,34 @@ public class LTEClient continue; } - var infoMatch = RegExpInfo1.Match(log.Message); - if (infoMatch.Success) + var rrcInfoMatch = RegExpInfo1.Match(log.Message); + if (rrcInfoMatch.Success) { - if (!SetLogInfo(log, infoMatch.Groups[1].Value)) continue; - log.Message = infoMatch.Groups[2].Value; + if (!SetLogInfo(log, rrcInfoMatch.Groups[1].Value)) continue; + log.Message = rrcInfoMatch.Groups[2].Value; ProcessRrcLog(log); } - var bcMatch = RegExpRRC_BC.Match(log.Message); - if (bcMatch.Success) + var rrcBcMatch = RegExpRRC_BC.Match(log.Message); + if (rrcBcMatch.Success) { try { var data = log.GetDataString(); var jsonData = JsonConvert.DeserializeObject(data); - // 处理频段组合信息 + // 这里需要调用getUECaps(log.ue_id).setBandComb(data, info[1].toLowerCase()); + // 暂时注释掉,因为还没有实现getUECaps方法 + // GetUECaps(log.UeId ?? 0).SetBandComb(jsonData, rrcBcMatch.Groups[1].Value.ToLower()); } - catch + catch (Exception e) { - // 忽略JSON解析错误 + Console.WriteLine($"Band combination parsing error: {e.Message}"); } } break; case "NAS": - ParseCellId(log, isWebSocket); - var nasTmsiMatch = RegExpNAS_TMSI.Match(log.Message); - if (nasTmsiMatch.Success) - { - SetTmsi(log, nasTmsiMatch.Groups[1].Value); - continue; - } - - var nas5gTmsiMatch = RegExpNAS_5GTMSI.Match(log.Message); - if (nas5gTmsiMatch.Success) - { - SetTmsi(log, nas5gTmsiMatch.Groups[1].Value); - continue; - } - - var nasInfoMatch = RegExpInfo2.Match(log.Message); + var nasInfoMatch = RegExpInfo1.Match(log.Message); if (nasInfoMatch.Success) { if (!SetLogInfo(log, nasInfoMatch.Groups[1].Value)) continue; @@ -817,11 +812,31 @@ public class LTEClient } break; + case "MON": + case "OTS": + var monOtsInfoMatch = RegExpInfo1.Match(log.Message); + if (monOtsInfoMatch.Success) + { + if (!SetLogInfo(log, monOtsInfoMatch.Groups[1].Value)) continue; + log.Message = monOtsInfoMatch.Groups[2].Value; + } + break; + case "MAC": ParseCellId(log, isWebSocket); ParseMacLog(log); break; + case "RLC": + case "PDCP": + var rlcPdcpInfoMatch = RegExpInfo2.Match(log.Message); + if (rlcPdcpInfoMatch.Success) + { + if (!SetLogInfo(log, rlcPdcpInfoMatch.Groups[1].Value)) continue; + log.Message = rlcPdcpInfoMatch.Groups[2].Value; + } + break; + case "IP": var ipMatch = RegExpIP.Match(log.Message); if (ipMatch.Success) @@ -853,6 +868,15 @@ public class LTEClient var ranId = int.TryParse(s1ngMatch.Groups[2].Value, System.Globalization.NumberStyles.HexNumber, null, out var ran) ? ran : (int?)null; log.LinkIds = new LinkIds { Core = coreId, Ran = ranId }; + // 根据模型类型决定 UeId 赋值 + if ((Config.Model?.ToUpper() ?? "") == "MME") + { + if (coreId.HasValue) log.UeId = coreId.Value; + } + else + { + if (ranId.HasValue) log.UeId = ranId.Value; + } } break; @@ -861,11 +885,26 @@ public class LTEClient if (sipMatch.Success) { if (!SetLogInfo(log, sipMatch.Groups[2].Value)) continue; - log.Message = sipMatch.Groups[3].Value; + log.Msg0 = log.Message; + // 替换 ue_id 并调用 SetSameUe + var msg = sipMatch.Groups[3].Value; + var ueIdMatch = System.Text.RegularExpressions.Regex.Match(msg, @" ue_id=(\d+)"); + if (ueIdMatch.Success) + { + if (int.TryParse(ueIdMatch.Groups[1].Value, out var ueId)) + { + SetSameUe(log, ueId); + } + msg = System.Text.RegularExpressions.Regex.Replace(msg, @" ue_id=\d+", ""); + } + // 拼接 from/to 和 info[1] + var dirStr = log.Direction == 1 ? " from " : " to "; // 1=UL, 2=DL + log.Message = msg + dirStr + sipMatch.Groups[1].Value; } break; case "MEDIA": + case "RTP": var mediaMatch = RegExpMediaReq.Match(log.Message); if (mediaMatch.Success) { @@ -875,11 +914,60 @@ public class LTEClient break; case "IPsec": - var ipsecMatch = RegExpIPsec.Match(log.Message); - if (ipsecMatch.Success) + var ipsecInfoMatch = RegExpInfo1.Match(log.Message); + if (ipsecInfoMatch.Success) + { + if (!SetLogInfo(log, ipsecInfoMatch.Groups[1].Value)) continue; + log.Message = ipsecInfoMatch.Groups[2].Value; + } + var ipsecPacketMatch = RegExpIPsec.Match(log.Message); + if (ipsecPacketMatch.Success) + { + log.IpLen = int.Parse(ipsecPacketMatch.Groups[1].Value); + HasData = true; + } + break; + + case "SWU": + case "NWU": + var swuNwuInfoMatch = RegExpInfo1.Match(log.Message); + if (swuNwuInfoMatch.Success) + { + if (!SetLogInfo(log, swuNwuInfoMatch.Groups[1].Value)) continue; + log.Message = swuNwuInfoMatch.Groups[2].Value; + } + break; + + case "IMS": + var imsInfoMatch = RegExpInfo1.Match(log.Message); + if (imsInfoMatch.Success) + { + if (!SetLogInfo(log, imsInfoMatch.Groups[1].Value)) continue; + log.Message = imsInfoMatch.Groups[2].Value; + + var hints = ParseHints(log, new Dictionary { { "rid", 0 }, { "aid", 0 } }); + if (hints != null) + { + if (hints.ContainsKey("rid") && hints["rid"] != null) + { + SetSameUeId(log.UeId ?? 0, Convert.ToInt32(hints["rid"])); + } + if (hints.ContainsKey("aid") && hints["aid"] != null) + { + SetSameUeId(log.UeId ?? 0, Convert.ToInt32(hints["aid"])); + } + } + } + break; + case "EPDG": + case "PROD": + case "COM": + var comInfoMatch = RegExpInfo1.Match(log.Message); + if (comInfoMatch.Success) { - log.IpLen = int.Parse(ipsecMatch.Groups[1].Value); - log.Message = ipsecMatch.Groups[2].Value; + if (!SetLogInfo(log, comInfoMatch.Groups[1].Value)) continue; + log.Message = comInfoMatch.Groups[2].Value; + var hints = ParseHints(log); } break; @@ -1158,15 +1246,163 @@ public class LTEClient /// private void ProcessNasLog(LTELog log) { - // NAS日志处理逻辑 + // 根据消息类型处理不同的NAS消息 + switch (log.Message.ToLower()) + { + case "attach accept": + var tmsiMatch = log.FindData(RegExpNAS_TMSI); + if (tmsiMatch != null) + { + SetTmsi(log, tmsiMatch.Groups[1].Value); + } + break; + case "registration accept": + var tmsi5gMatch = log.FindData(RegExpNAS_5GTMSI); + if (tmsi5gMatch != null) + { + SetTmsi(log, tmsi5gMatch.Groups[1].Value); + } + break; + } + + // 解析提示信息 + var hints = ParseHints(log, new Dictionary + { + { "ran_ue_id", 0 }, + { "ran_address", "" } + }); + + // 处理RAN ID + if (hints != null && hints.TryGetValue("ran_ue_id", out var ranUeIdObj)) + { + var ranUeId = Convert.ToInt32(ranUeIdObj); + if (ranUeId > 0) + { + // 获取RAN ID + string? ranId = null; + if (hints.TryGetValue("global_ran_node_id", out var globalRanNodeId)) + { + ranId = globalRanNodeId.ToString(); + } + else if (hints.TryGetValue("global_enb_id", out var globalEnbId)) + { + ranId = globalEnbId.ToString(); + } + + if (!string.IsNullOrEmpty(ranId)) + { + AddUERanID(log, ranUeId, ranId); + } + } + } } /// - /// 解析MAC日志 + /// 解析MAC日志 - 对应JavaScript中的_logParseMac方法 /// private void ParseMacLog(LTELog log) { - // MAC日志解析逻辑 + var type = ""; + var args = log.Message.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + for (int m = 0; m < args.Length; m++) + { + var param = args[m]; + string? value = null; + + // 检查是否有等号分隔符 + var equalIndex = param.IndexOf('='); + if (equalIndex >= 0) + { + value = param.Substring(equalIndex + 1); + param = param.Substring(0, equalIndex); + } + else + { + // 检查是否有冒号分隔符 + var colonIndex = param.IndexOf(':'); + if (colonIndex >= 0) + { + value = param.Substring(colonIndex + 1); + param = param.Substring(0, colonIndex); + } + } + + switch (param.ToLower()) + { + case "ph": + if (value != null && int.TryParse(value, out var phr)) + { + log.Phr = phr - 23; + } + break; + + case "b": + if (value != null && int.TryParse(value, out var bValue)) + { + switch (type) + { + case "SBSR": + if (bValue >= 0 && bValue < BsrTable.Length) + { + log.UlBufferSize = BsrTable[bValue]; + } + break; + case "LBSR": + if (bValue >= 0 && bValue < BsrTable.Length && + m + 3 < args.Length) + { + var b1 = int.TryParse(args[++m], out var b1Val) ? b1Val : 0; + var b2 = int.TryParse(args[++m], out var b2Val) ? b2Val : 0; + var b3 = int.TryParse(args[++m], out var b3Val) ? b3Val : 0; + + var total = 0; + if (bValue < BsrTable.Length) total += BsrTable[bValue]; + if (b1 < BsrTable.Length) total += BsrTable[b1]; + if (b2 < BsrTable.Length) total += BsrTable[b2]; + if (b3 < BsrTable.Length) total += BsrTable[b3]; + + log.UlBufferSize = total; + } + break; + } + } + break; + + case "len": + if (value != null && int.TryParse(value, out var len)) + { + switch (type) + { + case "PAD": + log.MacPad = (log.MacPad ?? 0) + len; + break; + case "LCID": + log.MacLen = (log.MacLen ?? 0) + len; + break; + } + } + break; + + case "lcid": + type = param; + break; + + case "ta": + if (value != null && int.TryParse(value, out var ta)) + { + log.Ta = ta - 31; + } + break; + + default: + if (value == "") + { + type = param; + } + break; + } + } } /// @@ -1201,6 +1437,147 @@ public class LTEClient } } + /// + /// 获取UE信息 + /// + /// UE ID + /// UE信息 + public UEInfo? GetUE(int ueId) + { + return UeList.TryGetValue(ueId, out var ue) ? ue : null; + } + + /// + /// 创建UE信息 + /// + /// UE ID + /// UE信息 + public UEInfo CreateUE(int ueId) + { + if (!UeList.TryGetValue(ueId, out var ue)) + { + ue = new UEInfo { UeId = ueId }; + UeList[ueId] = ue; + } + return ue; + } + + /// + /// 根据参数获取UE + /// + /// 参数名 + /// 参数值 + /// UE信息 + public UEInfo? GetUEByParam(string name, object value) + { + foreach (var ue in UeList.Values) + { + var property = typeof(UEInfo).GetProperty(name); + if (property?.GetValue(ue)?.Equals(value) == true) + return ue; + } + return null; + } + + /// + /// 获取UE能力信息 + /// + /// UE ID + /// UE能力信息 + public object GetUECaps(int ueId) + { + var ue = CreateUE(ueId); + if (ue.Caps == null) + { + // 这里可以创建一个LTECaps对象 + // ue.Caps = new LTECaps(ueId); + ue.Caps = new object(); // 临时实现 + } + return ue.Caps; + } + + /// + /// 添加UE RAN ID + /// + /// 日志 + /// RAN UE ID + /// RAN ID + private void AddUERanID(LTELog log, int ranUeId, string ranId) + { + // 简化实现,实际可能需要更复杂的逻辑 + var ue = CreateUE(log.UeId ?? 0); + // 这里可以添加RAN ID相关的处理逻辑 + } + + /// + /// 解析提示信息 + /// + /// 日志 + /// 配置 + /// 提示信息字典 + private Dictionary? ParseHints(LTELog log, Dictionary? config = null) + { + if (log.Info != ID_HINTS) return null; + + var hints = new Dictionary(config ?? new Dictionary()); + + // 解析消息中的参数 + var args = log.Message.Split(' ', StringSplitOptions.RemoveEmptyEntries); + foreach (var arg in args) + { + var parts = arg.Split('='); + if (parts.Length == 2) + { + hints[parts[0]] = parts[1]; + } + } + + // 处理IMEI/IMEISV + if (hints.TryGetValue("imei", out var imeiObj)) + { + var imei = imeiObj.ToString(); + var ue = GetUEByParam("Imei", imei); + if (ue != null) + { + SetSameUe(log, ue.UeId); + } + else + { + ue = CreateUE(log.UeId ?? 0); + ue.Imei = imei; + } + } + else if (hints.TryGetValue("imeisv", out var imeisvObj)) + { + var imeisv = imeisvObj.ToString(); + var imei = imeisv.Length > 2 ? imeisv[..^2] : imeisv; // 移除最后两个字符 + var ue = GetUEByParam("Imei", imei); + if (ue != null) + { + SetSameUe(log, ue.UeId); + } + else + { + ue = CreateUE(log.UeId ?? 0); + ue.Imei = imei; + } + } + + // 处理IMSI + if (hints.TryGetValue("imsi", out var imsiObj)) + { + var imsi = imsiObj.ToString(); + var ue = GetUEByParam("Imsi", imsi); + if (ue == null) + { + ue = CreateUE(log.UeId ?? 0); + ue.Imsi = imsi; + } + } + + return hints; + } + #endregion #region 私有辅助方法 @@ -1527,6 +1904,46 @@ public class LTEClient }; #endregion + + /// + /// 设置两个UE ID为同一UE(合并UE信息) + /// + private void SetSameUeId(int id0, int id1) + { + if (id0 == id1) return; + var ue0 = UeList.ContainsKey(id0) ? UeList[id0] : null; + var ue1 = UeList.ContainsKey(id1) ? UeList[id1] : null; + + if (ue0 == ue1) + { + if (ue1 == null) + { + ue1 = CreateUE(id1); + UeList[id0] = ue1; + } + } + else if (ue0 == null) + { + UeList[id0] = ue1; + } + else if (ue1 == null) + { + UeList[id1] = ue0; + } + else + { + // 合并所有指向id1的UE为ue0 + var keysToUpdate = UeList.Where(kv => kv.Value == ue1).Select(kv => kv.Key).ToList(); + foreach (var key in keysToUpdate) + { + UeList[key] = ue0; + } + // 合并属性 + if (string.IsNullOrEmpty(ue0.Imsi)) ue0.Imsi = ue1.Imsi; + if (string.IsNullOrEmpty(ue0.Imei)) ue0.Imei = ue1.Imei; + if (ue0.Caps == null) ue0.Caps = ue1.Caps; + } + } } /// diff --git a/LTEMvcApp/Models/LTELog.cs b/LTEMvcApp/Models/LTELog.cs index 364e20d..43c2f89 100644 --- a/LTEMvcApp/Models/LTELog.cs +++ b/LTEMvcApp/Models/LTELog.cs @@ -71,6 +71,11 @@ public class LTELog /// public string? Marker { get; set; } + /// + /// SIP原始消息内容 + /// + public string? Msg0 { get; set; } + #endregion #region PHY层相关属性 @@ -171,6 +176,35 @@ public class LTELog #endregion + #region MAC层相关属性 + + /// + /// 功率余量报告(PHR) + /// + public int? Phr { get; set; } + + /// + /// 上行缓冲区大小 + /// + public int? UlBufferSize { get; set; } + + /// + /// MAC填充长度 + /// + public int? MacPad { get; set; } + + /// + /// MAC数据长度 + /// + public int? MacLen { get; set; } + + /// + /// 定时提前量(TA) + /// + public int? Ta { get; set; } + + #endregion + #region 扩展方法 /// @@ -191,6 +225,24 @@ public class LTELog return Data; } + /// + /// 在数据中查找匹配正则表达式的模式 + /// + /// 正则表达式 + /// 匹配结果,如果没有匹配则返回null + public Match? FindData(Regex regex) + { + if (Data == null) return null; + + foreach (var line in Data) + { + var match = regex.Match(line); + if (match.Success) + return match; + } + return null; + } + #endregion }