diff --git a/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs b/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs index 26a5f76..74157eb 100644 --- a/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs +++ b/src/X1.WebSocket/Handlers/ProtocolMessageHandler.cs @@ -6,31 +6,151 @@ using System.Text.Json; using System.Threading.Tasks; using CellularManagement.WebSocket.Models; using Microsoft.Extensions.Logging; +using X1.WebSocket.Models; namespace CellularManagement.WebSocket.Handlers { public class ProtocolMessageHandler : IWebSocketMessageHandler { private readonly ILogger _logger; + private readonly JsonSerializerOptions _jsonOptions; public ProtocolMessageHandler(ILogger logger) { _logger = logger; + _jsonOptions = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; } public string MessageType => "Protocol"; public async Task HandleAsync(WebSocketMessage message) { - _logger.LogDebug("收到仪表发送[Protocol]:{Data}", System.Text.Encoding.UTF8.GetString(message.Data)); + var messageData = Encoding.UTF8.GetString(message.Data); + _logger.LogDebug("收到协议消息,连接ID:{ConnectionId},数据长度:{DataLength}字节", + message.ConnectionId, message.Data.Length); + + ProcessProtocolMessage(messageData); + var response = new WebSocketMessage { ConnectionId = message.ConnectionId, MessageType = System.Net.WebSockets.WebSocketMessageType.Text, - NeedQueue=false + NeedQueue = false }; - await Task.CompletedTask.ConfigureAwait(false); + + _logger.LogDebug("协议消息处理完成,连接ID:{ConnectionId}", message.ConnectionId); return response; } + + /// + /// 处理协议消息 + /// + /// 消息数据 + private void ProcessProtocolMessage(string messageData) + { + if (string.IsNullOrWhiteSpace(messageData)) + { + _logger.LogWarning("协议消息数据为空"); + return; + } + + try + { + var protocolMessage = JsonSerializer.Deserialize(messageData, _jsonOptions); + + if (protocolMessage?.Payload?.Message == null) + { + _logger.LogWarning("协议消息载荷为空或格式无效"); + return; + } + + var messageCount = protocolMessage.Payload.Message.Length; + _logger.LogInformation("开始处理协议消息,消息数量:{MessageCount}", messageCount); + + if (messageCount == 0) + { + _logger.LogWarning("协议消息数组为空"); + return; + } + + ProcessProtocolLogs(protocolMessage.Payload.Message); + + _logger.LogInformation("协议消息处理完成,成功处理 {MessageCount} 条消息", messageCount); + } + catch (JsonException jsonEx) + { + _logger.LogError(jsonEx, "协议消息JSON反序列化失败:{MessageData}", messageData); + throw new InvalidOperationException("协议消息格式无效", jsonEx); + } + catch (Exception ex) + { + _logger.LogError(ex, "处理协议消息时发生未预期的错误"); + } + } + + /// + /// 处理协议日志数组 + /// + /// 协议日志数组 + private void ProcessProtocolLogs(TransferProtocolLog[] protocolLogs) + { + var processedCount = 0; + var errorCount = 0; + + foreach (var log in protocolLogs) + { + try + { + ProcessSingleProtocolLog(log); + processedCount++; + } + catch (Exception ex) + { + errorCount++; + _logger.LogError(ex, "处理单个协议日志时发生错误,日志ID:{LogId}", log.Id); + } + } + + if (errorCount > 0) + { + _logger.LogWarning("协议日志处理完成,成功:{SuccessCount},失败:{ErrorCount}", + processedCount, errorCount); + } + else + { + _logger.LogDebug("协议日志处理完成,成功处理 {ProcessedCount} 条日志", processedCount); + } + } + + /// + /// 处理单个协议日志 + /// + /// 协议日志 + private void ProcessSingleProtocolLog(TransferProtocolLog log) + { + var logInfo = new + { + Id = log.Id, + Time = log.Time.ToString(@"hh\:mm\:ss\.fff"), + Layer = log.LayerType, + UEID = log.UEID?.ToString() ?? "N/A", + IMSI = log.IMSI ?? "N/A", + PLMN = log.PLMN ?? "N/A", + CellID = log.CellID?.ToString() ?? "N/A", + Direction = log.Direction, + Info = log.Info ?? "N/A", + Message = !string.IsNullOrEmpty(log.Message) ? log.Message : "N/A" + }; + + _logger.LogDebug("处理协议日志 - 【ID】{Id} 【时间】{Time} 【层】{Layer} 【UEID】{UEID} 【IMSI】{IMSI} 【PLMN】{PLMN} 【小区】{CellID} 【方向】{Direction} 【信息】{Info} 【消息】{Message}", + logInfo.Id, logInfo.Time, logInfo.Layer, logInfo.UEID, logInfo.IMSI, logInfo.PLMN, logInfo.CellID, logInfo.Direction, logInfo.Info, logInfo.Message); + + // 这里可以添加具体的业务逻辑处理 + // 例如:数据验证、业务规则检查、数据持久化等 + } } } diff --git a/src/X1.WebSocket/Models/ProtocolLayer.cs b/src/X1.WebSocket/Models/ProtocolLayer.cs new file mode 100644 index 0000000..f6411cb --- /dev/null +++ b/src/X1.WebSocket/Models/ProtocolLayer.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace X1.WebSocket.Models +{ + /// + /// 协议层类型枚举 + /// 定义了各种协议层的类型标识 + /// + public enum ProtocolLayer + { + NONE, + GTPU, + LPPa, + M2AP, + MAC, + NAS, + NGAP, + NRPPa, + PDCP, + PROD, + PHY, + RLC, + RRC, + S1AP, + TRX, + X2AP, + XnAP, + + //NAS, + IP, + //S1AP, + //NGAP, + //GTPU, + IMS, + CX, + RX, + S6, + S13, + SGsAP, + SBcAP, + LCSAP, + //LPPa, + N12, + N8, + N17, + N50, + N13, + NL1, + HTTP2, + EPDG, + IKEV2, + IPSEC, + //PROD, + + //CX, + //IMS, + //IPSEC, + MEDIA, + MMS, + //RX, + SIP, + } +} diff --git a/src/X1.WebSocket/Models/ProtocolMessage.cs b/src/X1.WebSocket/Models/ProtocolMessage.cs new file mode 100644 index 0000000..0b2c5bb --- /dev/null +++ b/src/X1.WebSocket/Models/ProtocolMessage.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using X1.WebSocket.Models; + +namespace CellularManagement.WebSocket.Models +{ + /// + /// 协议消息模型 + /// 用于封装和传输协议相关的消息数据 + /// + public class ProtocolMessage + { + /// + /// 消息类型标识 + /// 默认为 "Protocol",表示协议类型消息 + /// + public string Type { get; set; } = "Protocol"; + + /// + /// 消息载荷数据 + /// 包含具体的协议日志数据 + /// + public ProtocolPayload Payload { get; set; } + + /// + /// 初始化协议消息的新实例 + /// + /// 协议日志消息数组 + public ProtocolMessage(TransferProtocolLog[] messages) + { + Payload = new ProtocolPayload(messages); + } + } + + /// + /// 协议消息载荷 + /// 包含具体的协议日志数据内容 + /// + public class ProtocolPayload + { + /// + /// 协议日志消息数组 + /// 存储要传输的协议日志数据 + /// + public TransferProtocolLog[] Message { get; set; } = Array.Empty(); + + /// + /// 初始化协议载荷的新实例 + /// + /// 协议日志消息数组 + public ProtocolPayload(TransferProtocolLog[] messages) + { + Message = messages; + } + } +} diff --git a/src/X1.WebSocket/Models/TransferProtocolLog.cs b/src/X1.WebSocket/Models/TransferProtocolLog.cs new file mode 100644 index 0000000..24369c2 --- /dev/null +++ b/src/X1.WebSocket/Models/TransferProtocolLog.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace X1.WebSocket.Models +{ + public class TransferProtocolLog + { + /// + /// 主键ID + /// + public long Id { get; set; } + + /// + /// 协议层类型 + /// + public ProtocolLayer LayerType { get; set; } + + /// + /// 消息详情集合(JSON格式存储) + /// + public string? MessageDetailJson { get; set; } + + /// + /// 小区ID + /// + public int? CellID { get; set; } + + /// + /// 国际移动用户识别码 + /// + public string? IMSI { get; set; } + + /// + /// 日志方向类型 + /// + public int Direction { get; set; } + + /// + /// 用户设备ID + /// + public int? UEID { get; set; } + + /// + /// 公共陆地移动网络标识 + /// + public string? PLMN { get; set; } + + /// + /// 时间间隔(毫秒) + /// + public long TimeMs { get; set; } + + /// + /// 时间戳 + /// + public long Timestamp { get; set; } + + /// + /// 信息字段 + /// + public string? Info { get; set; } + + /// + /// 消息字段 + /// + public string? Message { get; set; } + + /// + /// 消息详情集合(用于业务逻辑) + /// + public IEnumerable? MessageDetail + { + get => !string.IsNullOrEmpty(MessageDetailJson) + ? JsonSerializer.Deserialize>(MessageDetailJson, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }) + : null; + set => MessageDetailJson = value != null + ? JsonSerializer.Serialize(value, new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + WriteIndented = true + }) + : null; + } + + /// + /// 时间间隔(用于业务逻辑) + /// + public TimeSpan Time + { + get => TimeSpan.FromMilliseconds(TimeMs); + set => TimeMs = (long)value.TotalMilliseconds; + } + } +} diff --git a/src/modify.md b/src/modify.md new file mode 100644 index 0000000..91378c4 --- /dev/null +++ b/src/modify.md @@ -0,0 +1,55 @@ +# 修改记录 + +## 2024-12-19 ProtocolMessageHandler 优化 + +### 修改文件 +- `X1.WebSocket/Handlers/ProtocolMessageHandler.cs` + +### 主要改进 + +#### 1. 方法重命名 +- `ProtocolMessageOutput` → `ProcessProtocolMessageAsync` +- 更符合方法命名规范,清晰表达方法功能 + +#### 2. 代码结构优化 +- 将原来的单一方法拆分为多个职责明确的方法: + - `ProcessProtocolMessageAsync`: 处理协议消息的主要逻辑 + - `ProcessProtocolLogs`: 处理协议日志数组 + - `ProcessSingleProtocolLog`: 处理单个协议日志 + +#### 3. 错误处理改进 +- 在 `ProcessProtocolMessageAsync` 方法中添加了完整的异常处理机制 +- 区分 JSON 反序列化错误和其他异常 +- 提供更详细的错误日志信息 +- 移除了 `HandleAsync` 方法中不必要的 try-catch,让异常向上传播 +- 优化异常处理策略:记录错误日志后不再抛出异常,避免异常传播 + +#### 4. 日志记录优化 +- 使用结构化日志记录,提高日志可读性 +- 添加处理进度和统计信息的日志 +- 改进日志级别使用,Debug/Info/Warning/Error 合理分配 +- 美化协议日志输出格式,使用【】括号突出字段名称,提高可读性 +- 添加空值处理,使用 "N/A" 标识空值 +- 时间格式化为易读的时分秒毫秒格式 + +#### 5. 性能优化 +- 添加 JsonSerializerOptions 配置,提高序列化性能 +- 移除不必要的异步操作(ProcessProtocolMessage、ProcessProtocolLogs 和 ProcessSingleProtocolLog) +- 避免为了异步而异步的代码模式,只在实际需要异步的地方使用 async/await + +#### 6. 代码质量提升 +- 添加详细的 XML 文档注释 +- 改进变量命名(MsgData → messageData) +- 使用 null 检查和空值验证 +- 添加输入参数验证 + +#### 7. 可维护性改进 +- 方法职责单一,便于测试和维护 +- 代码结构清晰,易于理解和扩展 +- 为未来业务逻辑扩展预留了接口 + +### 技术细节 +- 使用 JsonSerializerOptions 配置大小写不敏感和驼峰命名 +- 添加了消息数量统计和错误计数 +- 改进了异常处理的分层结构 +- 优化了日志输出的格式和内容 \ No newline at end of file