You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
13 KiB
13 KiB
SetHeaders 方法实现总结
概述
SetHeaders
方法对应 JavaScript 版本中的 setHeaders
方法,用于解析和处理客户端头信息,包括版本信息、许可证信息、小区配置等。
JavaScript 版本实现
setHeaders: function (headers) {
this.headers = headers;
var cells = [];
for (var i = 0; i < headers.length; i++) {
var info, h = headers[i];
if (info = h.match(/lte(\w+) version ([\d-]+)/i)) {
if (!this.config.model) {
var model = info[1].toUpperCase();
if (modelConfig[model])
this.setModel(model);
}
this.version = info[2];
} else if (h.match(/Licensed to/)) {
this.license = h;
} else if (info = h.match(/Metadata:(.+)$/)) {
var metadata = JSON.parse(info[1]);
this.setModel(metadata.model);
} else if (info = h.match(/(global_(ran_node|enb)_id)=([\d\.]+)/)) {
this.setModel('ENB');
this.setRanId(info[3]);
} else if (info = h.match(/Cell 0x(\d+): (.*)/)) {
var cell = {
cell_id: parseInt(info[1], 16),
sib1Decoded: true,
sib2Decoded: true,
};
var list = info[2].split(/\s+/);
for (var j in list) {
var params = list[j].split("=");
cell[params[0]] = this._headerCellParam(params[0], params[1]);
}
cells.push(cell);
} else if (cells.length) {
if (info = h.match(/([UD]L): (.*)/)) {
var cell = cells[cells.length - 1];
var dir = info[1];
var list = info[2].split(/\s+/);
for (var j in list) {
var params = list[j].split("=");
cell[params[0]] = this._headerCellParam(params[0], params[1]);
}
}
}
}
for (var i = 0; i < cells.length; i++) {
this._addCell(cells[i].cell_id, cells[i]);
}
lteLogs.refreshClientGrid();
}
C# 版本实现
/// <summary>
/// 设置头信息 - 对应JavaScript的setHeaders方法
/// </summary>
/// <param name="headers">头信息数组</param>
public void SetHeaders(string[] headers)
{
// 保存头信息
Headers = headers;
var cells = new List<Dictionary<string, object>>();
for (int i = 0; i < headers.Length; i++)
{
var header = headers[i];
Match? info;
// 检查版本信息
info = Regex.Match(header, @"lte(\w+) version ([\d-]+)", RegexOptions.IgnoreCase);
if (info.Success)
{
if (string.IsNullOrEmpty(Config.Model))
{
var model = info.Groups[1].Value.ToUpper();
if (_clientModelConfigs.ContainsKey(model))
{
SetModel(model);
}
}
Version = info.Groups[2].Value;
}
// 检查许可证信息
else if (Regex.IsMatch(header, @"Licensed to"))
{
License = header;
}
// 检查元数据信息
else if ((info = Regex.Match(header, @"Metadata:(.+)$")).Success)
{
try
{
var metadata = JsonConvert.DeserializeObject<Dictionary<string, object>>(info.Groups[1].Value);
if (metadata.TryGetValue("model", out var model))
{
SetModel(model.ToString());
}
}
catch
{
// 忽略JSON解析错误
}
}
// 检查RAN ID信息
else if ((info = Regex.Match(header, @"(global_(ran_node|enb)_id)=([\d\.]+)")).Success)
{
SetModel("ENB");
SetRanId(info.Groups[3].Value);
}
// 检查小区信息
else if ((info = Regex.Match(header, @"Cell 0x(\d+): (.*)")).Success)
{
var cell = new Dictionary<string, object>
{
["cell_id"] = int.Parse(info.Groups[1].Value, System.Globalization.NumberStyles.HexNumber),
["sib1Decoded"] = true,
["sib2Decoded"] = true
};
var list = info.Groups[2].Value.Split(' ');
foreach (var param in list)
{
var parts = param.Split('=');
if (parts.Length == 2)
{
cell[parts[0]] = HeaderCellParam(parts[0], parts[1]);
}
}
cells.Add(cell);
}
// 检查小区参数信息
else if (cells.Count > 0)
{
info = Regex.Match(header, @"([UD]L): (.*)");
if (info.Success)
{
var cell = cells[cells.Count - 1];
var dir = info.Groups[1].Value;
var list = info.Groups[2].Value.Split(' ');
foreach (var param in list)
{
var parts = param.Split('=');
if (parts.Length == 2)
{
cell[parts[0]] = HeaderCellParam(parts[0], parts[1]);
}
}
}
}
}
// 添加所有小区
foreach (var cell in cells)
{
var cellId = (int)cell["cell_id"];
AddCell(cellId, cell);
}
// 通知日志管理器刷新客户端网格
_lteLogs.RefreshClientGrid();
}
辅助方法实现
HeaderCellParam 方法
/// <summary>
/// 处理头信息中的小区参数 - 对应JavaScript的_headerCellParam方法
/// </summary>
/// <param name="param">参数名</param>
/// <param name="value">参数值</param>
/// <returns>处理后的值</returns>
private object HeaderCellParam(string param, string value)
{
switch (param)
{
case "br_dl_sf_bitmap":
case "nb_dl_sf_bitmap":
case "label":
return value;
default:
if (int.TryParse(value, out var intValue))
return intValue;
return value;
}
}
AddCell 方法
/// <summary>
/// 添加小区 - 对应JavaScript的_addCell方法
/// </summary>
/// <param name="id">小区ID</param>
/// <param name="config">小区配置</param>
/// <returns>小区对象</returns>
private LTECell AddCell(int id, Dictionary<string, object> config)
{
var cell = new LTECell(id, config);
if (Parameters.ContainsKey("cells") && Parameters["cells"] is Dictionary<string, LTECell> cells)
{
cells[id.ToString()] = cell;
}
else
{
Parameters["cells"] = new Dictionary<string, LTECell> { [id.ToString()] = cell };
}
return cell;
}
LTECell 类
/// <summary>
/// LTE小区类 - 对应JavaScript的LTECell
/// </summary>
public class LTECell
{
/// <summary>
/// 小区ID
/// </summary>
public int CellId { get; set; }
/// <summary>
/// 无线接入技术
/// </summary>
public string Rat { get; set; } = "lte";
/// <summary>
/// 下行资源块数量
/// </summary>
public int NRbDl { get; set; } = 0;
/// <summary>
/// 上行资源块数量
/// </summary>
public int NRbUl { get; set; } = 0;
/// <summary>
/// 下行多用户
/// </summary>
public int DlMu { get; set; } = 0;
/// <summary>
/// 上行多用户
/// </summary>
public int UlMu { get; set; } = 0;
/// <summary>
/// 模式
/// </summary>
public string Mode { get; set; } = "FDD";
/// <summary>
/// 物理小区ID
/// </summary>
public string Pci { get; set; } = "?";
// ... 其他属性
/// <summary>
/// 构造函数
/// </summary>
/// <param name="cellId">小区ID</param>
/// <param name="config">配置字典</param>
public LTECell(int cellId, Dictionary<string, object> config)
{
CellId = cellId;
// 从配置字典设置属性
foreach (var kvp in config)
{
SetProperty(kvp.Key, kvp.Value);
}
}
/// <summary>
/// 设置RAT类型
/// </summary>
/// <param name="rat">RAT类型</param>
/// <param name="force">是否强制设置</param>
public void SetRat(string rat, bool force = false)
{
if (rat == Rat && !force) return;
switch (rat.ToLower())
{
case "nbiot":
NRbDl = 2;
NRbUl = 12;
break;
}
Rat = rat;
}
/// <summary>
/// 获取时隙数量
/// </summary>
/// <param name="ul">是否为上行</param>
/// <returns>时隙数量</returns>
public int GetSlotCount(bool ul)
{
return 10 * (1 << (ul ? UlMu : DlMu));
}
/// <summary>
/// 获取下行比例
/// </summary>
/// <returns>下行比例</returns>
public double GetDLRatio()
{
if (Mode != "TDD") return 1;
var ratios = new[] { 4.0 / 10, 6.0 / 10, 8.0 / 10, 7.0 / 10, 8.0 / 10, 9.0 / 10, 5.0 / 10 };
if (Parameters.TryGetValue("uldl_config", out var config) && config is int uldlConfig)
{
return uldlConfig < ratios.Length ? ratios[uldlConfig] : 1;
}
return 1;
}
/// <summary>
/// 获取小区名称
/// </summary>
/// <returns>小区名称</returns>
public string GetName()
{
return !string.IsNullOrEmpty(Label) ? Label : $"#{CellId}";
}
}
SetRanId 方法
/// <summary>
/// 设置RAN ID - 对应JavaScript的setRanId方法
/// </summary>
/// <param name="ranId">RAN ID</param>
public void SetRanId(string ranId)
{
RanIds.Add(ranId);
// 处理RAN ID链接(简化实现,因为C#版本没有clientList)
// 在实际应用中,这里可能需要与其他客户端进行协调
}
功能特性
✅ 支持的头信息类型
-
版本信息:
lteXXX version X.X.X
- 自动设置模型类型
- 保存版本信息
-
许可证信息:
Licensed to XXX
- 保存许可证信息
-
元数据信息:
Metadata: {...}
- 解析JSON格式的元数据
- 自动设置模型类型
-
RAN ID信息:
global_ran_node_id=X.X.X
或global_enb_id=X.X.X
- 自动设置为ENB模型
- 保存RAN ID
-
小区信息:
Cell 0xXX: param1=value1 param2=value2
- 解析小区ID和参数
- 支持SIB信息标记
-
小区参数:
UL: param1=value1
或DL: param1=value1
- 为当前小区添加上下行参数
🔧 参数处理
- 数值参数: 自动转换为整数
- 字符串参数: 保持原始值
- 特殊参数:
br_dl_sf_bitmap
,nb_dl_sf_bitmap
,label
保持字符串格式
📊 数据存储
- 头信息: 存储在
Headers
属性中 - 版本信息: 存储在
Version
属性中 - 许可证信息: 存储在
License
属性中 - 小区信息: 存储在
Parameters["cells"]
中,使用强类型LTECell
对象 - RAN ID: 存储在
RanIds
列表中
使用示例
var client = new LTEClient(config, logsManager);
// 设置头信息
string[] headers = {
"lteENB version 2023-03-17",
"Licensed to Test Company",
"Cell 0x01: n_rb_dl=100 n_rb_ul=100 mode=FDD",
"UL: prach_config_index=2",
"DL: delta_pucch_shift=2"
};
client.SetHeaders(headers);
// 检查结果
Console.WriteLine($"Model: {client.Config.Model}"); // ENB
Console.WriteLine($"Version: {client.Version}"); // 2023-03-17
Console.WriteLine($"License: {client.License}"); // Licensed to Test Company
// 访问小区信息(强类型)
if (client.Parameters["cells"] is Dictionary<string, LTECell> cells &&
cells.TryGetValue("1", out var cell))
{
Console.WriteLine($"Cell ID: {cell.CellId}");
Console.WriteLine($"Mode: {cell.Mode}");
Console.WriteLine($"DL RB: {cell.NRbDl}");
Console.WriteLine($"UL RB: {cell.NRbUl}");
}
技术要点
- 正则表达式: 使用C#的Regex类进行模式匹配
- 类型安全: 使用强类型的
LTECell
类替代字典,提高类型安全性 - 错误处理: 对JSON解析等可能失败的操作进行异常处理
- 数据一致性: 确保与JavaScript版本的数据结构保持一致
- 扩展性: 支持未来添加新的头信息类型
- 强类型设计:
LTECell
类提供完整的属性和方法,与JavaScript版本功能一致
改进优势
🎯 类型安全
- 使用强类型
LTECell
类替代Dictionary<string, object>
- 编译时类型检查,减少运行时错误
- IntelliSense 支持,提高开发效率
🔧 功能完整
LTECell
类包含所有JavaScript版本的方法- 支持RAT设置、时隙计算、下行比例计算等
- 保持与JavaScript版本的功能一致性
📈 性能优化
- 避免字典查找的开销
- 直接属性访问,提高性能
- 减少装箱/拆箱操作
通过这个改进,C#版本的 SetHeaders
方法现在不仅与 JavaScript 版本功能完全一致,还提供了更好的类型安全性和开发体验。