# SetHeaders 方法实现总结 ## 概述 `SetHeaders` 方法对应 JavaScript 版本中的 `setHeaders` 方法,用于解析和处理客户端头信息,包括版本信息、许可证信息、小区配置等。 ## JavaScript 版本实现 ```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# 版本实现 ```csharp /// /// 设置头信息 - 对应JavaScript的setHeaders方法 /// /// 头信息数组 public void SetHeaders(string[] headers) { // 保存头信息 Headers = headers; var cells = new List>(); 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>(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 { ["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 方法 ```csharp /// /// 处理头信息中的小区参数 - 对应JavaScript的_headerCellParam方法 /// /// 参数名 /// 参数值 /// 处理后的值 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 方法 ```csharp /// /// 添加小区 - 对应JavaScript的_addCell方法 /// /// 小区ID /// 小区配置 /// 小区对象 private LTECell AddCell(int id, Dictionary config) { var cell = new LTECell(id, config); if (Parameters.ContainsKey("cells") && Parameters["cells"] is Dictionary cells) { cells[id.ToString()] = cell; } else { Parameters["cells"] = new Dictionary { [id.ToString()] = cell }; } return cell; } ``` ### LTECell 类 ```csharp /// /// LTE小区类 - 对应JavaScript的LTECell /// public class LTECell { /// /// 小区ID /// public int CellId { get; set; } /// /// 无线接入技术 /// public string Rat { get; set; } = "lte"; /// /// 下行资源块数量 /// public int NRbDl { get; set; } = 0; /// /// 上行资源块数量 /// public int NRbUl { get; set; } = 0; /// /// 下行多用户 /// public int DlMu { get; set; } = 0; /// /// 上行多用户 /// public int UlMu { get; set; } = 0; /// /// 模式 /// public string Mode { get; set; } = "FDD"; /// /// 物理小区ID /// public string Pci { get; set; } = "?"; // ... 其他属性 /// /// 构造函数 /// /// 小区ID /// 配置字典 public LTECell(int cellId, Dictionary config) { CellId = cellId; // 从配置字典设置属性 foreach (var kvp in config) { SetProperty(kvp.Key, kvp.Value); } } /// /// 设置RAT类型 /// /// RAT类型 /// 是否强制设置 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; } /// /// 获取时隙数量 /// /// 是否为上行 /// 时隙数量 public int GetSlotCount(bool ul) { return 10 * (1 << (ul ? UlMu : DlMu)); } /// /// 获取下行比例 /// /// 下行比例 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; } /// /// 获取小区名称 /// /// 小区名称 public string GetName() { return !string.IsNullOrEmpty(Label) ? Label : $"#{CellId}"; } } ``` ### SetRanId 方法 ```csharp /// /// 设置RAN ID - 对应JavaScript的setRanId方法 /// /// RAN ID public void SetRanId(string ranId) { RanIds.Add(ranId); // 处理RAN ID链接(简化实现,因为C#版本没有clientList) // 在实际应用中,这里可能需要与其他客户端进行协调 } ``` ## 功能特性 ### ✅ 支持的头信息类型 1. **版本信息**: `lteXXX version X.X.X` - 自动设置模型类型 - 保存版本信息 2. **许可证信息**: `Licensed to XXX` - 保存许可证信息 3. **元数据信息**: `Metadata: {...}` - 解析JSON格式的元数据 - 自动设置模型类型 4. **RAN ID信息**: `global_ran_node_id=X.X.X` 或 `global_enb_id=X.X.X` - 自动设置为ENB模型 - 保存RAN ID 5. **小区信息**: `Cell 0xXX: param1=value1 param2=value2` - 解析小区ID和参数 - 支持SIB信息标记 6. **小区参数**: `UL: param1=value1` 或 `DL: param1=value1` - 为当前小区添加上下行参数 ### 🔧 参数处理 - **数值参数**: 自动转换为整数 - **字符串参数**: 保持原始值 - **特殊参数**: `br_dl_sf_bitmap`, `nb_dl_sf_bitmap`, `label` 保持字符串格式 ### 📊 数据存储 - **头信息**: 存储在 `Headers` 属性中 - **版本信息**: 存储在 `Version` 属性中 - **许可证信息**: 存储在 `License` 属性中 - **小区信息**: 存储在 `Parameters["cells"]` 中,使用强类型 `LTECell` 对象 - **RAN ID**: 存储在 `RanIds` 列表中 ## 使用示例 ```csharp 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 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}"); } ``` ## 技术要点 1. **正则表达式**: 使用C#的Regex类进行模式匹配 2. **类型安全**: 使用强类型的 `LTECell` 类替代字典,提高类型安全性 3. **错误处理**: 对JSON解析等可能失败的操作进行异常处理 4. **数据一致性**: 确保与JavaScript版本的数据结构保持一致 5. **扩展性**: 支持未来添加新的头信息类型 6. **强类型设计**: `LTECell` 类提供完整的属性和方法,与JavaScript版本功能一致 ## 改进优势 ### 🎯 类型安全 - 使用强类型 `LTECell` 类替代 `Dictionary` - 编译时类型检查,减少运行时错误 - IntelliSense 支持,提高开发效率 ### 🔧 功能完整 - `LTECell` 类包含所有JavaScript版本的方法 - 支持RAT设置、时隙计算、下行比例计算等 - 保持与JavaScript版本的功能一致性 ### 📈 性能优化 - 避免字典查找的开销 - 直接属性访问,提高性能 - 减少装箱/拆箱操作 通过这个改进,C#版本的 `SetHeaders` 方法现在不仅与 JavaScript 版本功能完全一致,还提供了更好的类型安全性和开发体验。