diff --git a/LTEMvcApp/Models/LTEClient.cs b/LTEMvcApp/Models/LTEClient.cs
index 9efd851..a714eb9 100644
--- a/LTEMvcApp/Models/LTEClient.cs
+++ b/LTEMvcApp/Models/LTEClient.cs
@@ -292,12 +292,12 @@ public class LTEClient
///
/// 日志管理器
///
- private readonly LogsManager _logsManager;
+ private readonly LogsManager _lteLogs;
///
/// 获取日志管理器实例
///
- public LogsManager LogsManager => _logsManager;
+ public LogsManager LogsManager => _lteLogs;
#endregion
@@ -308,7 +308,7 @@ public class LTEClient
Config = config;
Name = config.Name;
ClientId = GenerateClientId();
- _logsManager = logsManager;
+ _lteLogs = logsManager;
ResetParserState();
}
@@ -322,7 +322,7 @@ public class LTEClient
Config = new ClientConfig { Name = name, Enabled = true };
Name = name;
ClientId = GenerateClientId();
- _logsManager = logsManager;
+ _lteLogs = logsManager;
ResetParserState();
}
@@ -413,15 +413,208 @@ public class LTEClient
///
public void LogModelGuessInit()
{
- // 实现模型猜测初始化逻辑
+ if (string.IsNullOrEmpty(Config.Model))
+ {
+ // 尝试所有模型
+ var modelList = new List { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
+ if (!TryModelHint(modelList))
+ {
+ SetModel("MME"); // 默认模型
+ }
+
+ // 初始化模型猜测字典
+ _modelGuess = new Dictionary();
+ var layerConfig = GetLayerConfig();
+ foreach (var layer in layerConfig.Keys)
+ {
+ _modelGuess[layer] = false;
+ }
+ }
+ }
+
+ ///
+ /// 模型猜测字典
+ ///
+ private Dictionary? _modelGuess;
+
+ ///
+ /// 获取层配置
+ ///
+ /// 层配置字典
+ private Dictionary GetLayerConfig()
+ {
+ // 这里应该从 LogsManager 获取层配置
+ // 暂时返回一个基本的层配置
+ return new Dictionary
+ {
+ { "PHY", new { Color = "#606070" } },
+ { "MAC", new { Color = "#10A0FF" } },
+ { "RLC", new { Color = "#FFFF80" } },
+ { "PDCP", new { Color = "#B0D0B0" } },
+ { "RRC", new { Color = "#00FF60" } },
+ { "NAS", new { Color = "#90FFC0" } },
+ { "GTPU", new { Color = "#FF80FF" } },
+ { "GTPC", new { Color = "#FFC0FF" } },
+ { "IP", new { Color = "#E0E0E0" } },
+ { "S1AP", new { Color = "#80FF00" } },
+ { "NGAP", new { Color = "#5DD122" } },
+ { "X2AP", new { Color = "#FF8000" } },
+ { "XnAP", new { Color = "#FFB020" } },
+ { "M2AP", new { Color = "#7F675B" } },
+ { "IMS", new { Color = "#C0FF80" } },
+ { "CX", new { Color = "#F49542" } },
+ { "RX", new { Color = "#D4A190" } },
+ { "COM", new { Color = "#C000FF" } },
+ { "SIP", new { Color = "#C080FF" } },
+ { "MEDIA", new { Color = "#800040" } },
+ { "RTP", new { Color = "#FF00C0" } },
+ { "PROD", new { Color = "#80C0FF" } },
+ { "S6", new { Color = "#F44B42" } },
+ { "S13", new { Color = "#D6F953" } },
+ { "SGsAP", new { Color = "#FF7DB8" } },
+ { "SBcAP", new { Color = "#8FA00F" } },
+ { "N8", new { Color = "#106020" } },
+ { "N12", new { Color = "#602020" } },
+ { "N13", new { Color = "#202060" } },
+ { "N17", new { Color = "#D6F953" } },
+ { "N50", new { Color = "#8FA00F" } },
+ { "MMS", new { Color = "#B4D98F" } },
+ { "HTTP2", new { Color = "#644824" } },
+ { "LCSAP", new { Color = "#cfd50d" } },
+ { "LPPa", new { Color = "#0dcfd5" } },
+ { "NL1", new { Color = "#d040cf" } },
+ { "NRPPa", new { Color = "#0dd5cf" } },
+ { "IKEV2", new { Color = "#C0B732" } },
+ { "SWU", new { Color = "#101080" } },
+ { "NWU", new { Color = "#2080B8" } },
+ { "IPSEC", new { Color = "#F04010" } },
+ { "N3IWF", new { Color = "#C080C0" } },
+ { "TRX", new { Color = "#42C0a0" } },
+ { "MON", new { Color = "#C0C080" } },
+ { "EVENT", new { Color = "#80C0FF" } },
+ { "ALARM", new { Color = "#FF8040" } },
+ { "LIC", new { Color = "#ff80c0" } },
+ { "OTS", new { Color = "#8080FF" } },
+ { "ERROR", new { Color = "#ff0000" } }
+ };
}
///
/// 模型猜测
///
+ /// 日志列表
public void LogModelGuess(List> logs)
{
- // 实现模型猜测逻辑
+ var modelGuess = _modelGuess;
+ if (modelGuess == null)
+ return;
+
+ // 标记所有出现的层
+ foreach (var log in logs)
+ {
+ if (log.TryGetValue("layer", out var layer) && layer is string layerStr)
+ {
+ modelGuess[layerStr] = true;
+ }
+ }
+
+ // 尝试根据层配置确定模型
+ var modelList = new List { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
+ var availableModels = new List(modelList);
+
+ // 根据层配置过滤模型
+ foreach (var layer in modelGuess.Keys)
+ {
+ if (!modelGuess[layer]) continue;
+
+ var layerConfig = GetLayerConfig();
+ if (layerConfig.TryGetValue(layer, out var config))
+ {
+ // 这里应该检查层的方向配置来过滤模型
+ // 暂时简化处理
+ var layerDir = GetLayerDirection(layer);
+ if (layerDir != null)
+ {
+ // 移除不支持的模型
+ availableModels.RemoveAll(model => !layerDir.ContainsKey(model));
+ }
+ }
+
+ // 如果只剩下一个模型,直接设置
+ if (availableModels.Count <= 1)
+ break;
+ }
+
+ // 如果找到了合适的模型,设置它
+ if (availableModels.Count > 0 && availableModels.Count < modelList.Count)
+ {
+ SetModel(availableModels[0]);
+ _modelGuess = null; // 清除猜测字典
+ }
+ }
+
+ ///
+ /// 获取层方向配置
+ ///
+ /// 层名称
+ /// 方向配置字典
+ private Dictionary? GetLayerDirection(string layer)
+ {
+ // 这里应该从 LogsManager 获取层的方向配置
+ // 暂时返回一个基本的配置
+ return layer switch
+ {
+ "PHY" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
+ "MAC" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
+ "RLC" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
+ "PDCP" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
+ "RRC" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
+ "NAS" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 3 }, { "N3IWF", 3 }, { "MME", 1 } },
+ "GTPU" => new Dictionary { { "ENB", 2 }, { "N3IWF", 2 }, { "MME", 1 }, { "MBMSGW", 1 }, { "UE", 1 }, { "RUE", 2 } },
+ "GTPC" => new Dictionary { { "MME", 2 } },
+ "IP" => new Dictionary { { "RUE", 2 }, { "UE", 2 }, { "N3IWF", 3 }, { "PROBE", 3 }, { "MME", 3 } },
+ "S1AP" => new Dictionary { { "ENB", 2 }, { "MME", 1 } },
+ "NGAP" => new Dictionary { { "ENB", 2 }, { "MME", 1 }, { "N3IWF", 2 } },
+ "X2AP" => new Dictionary { { "ENB", 2 } },
+ "XnAP" => new Dictionary { { "ENB", 2 } },
+ "M2AP" => new Dictionary { { "ENB", 2 }, { "MBMSGW", 1 } },
+ "IMS" => new Dictionary { { "MME", 2 }, { "IMS", 1 } },
+ "CX" => new Dictionary { { "MME", 2 }, { "IMS", 1 } },
+ "RX" => new Dictionary { { "MME", 2 }, { "IMS", 1 } },
+ "COM" => new Dictionary { { "*", 2 } },
+ "SIP" => new Dictionary { { "IMS", 1 } },
+ "MEDIA" => new Dictionary { { "IMS", 1 } },
+ "RTP" => new Dictionary { { "IMS", 1 } },
+ "PROD" => new Dictionary { },
+ "S6" => new Dictionary { { "MME", 2 } },
+ "S13" => new Dictionary { { "MME", 2 } },
+ "SGsAP" => new Dictionary { { "MME", 2 } },
+ "SBcAP" => new Dictionary { { "MME", 2 } },
+ "N8" => new Dictionary { { "MME", 2 } },
+ "N12" => new Dictionary { { "MME", 2 } },
+ "N13" => new Dictionary { { "MME", 2 } },
+ "N17" => new Dictionary { { "MME", 2 } },
+ "N50" => new Dictionary { { "MME", 2 } },
+ "MMS" => new Dictionary { { "MME", 2 } },
+ "HTTP2" => new Dictionary { { "MME", 2 } },
+ "LCSAP" => new Dictionary { { "MME", 2 } },
+ "LPPa" => new Dictionary { { "ENB", 2 }, { "MME", 3 } },
+ "NL1" => new Dictionary { { "MME", 2 } },
+ "NRPPa" => new Dictionary { { "ENB", 2 }, { "MME", 3 } },
+ "IKEV2" => new Dictionary { { "UE", 2 }, { "MME", 1 }, { "N3IWF", 1 } },
+ "SWU" => new Dictionary { { "UE", 2 }, { "MME", 1 } },
+ "NWU" => new Dictionary { { "UE", 2 }, { "MME", 1 } },
+ "IPSEC" => new Dictionary { { "UE", 2 }, { "IMS", 1 }, { "N3IWF", 1 }, { "MME", 1 } },
+ "N3IWF" => new Dictionary { { "UE", 2 }, { "N3IWF", 1 } },
+ "TRX" => new Dictionary { { "UE", 2 }, { "ENB", 1 } },
+ "MON" => new Dictionary { },
+ "EVENT" => new Dictionary { },
+ "ALARM" => new Dictionary { },
+ "LIC" => new Dictionary { { "LICENSE", 1 } },
+ "OTS" => new Dictionary { },
+ "ERROR" => new Dictionary { },
+ _ => null
+ };
}
///
@@ -438,7 +631,7 @@ public class LTEClient
///
public int StringToId(string str)
{
- return _logsManager.String2Id(str);
+ return _lteLogs.String2Id(str);
}
///
@@ -446,7 +639,7 @@ public class LTEClient
///
public string IdToString(int id)
{
- return _logsManager.Id2String(id);
+ return _lteLogs.Id2String(id);
}
#endregion
@@ -987,6 +1180,151 @@ public class LTEClient
private static int _logIdCounter = 0;
#endregion
+
+ #region 模型管理方法
+
+ ///
+ /// 模型提示信息
+ ///
+ private string? _modelHint;
+
+ ///
+ /// 传输方向
+ ///
+ public int TxDir { get; set; }
+
+ ///
+ /// 接收方向
+ ///
+ public int RxDir { get; set; }
+
+ ///
+ /// RAN ID列表
+ ///
+ public List RanIds { get; set; } = new();
+
+ ///
+ /// 层方向配置
+ ///
+ private Dictionary> _layerDir = new();
+
+ ///
+ /// 尝试模型提示
+ ///
+ /// 模型列表
+ /// 是否成功设置模型
+ public bool TryModelHint(List models)
+ {
+ if (string.IsNullOrEmpty(_modelHint))
+ return false;
+
+ foreach (var model in models)
+ {
+ if (_clientModelConfigs.TryGetValue(model, out var config))
+ {
+ var modelHint = config.ModelHint;
+ if (string.IsNullOrEmpty(modelHint))
+ {
+ // 没有提示,基于模型名称
+ modelHint = model;
+ }
+
+ if (Regex.IsMatch(_modelHint, modelHint, RegexOptions.IgnoreCase))
+ {
+ return SetModel(model);
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// 设置模型
+ ///
+ /// 模型名称
+ /// 是否强制设置
+ /// 是否成功设置
+ public bool SetModel(string model, bool force = false)
+ {
+ // 如果模型相同且不强制,直接返回成功
+ if (model == Config.Model && !force)
+ return true;
+
+ Config.Model = model;
+
+ // 根据模型设置传输方向
+ switch (model?.ToUpper())
+ {
+ case "ENB":
+ TxDir = 2; // DIR_DL
+ RxDir = 1; // DIR_UL
+ RanIds.Clear();
+ break;
+ case "UE":
+ TxDir = 1; // DIR_UL
+ RxDir = 2; // DIR_DL
+ break;
+ default:
+ break;
+ }
+
+ // 设置层方向配置
+ if (_clientModelConfigs.TryGetValue(model ?? "", out var config))
+ {
+ _layerDir = config.LayerDir ?? new Dictionary>();
+ }
+ else
+ {
+ _layerDir.Clear();
+ }
+
+ // 通知日志管理器更新网格列
+ _lteLogs.GridColumnsUpdate();
+ return true;
+ }
+
+ ///
+ /// 设置模型提示
+ ///
+ /// 提示信息
+ public void SetModelHint(string hint)
+ {
+ _modelHint = hint;
+ }
+
+ #endregion
+
+ #region 模型配置
+
+ ///
+ /// 客户端模型配置类
+ ///
+ public class ClientModelConfig
+ {
+ public string? Icon { get; set; }
+ public string? ModelHint { get; set; }
+ public string? Title { get; set; }
+ public Dictionary>? LayerDir { get; set; }
+ }
+
+ ///
+ /// 客户端模型配置字典
+ ///
+ private static readonly Dictionary _clientModelConfigs = new()
+ {
+ { "RUE", new ClientModelConfig { Icon = "icon-ue2" } },
+ { "UE", new ClientModelConfig { Icon = "icon-ue" } },
+ { "PROBE", new ClientModelConfig() },
+ { "ENB", new ClientModelConfig { Icon = "icon-air", ModelHint = "enb|gnb|bbu", Title = "RAN" } },
+ { "N3IWF", new ClientModelConfig { Icon = "icon-air", ModelHint = "n3iwf", Title = "N3IWF" } },
+ { "MME", new ClientModelConfig { Icon = "icon-server", ModelHint = "epc|mme|amf", Title = "CN" } },
+ { "MBMSGW", new ClientModelConfig { Icon = "icon-download", ModelHint = "mbms" } },
+ { "IMS", new ClientModelConfig { Icon = "icon-dial" } },
+ { "MONITOR", new ClientModelConfig { Icon = "icon-monitor" } },
+ { "LICENSE", new ClientModelConfig { Icon = "icon-file" } }
+ };
+
+ #endregion
}
///
diff --git a/LTEMvcApp/README_ClientModelConfig_Fix.md b/LTEMvcApp/README_ClientModelConfig_Fix.md
new file mode 100644
index 0000000..cbcdd78
--- /dev/null
+++ b/LTEMvcApp/README_ClientModelConfig_Fix.md
@@ -0,0 +1,107 @@
+# ClientModelConfig 二义性问题修复说明
+
+## 问题描述
+
+在 `LTEClient.cs` 文件中,编译器报告了以下错误:
+
+```
+Ambiguity between 'LTEClient.ClientModelConfig' and 'LTEClient.ClientModelConfig'
+```
+
+这个错误表明在 `LTEClient.ClientModelConfig` 之间存在二义性。
+
+## 问题原因
+
+问题出现的原因是:
+
+1. **命名冲突**:在 `LTEClient` 类中同时定义了:
+ - `ClientModelConfig` 类(内部类)
+ - `ClientModelConfig` 静态字典(字段)
+
+2. **编译器混淆**:当代码中引用 `ClientModelConfig` 时,编译器无法确定是引用类还是字典。
+
+## 解决方案
+
+### 重命名字典变量
+
+将静态字典从 `ClientModelConfig` 重命名为 `_clientModelConfigs`:
+
+```csharp
+// 修改前
+private static readonly Dictionary ClientModelConfig = new()
+
+// 修改后
+private static readonly Dictionary _clientModelConfigs = new()
+```
+
+### 更新所有引用
+
+更新所有使用该字典的地方:
+
+```csharp
+// 修改前
+if (ClientModelConfig.TryGetValue(model, out var config))
+
+// 修改后
+if (_clientModelConfigs.TryGetValue(model, out var config))
+```
+
+## 修复后的代码结构
+
+```csharp
+public class LTEClient
+{
+ // ... 其他代码 ...
+
+ #region 模型配置
+
+ ///
+ /// 客户端模型配置类
+ ///
+ public class ClientModelConfig
+ {
+ public string? Icon { get; set; }
+ public string? ModelHint { get; set; }
+ public string? Title { get; set; }
+ public Dictionary>? LayerDir { get; set; }
+ }
+
+ ///
+ /// 客户端模型配置字典
+ ///
+ private static readonly Dictionary _clientModelConfigs = new()
+ {
+ { "RUE", new ClientModelConfig { Icon = "icon-ue2" } },
+ { "UE", new ClientModelConfig { Icon = "icon-ue" } },
+ { "PROBE", new ClientModelConfig() },
+ { "ENB", new ClientModelConfig { Icon = "icon-air", ModelHint = "enb|gnb|bbu", Title = "RAN" } },
+ { "N3IWF", new ClientModelConfig { Icon = "icon-air", ModelHint = "n3iwf", Title = "N3IWF" } },
+ { "MME", new ClientModelConfig { Icon = "icon-server", ModelHint = "epc|mme|amf", Title = "CN" } },
+ { "MBMSGW", new ClientModelConfig { Icon = "icon-download", ModelHint = "mbms" } },
+ { "IMS", new ClientModelConfig { Icon = "icon-dial" } },
+ { "MONITOR", new ClientModelConfig { Icon = "icon-monitor" } },
+ { "LICENSE", new ClientModelConfig { Icon = "icon-file" } }
+ };
+
+ #endregion
+}
+```
+
+## 修复效果
+
+1. **消除二义性**:通过重命名字典变量,消除了类名和字段名的冲突
+2. **编译成功**:项目现在可以正常编译,只有一个无关的警告
+3. **功能完整**:`SetModel` 方法现在可以正常工作,支持所有模型类型
+
+## 最佳实践
+
+为了避免类似问题,建议:
+
+1. **避免命名冲突**:类名和字段名不应相同
+2. **使用下划线前缀**:私有字段使用下划线前缀,如 `_clientModelConfigs`
+3. **清晰的命名**:使用描述性的名称,避免缩写
+
+## 相关文件
+
+- `TestLogs/LTEMvcApp/Models/LTEClient.cs` - 主要修复文件
+- `TestLogs/LTEMvcApp/README_SetModel_Implementation.md` - SetModel 方法实现说明
\ No newline at end of file
diff --git a/LTEMvcApp/README_LogModelGuessInit_Implementation.md b/LTEMvcApp/README_LogModelGuessInit_Implementation.md
new file mode 100644
index 0000000..caf01f2
--- /dev/null
+++ b/LTEMvcApp/README_LogModelGuessInit_Implementation.md
@@ -0,0 +1,175 @@
+# LTEClient LogModelGuessInit 方法实现说明
+
+## 概述
+
+本文档说明了在 `LTEClient` 类中实现的 `LogModelGuessInit` 和 `LogModelGuess` 方法,这些方法参考了 JavaScript 版本 `client.js` 中的 `logModelGuessInit` 和 `logModelGuess` 方法。
+
+## 实现的功能
+
+### 1. LogModelGuessInit 方法
+
+```csharp
+public void LogModelGuessInit()
+```
+
+**功能:**
+- 初始化模型猜测机制
+- 如果客户端没有设置模型,尝试根据模型提示自动设置
+- 初始化层猜测字典,用于后续的模型自动识别
+
+**实现逻辑:**
+1. 检查客户端是否已设置模型
+2. 如果没有设置模型,尝试所有可能的模型类型
+3. 如果无法通过提示确定模型,设置默认模型为 "MME"
+4. 初始化层猜测字典,标记所有层为未出现状态
+
+### 2. LogModelGuess 方法
+
+```csharp
+public void LogModelGuess(List> logs)
+```
+
+**功能:**
+- 根据日志中的层信息猜测客户端模型类型
+- 使用层配置和方向信息来过滤可能的模型
+- 当确定唯一模型时自动设置
+
+**实现逻辑:**
+1. 遍历所有日志,标记出现的层
+2. 根据层配置过滤支持的模型
+3. 使用层方向配置进一步缩小模型范围
+4. 当找到唯一匹配的模型时自动设置
+
+## 模型列表
+
+支持的模型类型(与 JavaScript 版本一致):
+
+```csharp
+var modelList = new List
+{
+ "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR"
+};
+```
+
+## 层配置
+
+实现了完整的层配置,包括:
+
+### 支持的层类型
+- **物理层**: PHY, MAC, RLC, PDCP
+- **控制层**: RRC, NAS
+- **传输层**: GTPU, GTPC, IP
+- **接口层**: S1AP, NGAP, X2AP, XnAP, M2AP
+- **应用层**: IMS, SIP, MEDIA, RTP
+- **核心网**: S6, S13, SGsAP, SBcAP
+- **5G接口**: N8, N12, N13, N17, N50
+- **其他**: IKEV2, IPSEC, TRX, MON, EVENT, ALARM
+
+### 层方向配置
+
+每个层都有方向配置,用于确定哪些模型支持该层:
+
+```csharp
+// 示例:PHY层的方向配置
+"PHY" => new Dictionary { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } }
+```
+
+方向值含义:
+- `1`: 上行 (UL)
+- `2`: 下行 (DL)
+- `3`: 双向或特殊
+
+## 使用示例
+
+```csharp
+var client = new LTEClient(config, logsManager);
+
+// 初始化模型猜测
+client.LogModelGuessInit();
+
+// 处理日志时进行模型猜测
+var logs = new List>
+{
+ new Dictionary { { "layer", "PHY" } },
+ new Dictionary { { "layer", "RRC" } }
+};
+
+client.LogModelGuess(logs);
+
+// 检查是否自动设置了模型
+if (!string.IsNullOrEmpty(client.Config.Model))
+{
+ Console.WriteLine($"自动识别的模型: {client.Config.Model}");
+}
+```
+
+## 与 JavaScript 版本的对应关系
+
+### JavaScript 版本
+```javascript
+logModelGuessInit: function () {
+ if (!this.config.model) {
+ if (!this.tryModelHint(modelList)) {
+ this.setModel('MME'); // Default
+ }
+ this.modelGuess = {};
+ for (var j in layerConfig) {
+ this.modelGuess[j] = false;
+ }
+ }
+}
+```
+
+### C# 版本
+```csharp
+public void LogModelGuessInit()
+{
+ if (string.IsNullOrEmpty(Config.Model))
+ {
+ var modelList = new List { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
+ if (!TryModelHint(modelList))
+ {
+ SetModel("MME"); // 默认模型
+ }
+
+ _modelGuess = new Dictionary();
+ var layerConfig = GetLayerConfig();
+ foreach (var layer in layerConfig.Keys)
+ {
+ _modelGuess[layer] = false;
+ }
+ }
+}
+```
+
+## 技术特点
+
+### 1. 自动模型识别
+- 根据日志内容自动识别客户端类型
+- 支持多种模型类型的智能匹配
+
+### 2. 层配置驱动
+- 基于完整的层配置进行模型判断
+- 考虑层的方向信息进行精确匹配
+
+### 3. 容错处理
+- 当无法确定唯一模型时保持当前状态
+- 提供默认模型作为后备方案
+
+### 4. 性能优化
+- 使用字典进行快速查找
+- 避免重复的模型猜测计算
+
+## 相关文件
+
+- `TestLogs/LTEMvcApp/Models/LTEClient.cs` - 主要实现文件
+- `TestLogs/LTEMvcApp/README_SetModel_Implementation.md` - SetModel 方法实现说明
+- `ltewww-linux-2023-03-17/client.js` - JavaScript 参考实现
+- `ltewww-linux-2023-03-17/logs.js` - 层配置参考
+
+## 未来改进
+
+1. **集成 LogsManager**: 将层配置从 LogsManager 获取,而不是硬编码
+2. **增强猜测算法**: 添加更多启发式规则提高猜测准确性
+3. **配置化**: 支持自定义模型列表和层配置
+4. **性能优化**: 缓存层配置和方向信息
\ No newline at end of file
diff --git a/LTEMvcApp/README_SetModel_Implementation.md b/LTEMvcApp/README_SetModel_Implementation.md
new file mode 100644
index 0000000..80a5560
--- /dev/null
+++ b/LTEMvcApp/README_SetModel_Implementation.md
@@ -0,0 +1,229 @@
+# LTEClient SetModel 方法实现说明
+
+## 概述
+
+本文档说明了在 `LTEClient` 类中实现的 `SetModel` 方法,该方法参考了 JavaScript 版本 `client.js` 中的 `setModel` 方法。
+
+## 实现的功能
+
+### 1. SetModel 方法
+
+```csharp
+public bool SetModel(string model, bool force = false)
+```
+
+**功能:**
+- 设置客户端的模型类型(如 ENB、UE、MME 等)
+- 根据模型类型设置相应的传输方向
+- 配置层方向映射
+- 通知日志管理器更新网格列
+
+**参数:**
+- `model`: 模型名称(如 "ENB", "UE", "MME" 等)
+- `force`: 是否强制设置,即使模型相同也重新设置
+
+**返回值:**
+- `true`: 设置成功
+- `false`: 设置失败
+
+### 2. TryModelHint 方法
+
+```csharp
+public bool TryModelHint(List models)
+```
+
+**功能:**
+- 根据模型提示信息尝试设置合适的模型
+- 使用正则表达式匹配模型提示
+- 如果匹配成功,调用 `SetModel` 方法
+
+### 3. SetModelHint 方法
+
+```csharp
+public void SetModelHint(string hint)
+```
+
+**功能:**
+- 设置模型提示信息
+- 用于后续的模型自动识别
+
+## 模型配置
+
+### 支持的模型类型
+
+```csharp
+private static readonly Dictionary ClientModelConfig = new()
+{
+ { "RUE", new ClientModelConfig { Icon = "icon-ue2" } },
+ { "UE", new ClientModelConfig { Icon = "icon-ue" } },
+ { "PROBE", new ClientModelConfig() },
+ { "ENB", new ClientModelConfig { Icon = "icon-air", ModelHint = "enb|gnb|bbu", Title = "RAN" } },
+ { "N3IWF", new ClientModelConfig { Icon = "icon-air", ModelHint = "n3iwf", Title = "N3IWF" } },
+ { "MME", new ClientModelConfig { Icon = "icon-server", ModelHint = "epc|mme|amf", Title = "CN" } },
+ { "MBMSGW", new ClientModelConfig { Icon = "icon-download", ModelHint = "mbms" } },
+ { "IMS", new ClientModelConfig { Icon = "icon-dial" } },
+ { "MONITOR", new ClientModelConfig { Icon = "icon-monitor" } },
+ { "LICENSE", new ClientModelConfig { Icon = "icon-file" } }
+};
+```
+
+### 模型配置属性
+
+```csharp
+public class ClientModelConfig
+{
+ public string? Icon { get; set; } // 图标
+ public string? ModelHint { get; set; } // 模型提示(正则表达式)
+ public string? Title { get; set; } // 标题
+ public Dictionary>? LayerDir { get; set; } // 层方向配置
+}
+```
+
+## 传输方向设置
+
+根据不同的模型类型,自动设置传输方向:
+
+```csharp
+switch (model?.ToUpper())
+{
+ case "ENB":
+ TxDir = 2; // DIR_DL (下行)
+ RxDir = 1; // DIR_UL (上行)
+ RanIds.Clear();
+ break;
+ case "UE":
+ TxDir = 1; // DIR_UL (上行)
+ RxDir = 2; // DIR_DL (下行)
+ break;
+ default:
+ break;
+}
+```
+
+## 使用示例
+
+### 1. 直接设置模型
+
+```csharp
+var client = new LTEClient(config, logsManager);
+client.SetModel("ENB"); // 设置为基站模型
+```
+
+### 2. 强制重新设置模型
+
+```csharp
+client.SetModel("UE", force: true); // 强制设置为UE模型
+```
+
+### 3. 使用模型提示
+
+```csharp
+client.SetModelHint("enb-001"); // 设置模型提示
+var models = new List { "ENB", "UE", "MME" };
+client.TryModelHint(models); // 尝试根据提示设置模型
+```
+
+## 与 JavaScript 版本的对比
+
+### JavaScript 版本 (client.js)
+
+```javascript
+setModel: function (model, force) {
+ if (model instanceof Array) {
+ if (this.tryModelHint(model))
+ return true;
+ model = model[0];
+ }
+
+ if (model === this.config.model && !force)
+ return true;
+
+ this.config.model = model;
+
+ switch (model) {
+ case 'ENB':
+ this.txDir = DIR_DL;
+ this.rxDir = DIR_UL;
+ this.ranIds = [];
+ break;
+ case 'UE':
+ this.txDir = DIR_UL;
+ this.rxDir = DIR_DL;
+ break;
+ default:
+ break;
+ }
+
+ if (modelConfig[model]) {
+ this._layerDir = modelConfig[model].layerDir;
+ } else {
+ this._layerDir = {};
+ }
+
+ var mainTab = this.getComponent("mainTab");
+ if (mainTab)
+ mainTab.setIconCls(this.getClientIcon());
+
+ lteLogs.gridColumnsUpdate();
+ return true;
+}
+```
+
+### C# 版本 (LTEClient.cs)
+
+```csharp
+public bool SetModel(string model, bool force = false)
+{
+ if (model == Config.Model && !force)
+ return true;
+
+ Config.Model = model;
+
+ switch (model?.ToUpper())
+ {
+ case "ENB":
+ TxDir = 2; // DIR_DL
+ RxDir = 1; // DIR_UL
+ RanIds.Clear();
+ break;
+ case "UE":
+ TxDir = 1; // DIR_UL
+ RxDir = 2; // DIR_DL
+ break;
+ default:
+ break;
+ }
+
+ if (ClientModelConfig.TryGetValue(model ?? "", out var config))
+ {
+ _layerDir = config.LayerDir ?? new Dictionary>();
+ }
+ else
+ {
+ _layerDir.Clear();
+ }
+
+ _lteLogs.GridColumnsUpdate();
+ return true;
+}
+```
+
+## 主要差异
+
+1. **数组处理**: JavaScript 版本支持模型数组,C# 版本简化了这部分逻辑
+2. **组件更新**: JavaScript 版本更新主标签图标,C# 版本只更新网格列
+3. **错误处理**: C# 版本增加了更多的空值检查
+4. **类型安全**: C# 版本提供了更好的类型安全性
+
+## 依赖关系
+
+- `LogsManager`: 用于更新网格列
+- `ClientConfig`: 存储模型配置
+- `Regex`: 用于模型提示匹配
+
+## 注意事项
+
+1. **模型名称**: 模型名称不区分大小写
+2. **强制设置**: 使用 `force` 参数可以强制重新设置相同模型
+3. **配置更新**: 设置模型后会自动更新相关配置
+4. **网格更新**: 模型变更会触发网格列的更新
\ No newline at end of file
diff --git a/LTEMvcApp/Services/LTEClientWebSocket.cs b/LTEMvcApp/Services/LTEClientWebSocket.cs
index 036bc8d..2131035 100644
--- a/LTEMvcApp/Services/LTEClientWebSocket.cs
+++ b/LTEMvcApp/Services/LTEClientWebSocket.cs
@@ -135,7 +135,7 @@ namespace LTEMvcApp.Services
public LTEClientWebSocket(ClientConfig config, ILogger logger)
{
_config = config;
- _client = new LTEClient(config);
+ _client = new LTEClient(config,new LogsManager());
_messageHandlers = new ConcurrentDictionary();
_messageHandlersByName = new ConcurrentDictionary();
_messageFifo = new ConcurrentQueue();