Browse Source

1

feature/LteClientLogFun
hyh 1 month ago
parent
commit
333ae8f2c6
  1. 354
      LTEMvcApp/Models/LTEClient.cs
  2. 107
      LTEMvcApp/README_ClientModelConfig_Fix.md
  3. 175
      LTEMvcApp/README_LogModelGuessInit_Implementation.md
  4. 229
      LTEMvcApp/README_SetModel_Implementation.md
  5. 2
      LTEMvcApp/Services/LTEClientWebSocket.cs

354
LTEMvcApp/Models/LTEClient.cs

@ -292,12 +292,12 @@ public class LTEClient
/// <summary>
/// 日志管理器
/// </summary>
private readonly LogsManager _logsManager;
private readonly LogsManager _lteLogs;
/// <summary>
/// 获取日志管理器实例
/// </summary>
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
/// </summary>
public void LogModelGuessInit()
{
// 实现模型猜测初始化逻辑
if (string.IsNullOrEmpty(Config.Model))
{
// 尝试所有模型
var modelList = new List<string> { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
if (!TryModelHint(modelList))
{
SetModel("MME"); // 默认模型
}
// 初始化模型猜测字典
_modelGuess = new Dictionary<string, bool>();
var layerConfig = GetLayerConfig();
foreach (var layer in layerConfig.Keys)
{
_modelGuess[layer] = false;
}
}
}
/// <summary>
/// 模型猜测字典
/// </summary>
private Dictionary<string, bool>? _modelGuess;
/// <summary>
/// 获取层配置
/// </summary>
/// <returns>层配置字典</returns>
private Dictionary<string, object> GetLayerConfig()
{
// 这里应该从 LogsManager 获取层配置
// 暂时返回一个基本的层配置
return new Dictionary<string, object>
{
{ "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" } }
};
}
/// <summary>
/// 模型猜测
/// </summary>
/// <param name="logs">日志列表</param>
public void LogModelGuess(List<Dictionary<string, object>> 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<string> { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
var availableModels = new List<string>(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; // 清除猜测字典
}
}
/// <summary>
/// 获取层方向配置
/// </summary>
/// <param name="layer">层名称</param>
/// <returns>方向配置字典</returns>
private Dictionary<string, int>? GetLayerDirection(string layer)
{
// 这里应该从 LogsManager 获取层的方向配置
// 暂时返回一个基本的配置
return layer switch
{
"PHY" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
"MAC" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
"RLC" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
"PDCP" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
"RRC" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } },
"NAS" => new Dictionary<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 3 }, { "N3IWF", 3 }, { "MME", 1 } },
"GTPU" => new Dictionary<string, int> { { "ENB", 2 }, { "N3IWF", 2 }, { "MME", 1 }, { "MBMSGW", 1 }, { "UE", 1 }, { "RUE", 2 } },
"GTPC" => new Dictionary<string, int> { { "MME", 2 } },
"IP" => new Dictionary<string, int> { { "RUE", 2 }, { "UE", 2 }, { "N3IWF", 3 }, { "PROBE", 3 }, { "MME", 3 } },
"S1AP" => new Dictionary<string, int> { { "ENB", 2 }, { "MME", 1 } },
"NGAP" => new Dictionary<string, int> { { "ENB", 2 }, { "MME", 1 }, { "N3IWF", 2 } },
"X2AP" => new Dictionary<string, int> { { "ENB", 2 } },
"XnAP" => new Dictionary<string, int> { { "ENB", 2 } },
"M2AP" => new Dictionary<string, int> { { "ENB", 2 }, { "MBMSGW", 1 } },
"IMS" => new Dictionary<string, int> { { "MME", 2 }, { "IMS", 1 } },
"CX" => new Dictionary<string, int> { { "MME", 2 }, { "IMS", 1 } },
"RX" => new Dictionary<string, int> { { "MME", 2 }, { "IMS", 1 } },
"COM" => new Dictionary<string, int> { { "*", 2 } },
"SIP" => new Dictionary<string, int> { { "IMS", 1 } },
"MEDIA" => new Dictionary<string, int> { { "IMS", 1 } },
"RTP" => new Dictionary<string, int> { { "IMS", 1 } },
"PROD" => new Dictionary<string, int> { },
"S6" => new Dictionary<string, int> { { "MME", 2 } },
"S13" => new Dictionary<string, int> { { "MME", 2 } },
"SGsAP" => new Dictionary<string, int> { { "MME", 2 } },
"SBcAP" => new Dictionary<string, int> { { "MME", 2 } },
"N8" => new Dictionary<string, int> { { "MME", 2 } },
"N12" => new Dictionary<string, int> { { "MME", 2 } },
"N13" => new Dictionary<string, int> { { "MME", 2 } },
"N17" => new Dictionary<string, int> { { "MME", 2 } },
"N50" => new Dictionary<string, int> { { "MME", 2 } },
"MMS" => new Dictionary<string, int> { { "MME", 2 } },
"HTTP2" => new Dictionary<string, int> { { "MME", 2 } },
"LCSAP" => new Dictionary<string, int> { { "MME", 2 } },
"LPPa" => new Dictionary<string, int> { { "ENB", 2 }, { "MME", 3 } },
"NL1" => new Dictionary<string, int> { { "MME", 2 } },
"NRPPa" => new Dictionary<string, int> { { "ENB", 2 }, { "MME", 3 } },
"IKEV2" => new Dictionary<string, int> { { "UE", 2 }, { "MME", 1 }, { "N3IWF", 1 } },
"SWU" => new Dictionary<string, int> { { "UE", 2 }, { "MME", 1 } },
"NWU" => new Dictionary<string, int> { { "UE", 2 }, { "MME", 1 } },
"IPSEC" => new Dictionary<string, int> { { "UE", 2 }, { "IMS", 1 }, { "N3IWF", 1 }, { "MME", 1 } },
"N3IWF" => new Dictionary<string, int> { { "UE", 2 }, { "N3IWF", 1 } },
"TRX" => new Dictionary<string, int> { { "UE", 2 }, { "ENB", 1 } },
"MON" => new Dictionary<string, int> { },
"EVENT" => new Dictionary<string, int> { },
"ALARM" => new Dictionary<string, int> { },
"LIC" => new Dictionary<string, int> { { "LICENSE", 1 } },
"OTS" => new Dictionary<string, int> { },
"ERROR" => new Dictionary<string, int> { },
_ => null
};
}
/// <summary>
@ -438,7 +631,7 @@ public class LTEClient
/// </summary>
public int StringToId(string str)
{
return _logsManager.String2Id(str);
return _lteLogs.String2Id(str);
}
/// <summary>
@ -446,7 +639,7 @@ public class LTEClient
/// </summary>
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 模型管理方法
/// <summary>
/// 模型提示信息
/// </summary>
private string? _modelHint;
/// <summary>
/// 传输方向
/// </summary>
public int TxDir { get; set; }
/// <summary>
/// 接收方向
/// </summary>
public int RxDir { get; set; }
/// <summary>
/// RAN ID列表
/// </summary>
public List<string> RanIds { get; set; } = new();
/// <summary>
/// 层方向配置
/// </summary>
private Dictionary<string, Dictionary<string, int>> _layerDir = new();
/// <summary>
/// 尝试模型提示
/// </summary>
/// <param name="models">模型列表</param>
/// <returns>是否成功设置模型</returns>
public bool TryModelHint(List<string> 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;
}
/// <summary>
/// 设置模型
/// </summary>
/// <param name="model">模型名称</param>
/// <param name="force">是否强制设置</param>
/// <returns>是否成功设置</returns>
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<string, Dictionary<string, int>>();
}
else
{
_layerDir.Clear();
}
// 通知日志管理器更新网格列
_lteLogs.GridColumnsUpdate();
return true;
}
/// <summary>
/// 设置模型提示
/// </summary>
/// <param name="hint">提示信息</param>
public void SetModelHint(string hint)
{
_modelHint = hint;
}
#endregion
#region 模型配置
/// <summary>
/// 客户端模型配置类
/// </summary>
public class ClientModelConfig
{
public string? Icon { get; set; }
public string? ModelHint { get; set; }
public string? Title { get; set; }
public Dictionary<string, Dictionary<string, int>>? LayerDir { get; set; }
}
/// <summary>
/// 客户端模型配置字典
/// </summary>
private static readonly Dictionary<string, ClientModelConfig> _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
}
/// <summary>

107
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<string, ClientModelConfig> ClientModelConfig = new()
// 修改后
private static readonly Dictionary<string, ClientModelConfig> _clientModelConfigs = new()
```
### 更新所有引用
更新所有使用该字典的地方:
```csharp
// 修改前
if (ClientModelConfig.TryGetValue(model, out var config))
// 修改后
if (_clientModelConfigs.TryGetValue(model, out var config))
```
## 修复后的代码结构
```csharp
public class LTEClient
{
// ... 其他代码 ...
#region 模型配置
/// <summary>
/// 客户端模型配置类
/// </summary>
public class ClientModelConfig
{
public string? Icon { get; set; }
public string? ModelHint { get; set; }
public string? Title { get; set; }
public Dictionary<string, Dictionary<string, int>>? LayerDir { get; set; }
}
/// <summary>
/// 客户端模型配置字典
/// </summary>
private static readonly Dictionary<string, ClientModelConfig> _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 方法实现说明

175
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<Dictionary<string, object>> logs)
```
**功能:**
- 根据日志中的层信息猜测客户端模型类型
- 使用层配置和方向信息来过滤可能的模型
- 当确定唯一模型时自动设置
**实现逻辑:**
1. 遍历所有日志,标记出现的层
2. 根据层配置过滤支持的模型
3. 使用层方向配置进一步缩小模型范围
4. 当找到唯一匹配的模型时自动设置
## 模型列表
支持的模型类型(与 JavaScript 版本一致):
```csharp
var modelList = new List<string>
{
"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<string, int> { { "UE", 2 }, { "PROBE", 3 }, { "ENB", 1 } }
```
方向值含义:
- `1`: 上行 (UL)
- `2`: 下行 (DL)
- `3`: 双向或特殊
## 使用示例
```csharp
var client = new LTEClient(config, logsManager);
// 初始化模型猜测
client.LogModelGuessInit();
// 处理日志时进行模型猜测
var logs = new List<Dictionary<string, object>>
{
new Dictionary<string, object> { { "layer", "PHY" } },
new Dictionary<string, object> { { "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<string> { "RUE", "UE", "PROBE", "ENB", "N3IWF", "MBMSGW", "MME", "IMS", "LICENSE", "MONITOR" };
if (!TryModelHint(modelList))
{
SetModel("MME"); // 默认模型
}
_modelGuess = new Dictionary<string, bool>();
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. **性能优化**: 缓存层配置和方向信息

229
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<string> models)
```
**功能:**
- 根据模型提示信息尝试设置合适的模型
- 使用正则表达式匹配模型提示
- 如果匹配成功,调用 `SetModel` 方法
### 3. SetModelHint 方法
```csharp
public void SetModelHint(string hint)
```
**功能:**
- 设置模型提示信息
- 用于后续的模型自动识别
## 模型配置
### 支持的模型类型
```csharp
private static readonly Dictionary<string, ClientModelConfig> 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<string, Dictionary<string, int>>? 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<string> { "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<string, Dictionary<string, int>>();
}
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. **网格更新**: 模型变更会触发网格列的更新

2
LTEMvcApp/Services/LTEClientWebSocket.cs

@ -135,7 +135,7 @@ namespace LTEMvcApp.Services
public LTEClientWebSocket(ClientConfig config, ILogger<LTEClientWebSocket> logger)
{
_config = config;
_client = new LTEClient(config);
_client = new LTEClient(config,new LogsManager());
_messageHandlers = new ConcurrentDictionary<int, MessageHandler>();
_messageHandlersByName = new ConcurrentDictionary<string, MessageHandler>();
_messageFifo = new ConcurrentQueue<JObject>();

Loading…
Cancel
Save