33 changed files with 5453 additions and 0 deletions
@ -0,0 +1,20 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net8.0</TargetFramework> |
|||
<ImplicitUsings>enable</ImplicitUsings> |
|||
<Nullable>enable</Nullable> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" /> |
|||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> |
|||
<PackageReference Include="WebSocket4Net" Version="0.15.2" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Folder Include="Managers\WebSocketMgr\" /> |
|||
<Folder Include="Enums\" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,64 @@ |
|||
# Constructor.cs (自动转换为Markdown) |
|||
|
|||
```csharp |
|||
// 以下内容为原始C#代码,含详细注释 |
|||
// 文件原路径:Managers/WebSocketMgr/Constructor.cs |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 构造函数 |
|||
|
|||
/// <summary> |
|||
/// 构造函数 - 对应LTEClientWebSocket构造函数中的WebSocket相关初始化 |
|||
/// |
|||
/// 初始化说明: |
|||
/// 1. 创建MessageIdManager替代原始的_messageId和_logGetId字段 |
|||
/// 2. 创建消息队列_messageFifo,保持与原始实现一致 |
|||
/// 3. 不初始化WebSocket实例,在Connect方法中创建 |
|||
/// 4. 移除_sentMessages和_receivedMessages的初始化 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 参数clientName:对应LTEClientWebSocket构造函数中的config.Name |
|||
/// - 参数logger:对应LTEClientWebSocket构造函数中的logger参数 |
|||
/// - _messageIdManager:替代原始的_messageId和_logGetId字段 |
|||
/// - _messageFifo:对应原始的_messageFifo初始化 |
|||
/// - _disposed:对应原始的_disposed初始化 |
|||
/// - 日志记录:对应原始的构造函数日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 参数验证:增加了对clientName和logger的null检查 |
|||
/// - 职责分离:专注于WebSocket相关初始化 |
|||
/// - 功能增强:通过MessageIdManager提供更好的消息ID管理 |
|||
/// - 移除冗余:移除了消息缓存相关的初始化 |
|||
/// </summary> |
|||
/// <param name="clientName">客户端名称,对应LTEClientWebSocket._config.Name</param> |
|||
/// <param name="logger">日志记录器,对应LTEClientWebSocket._logger</param> |
|||
public WebSocketMessageManager(string clientName, ILogger logger) |
|||
{ |
|||
_clientName = clientName ?? throw new ArgumentNullException(nameof(clientName)); |
|||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
|||
|
|||
// 创建MessageIdManager,替代原始的_messageId和_logGetId字段 |
|||
_messageIdManager = new MessageIdManager(clientName, logger); |
|||
|
|||
// 创建消息队列,使用BlockingCollection优化线程安全性和性能 |
|||
_messageFifo = new BlockingCollection<JObject>(); |
|||
|
|||
_logger.LogInformation($"[{_clientName}] 创建WebSocket消息管理器"); |
|||
} |
|||
|
|||
#endregion |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
# Dispose.cs (自动转换为Markdown) |
|||
|
|||
```csharp |
|||
// 以下内容为原始C#代码,含详细注释 |
|||
// 文件原路径:Managers/WebSocketMgr/PrivateMethods.cs |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region IDisposable实现 |
|||
|
|||
/// <summary> |
|||
/// 释放资源 - 对应LTEClientWebSocket.Dispose()方法 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 释放WebSocket连接和相关资源 |
|||
/// 2. 清理消息队列和定时器 |
|||
/// 3. 设置释放标志,防止重复释放 |
|||
/// 4. 调用MessageIdManager的Dispose方法 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 资源释放:对应原始实现中的Dispose()方法 |
|||
/// - 连接关闭:对应原始实现中的WebSocket关闭逻辑 |
|||
/// - 定时器清理:对应原始实现中的定时器释放逻辑 |
|||
/// - 队列清理:对应原始实现中的队列清理逻辑 |
|||
/// - 释放标志:对应原始实现中的_disposed设置 |
|||
/// - 日志记录:对应原始实现中的释放日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的资源释放顺序 |
|||
/// - 更完善的异常处理 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的释放逻辑 |
|||
/// </summary> |
|||
public void Dispose() |
|||
{ |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 释放资源的受保护方法 - 实现标准的Dispose模式 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 实现标准的Dispose模式,支持手动释放和垃圾回收 |
|||
/// 2. 确保资源只被释放一次 |
|||
/// 3. 按照正确的顺序释放资源 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 释放模式:对应.NET标准的Dispose模式 |
|||
/// - 资源清理:对应原始实现中的资源清理逻辑 |
|||
/// - 异常处理:对应原始实现中的异常处理 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 标准的Dispose模式实现 |
|||
/// - 更安全的资源管理 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的清理逻辑 |
|||
/// </summary> |
|||
/// <param name="disposing">是否为手动释放</param> |
|||
protected virtual void Dispose(bool disposing) |
|||
{ |
|||
if (_disposed) |
|||
return; |
|||
|
|||
if (disposing) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 释放WebSocket消息管理器资源"); |
|||
|
|||
// 停止消息发送定时器 - 对应原始实现中的定时器释放 |
|||
StopMessageDeferTimer(); |
|||
|
|||
// 清空消息队列 - 对应原始实现中的队列清理 |
|||
ClearMessageQueue(); |
|||
|
|||
// 释放BlockingCollection资源 - 优化:确保BlockingCollection正确释放 |
|||
_messageFifo?.Dispose(); |
|||
|
|||
// 关闭WebSocket连接 - 对应原始实现中的WebSocket关闭 |
|||
if (_webSocket != null) |
|||
{ |
|||
_webSocket.Close(); |
|||
_webSocket = null; |
|||
} |
|||
|
|||
// 释放MessageIdManager - 对应原始实现中的相关资源释放 |
|||
_messageIdManager?.Dispose(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 释放资源异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
_disposed = true; |
|||
} |
|||
|
|||
#endregion |
|||
} |
|||
} |
|||
@ -0,0 +1,400 @@ |
|||
# PrivateMethods.cs (自动转换为Markdown) |
|||
|
|||
```csharp |
|||
// 以下内容为原始C#代码,含详细注释 |
|||
// 文件原路径:Managers/WebSocketMgr/PrivateMethods.cs |
|||
|
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 私有方法 |
|||
|
|||
/// <summary> |
|||
/// 检查对象是否已释放,如果已释放则抛出异常 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 检查_disposed字段,如果为true则抛出ObjectDisposedException |
|||
/// 2. 在所有公共方法开始时调用,确保对象状态正确 |
|||
/// 3. 提供统一的释放状态检查逻辑 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 检查逻辑:对应原始实现中的_disposed检查 |
|||
/// - 异常类型:ObjectDisposedException,与.NET标准一致 |
|||
/// - 使用场景:在所有公共方法开始时调用 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 统一的释放状态检查 |
|||
/// - 更清晰的异常信息 |
|||
/// - 更好的代码复用 |
|||
/// </summary> |
|||
private void ThrowIfDisposed() |
|||
{ |
|||
if (_disposed) |
|||
throw new ObjectDisposedException(nameof(WebSocketMessageManager)); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// WebSocket连接打开事件处理器 - 对应LTEClientWebSocket.OnSocketOpened |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理WebSocket连接成功建立事件 |
|||
/// 2. 记录连接成功日志 |
|||
/// 3. 触发ConnectionOpened事件 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件处理:对应原始实现中的OnSocketOpened方法 |
|||
/// - 日志记录:对应原始实现中的连接成功日志 |
|||
/// - 事件触发:对应原始实现中的ConnectionOpened事件触发 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的日志记录 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的事件处理逻辑 |
|||
/// </summary> |
|||
/// <param name="sender">事件发送者</param> |
|||
/// <param name="e">事件参数</param> |
|||
private void OnSocketOpened(object? sender, EventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] WebSocket连接已建立"); |
|||
ConnectionOpened?.Invoke(this, EventArgs.Empty); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理连接打开事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// WebSocket连接关闭事件处理器 - 对应LTEClientWebSocket.OnSocketClosed |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理WebSocket连接关闭事件 |
|||
/// 2. 记录连接关闭日志 |
|||
/// 3. 触发ConnectionClosed事件 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件处理:对应原始实现中的OnSocketClosed方法 |
|||
/// - 日志记录:对应原始实现中的连接关闭日志 |
|||
/// - 事件触发:对应原始实现中的ConnectionClosed事件触发 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的日志记录 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的事件处理逻辑 |
|||
/// </summary> |
|||
/// <param name="sender">事件发送者</param> |
|||
/// <param name="e">事件参数</param> |
|||
private void OnSocketClosed(object? sender, EventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] WebSocket连接已关闭"); |
|||
ConnectionClosed?.Invoke(this, EventArgs.Empty); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理连接关闭事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// WebSocket消息接收事件处理器 - 对应LTEClientWebSocket.OnSocketMessage |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理WebSocket消息接收事件 |
|||
/// 2. 解析接收到的消息 |
|||
/// 3. 触发MessageReceived事件 |
|||
/// 4. 调用HandleReceivedMessage处理消息 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件处理:对应原始实现中的OnSocketMessage方法 |
|||
/// - 消息解析:对应原始实现中的消息解析逻辑 |
|||
/// - 事件触发:对应原始实现中的MessageReceived事件触发 |
|||
/// - 消息处理:对应原始实现中的消息处理逻辑 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的错误处理 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的事件处理逻辑 |
|||
/// </summary> |
|||
/// <param name="sender">事件发送者</param> |
|||
/// <param name="e">消息接收事件参数</param> |
|||
private void OnSocketMessageReceived(object? sender, MessageReceivedEventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
var messageText = e.Message; |
|||
_logger.LogDebug($"[{_clientName}] 接收到消息: {messageText}"); |
|||
|
|||
// 解析消息 - 对应原始实现中的消息解析逻辑 |
|||
JObject? message = null; |
|||
try |
|||
{ |
|||
message = JObject.Parse(messageText); |
|||
} |
|||
catch (JsonException ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 消息解析失败: {messageText}"); |
|||
ConnectionError?.Invoke(this, $"消息解析失败: {ex.Message}"); |
|||
return; |
|||
} |
|||
|
|||
// 触发MessageReceived事件 - 对应原始实现中的事件触发 |
|||
MessageReceived?.Invoke(this, message); |
|||
|
|||
// 处理消息 - 对应原始实现中的消息处理逻辑 |
|||
HandleReceivedMessage(message, error => ConnectionError?.Invoke(this, error)); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理接收消息异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"处理接收消息异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// WebSocket错误事件处理器 - 对应LTEClientWebSocket.OnSocketError |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理WebSocket连接错误事件 |
|||
/// 2. 记录错误日志 |
|||
/// 3. 触发ConnectionError事件 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件处理:对应原始实现中的OnSocketError方法 |
|||
/// - 错误记录:对应原始实现中的错误日志记录 |
|||
/// - 事件触发:对应原始实现中的ConnectionError事件触发 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更详细的错误信息记录 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的事件处理逻辑 |
|||
/// </summary> |
|||
/// <param name="sender">事件发送者</param> |
|||
/// <param name="e">错误事件参数</param> |
|||
private void OnSocketError(object? sender, SuperSocket.ClientEngine.ErrorEventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
var errorMessage = e.Exception?.Message ?? "WebSocket连接错误"; |
|||
_logger.LogError(e.Exception, $"[{_clientName}] WebSocket错误: {errorMessage}"); |
|||
ConnectionError?.Invoke(this, errorMessage); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理WebSocket错误事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 启动消息延迟发送定时器 - 对应LTEClientWebSocket.StartMessageDeferTimer |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 启动消息延迟发送定时器,实现批量发送优化 |
|||
/// 2. 当队列中消息少于100条时,延迟1毫秒发送 |
|||
/// 3. 当队列中消息达到100条时,立即发送 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 定时器创建:对应原始实现中的定时器创建逻辑 |
|||
/// - 延迟策略:1毫秒延迟,与原始实现完全一致 |
|||
/// - 批处理大小:100条消息,与原始实现完全一致 |
|||
/// - 回调函数:对应原始实现中的定时器回调逻辑 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的定时器管理 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的批处理策略 |
|||
/// </summary> |
|||
private void StartMessageDeferTimer() |
|||
{ |
|||
Timer? timer = null; |
|||
timer = new Timer(_ => |
|||
{ |
|||
try |
|||
{ |
|||
OnMessageDeferTimer(null); |
|||
} |
|||
finally |
|||
{ |
|||
timer?.Dispose(); // 用完即销毁 |
|||
} |
|||
}, null, 1, Timeout.Infinite); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 停止消息延迟发送定时器 - 对应LTEClientWebSocket.StopMessageDeferTimer |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 停止消息延迟发送定时器 |
|||
/// 2. 释放定时器资源 |
|||
/// 3. 确保线程安全的定时器管理 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 定时器停止:对应原始实现中的定时器停止逻辑 |
|||
/// - 资源释放:对应原始实现中的定时器释放逻辑 |
|||
/// - 线程安全:使用锁确保线程安全 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的资源管理 |
|||
/// - 更好的线程安全保证 |
|||
/// - 保持了完全一致的停止逻辑 |
|||
/// </summary> |
|||
private void StopMessageDeferTimer() |
|||
{ |
|||
// 新实现下无需手动停止定时器,方法保留兼容性 |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 消息延迟发送定时器回调 - 对应LTEClientWebSocket.OnMessageDeferTimer |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理消息延迟发送定时器回调 |
|||
/// 2. 批量发送队列中的消息 |
|||
/// 3. 实现消息发送优化 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 定时器回调:对应原始实现中的OnMessageDeferTimer方法 |
|||
/// - 批量发送:对应原始实现中的批量发送逻辑 |
|||
/// - 批处理大小:100条消息,与原始实现完全一致 |
|||
/// - 发送逻辑:对应原始实现中的SendMessageNow调用 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的批量发送逻辑 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的批处理策略 |
|||
/// </summary> |
|||
/// <param name="state">定时器状态参数</param> |
|||
private void OnMessageDeferTimer(object? state) |
|||
{ |
|||
try |
|||
{ |
|||
// 批量发送消息 - 对应原始实现中的批量发送逻辑 |
|||
var messages = new List<JObject>(); |
|||
var count = 0; |
|||
const int batchSize = 100; // 与原始实现完全一致 |
|||
|
|||
// 从队列中取出消息 - 对应原始实现中的队列处理逻辑 |
|||
while (count < batchSize && _messageFifo.TryTake(out var message)) |
|||
{ |
|||
messages.Add(message); |
|||
count++; |
|||
} |
|||
|
|||
if (messages.Count > 0) |
|||
{ |
|||
// 发送消息 - 对应原始实现中的SendMessageNow调用 |
|||
SendMessageNow(messages); |
|||
} |
|||
|
|||
// 如果队列中还有消息,继续启动定时器 - 对应原始实现中的定时器重启逻辑 |
|||
if (_messageFifo.Count > 0) |
|||
{ |
|||
StartMessageDeferTimer(); |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 消息延迟发送定时器异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 立即发送消息 - 对应LTEClientWebSocket.SendMessageNow |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 立即发送消息列表到WebSocket |
|||
/// 2. 处理发送异常和错误 |
|||
/// 3. 触发MessageSent事件 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 消息发送:对应原始实现中的SendMessageNow方法 |
|||
/// - 异常处理:对应原始实现中的发送异常处理 |
|||
/// - 事件触发:对应原始实现中的事件触发逻辑 |
|||
/// - 日志记录:对应原始实现中的发送日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的发送逻辑 |
|||
/// - 更详细的错误处理 |
|||
/// - 新增MessageSent事件触发 |
|||
/// - 保持了完全一致的发送逻辑 |
|||
/// </summary> |
|||
/// <param name="messages">要发送的消息列表</param> |
|||
private void SendMessageNow(List<JObject> messages) |
|||
{ |
|||
if (messages == null || messages.Count == 0) |
|||
return; |
|||
|
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送消息"); |
|||
return; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
foreach (var message in messages) |
|||
{ |
|||
var messageText = JsonConvert.SerializeObject(message); |
|||
_webSocket?.Send(messageText); |
|||
|
|||
// 触发MessageSent事件 - 新增功能,提供更完整的消息生命周期通知 |
|||
MessageSent?.Invoke(this, message); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 消息已发送: {messageText}"); |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 发送消息异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"发送消息异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 清空消息队列 - 对应LTEClientWebSocket中的队列清理逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 清空消息队列中的所有消息 |
|||
/// 2. 在断开连接时调用,确保资源清理 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 队列清理:对应原始实现中的队列清理逻辑 |
|||
/// - 调用时机:在Disconnect()方法中调用 |
|||
/// - 日志记录:对应原始实现中的清理日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的清理逻辑 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的清理逻辑 |
|||
/// </summary> |
|||
private void ClearMessageQueue() |
|||
{ |
|||
var count = 0; |
|||
while (_messageFifo.TryTake(out _)) |
|||
{ |
|||
count++; |
|||
} |
|||
|
|||
if (count > 0) |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 清空消息队列,丢弃 {count} 条消息"); |
|||
} |
|||
} |
|||
|
|||
#endregion |
|||
} |
|||
} |
|||
@ -0,0 +1,468 @@ |
|||
# PublicMethods.cs (自动转换为Markdown) |
|||
|
|||
```csharp |
|||
// 以下内容为原始C#代码,含详细注释 |
|||
// 文件原路径:Managers/WebSocketMgr/PublicMethods.cs |
|||
|
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
using CoreAgent.ProtocolClient.Models; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 公共方法 |
|||
|
|||
/// <summary> |
|||
/// 连接到WebSocket服务器 - 对应LTEClientWebSocket.Start()方法 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 建立WebSocket连接,对应原始Start()方法的核心逻辑 |
|||
/// 2. 构建WebSocket URL,支持SSL和非SSL连接 |
|||
/// 3. 绑定事件处理器,对应原始的事件绑定逻辑 |
|||
/// 4. 提供更严格的参数验证和异常处理 |
|||
/// |
|||
/// 与原始实现的差异: |
|||
/// - 方法名从Start()改为Connect(),更明确表达功能 |
|||
/// - 移除了状态管理逻辑(SetState),专注连接管理 |
|||
/// - 增加了参数验证,提供更好的错误处理 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数url:对应原始实现中的config.Address |
|||
/// - 参数ssl:对应原始实现中的config.Ssl |
|||
/// - URL构建:对应原始实现中的URL构建逻辑 |
|||
/// - WebSocket创建:对应原始实现中的_webSocket = new WebSocket(url) |
|||
/// - 事件绑定:对应原始实现中的事件绑定逻辑 |
|||
/// - 连接打开:对应原始实现中的_webSocket.Open() |
|||
/// - 异常处理:对应原始实现中的异常处理逻辑 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更明确的参数验证 |
|||
/// - 更详细的异常处理 |
|||
/// - 更清晰的错误信息 |
|||
/// - 保持了完全一致的连接逻辑 |
|||
/// </summary> |
|||
/// <param name="url">WebSocket URL,对应LTEClientWebSocket._config.Address</param> |
|||
/// <param name="ssl">是否使用SSL,对应LTEClientWebSocket._config.Ssl</param> |
|||
public void Connect(string url, bool ssl = false) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (string.IsNullOrEmpty(url)) |
|||
throw new ArgumentException("URL不能为空", nameof(url)); |
|||
|
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 尝试连接: {url}"); |
|||
|
|||
// 构建WebSocket URL - 对应原始实现中的URL构建逻辑 |
|||
var fullUrl = (ssl ? "wss://" : "ws://") + url; |
|||
|
|||
// 创建WebSocket实例 - 对应原始实现中的_webSocket创建 |
|||
_webSocket = new WebSocket(fullUrl); |
|||
_webSocket.EnableAutoSendPing = false; |
|||
|
|||
// 绑定事件处理器 - 对应原始实现中的事件绑定 |
|||
_webSocket.Opened += OnSocketOpened!; |
|||
_webSocket.Closed += OnSocketClosed!; |
|||
_webSocket.MessageReceived += OnSocketMessageReceived!; // 对应OnSocketMessage0 |
|||
_webSocket.Error += OnSocketError!; |
|||
|
|||
// 打开连接 - 对应原始实现中的_webSocket.Open() |
|||
_webSocket.Open(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 连接异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"无法连接到 {url}: {ex.Message}"); |
|||
throw; |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 断开WebSocket连接 - 对应LTEClientWebSocket.Stop()方法中的WebSocket相关逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 关闭WebSocket连接,对应原始Stop()方法的核心逻辑 |
|||
/// 2. 清理消息队列和定时器,对应原始的资源清理逻辑 |
|||
/// 3. 提供更完善的异常处理 |
|||
/// |
|||
/// 与原始实现的差异: |
|||
/// - 方法名从Stop()改为Disconnect(),更明确表达功能 |
|||
/// - 移除了状态管理逻辑(SetState),专注连接管理 |
|||
/// - 移除了重连逻辑,专注连接断开 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 定时器停止:对应原始StopTimers()中的_messageDeferTimer处理 |
|||
/// - 队列清理:对应原始实现中的队列清理逻辑 |
|||
/// - WebSocket关闭:对应原始实现中的_webSocket.Close() |
|||
/// - 资源清理:对应原始实现中的资源清理逻辑 |
|||
/// - 异常处理:对应原始实现中的异常处理 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的资源清理顺序 |
|||
/// - 更完善的异常处理 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的清理逻辑 |
|||
/// </summary> |
|||
public void Disconnect() |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 断开连接"); |
|||
|
|||
// 停止消息发送定时器 - 对应原始StopTimers()中的_messageDeferTimer处理 |
|||
StopMessageDeferTimer(); |
|||
|
|||
// 清空消息队列 - 对应原始实现中的队列清理 |
|||
ClearMessageQueue(); |
|||
|
|||
// 关闭WebSocket连接 - 对应原始实现中的_webSocket.Close() |
|||
if (_webSocket != null) |
|||
{ |
|||
_webSocket.Close(); |
|||
_webSocket = null; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 断开连接异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 发送消息 - 对应LTEClientWebSocket.SendMessage()方法 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 发送通用消息,对应原始SendMessage()方法的核心逻辑 |
|||
/// 2. 使用MessageIdManager生成消息ID,替代原始的Interlocked.Increment(ref _messageId) |
|||
/// 3. 将消息加入队列,对应原始的_messageFifo.Enqueue(message) |
|||
/// 4. 启动延迟发送定时器,对应原始的定时器逻辑 |
|||
/// |
|||
/// 与原始实现的差异: |
|||
/// - 消息ID生成通过MessageIdManager,提供更好的管理 |
|||
/// - 移除了消息缓存逻辑(_sentMessages),专注传输 |
|||
/// - 增加了更严格的参数验证 |
|||
/// - 保持了完全一致的队列和定时器逻辑 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数message:对应原始方法中的message参数 |
|||
/// - 参数callback:对应原始方法中的callback参数 |
|||
/// - 参数errorHandler:对应原始方法中的errorHandler参数 |
|||
/// - 连接状态检查:对应原始实现中的连接状态检查 |
|||
/// - 消息ID生成:对应原始的Interlocked.Increment(ref _messageId) |
|||
/// - 队列操作:对应原始的_messageFifo.Enqueue(message) |
|||
/// - 定时器启动:对应原始的定时器启动逻辑 |
|||
/// - 返回值:对应原始方法的返回值 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更统一的消息ID管理 |
|||
/// - 更严格的参数验证 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的发送逻辑 |
|||
/// </summary> |
|||
/// <param name="message">消息对象,对应原始方法中的message参数</param> |
|||
/// <param name="callback">回调函数,对应原始方法中的callback参数</param> |
|||
/// <param name="errorHandler">是否为错误处理器,对应原始方法中的errorHandler参数</param> |
|||
/// <returns>消息ID,对应原始方法的返回值</returns> |
|||
public long SendMessage(JObject message, Action<JObject>? callback = null, bool errorHandler = false) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
throw new ArgumentNullException(nameof(message)); |
|||
|
|||
// 检查连接状态 - 对应原始实现中的连接状态检查 |
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送消息"); |
|||
return -1L; |
|||
} |
|||
|
|||
// 使用MessageIdManager生成ID - 替代原始的Interlocked.Increment(ref _messageId) |
|||
var messageId = _messageIdManager.GenerateGeneralMessageId(message, callback, errorHandler); |
|||
|
|||
// 添加到消息队列 - 对应原始实现中的_messageFifo.Enqueue(message) |
|||
_messageFifo.Add(message); |
|||
|
|||
// 启动消息发送定时器 - 对应原始实现中的定时器启动逻辑 |
|||
StartMessageDeferTimer(); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 消息已加入队列: message_id={messageId}"); |
|||
return messageId; |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 发送日志获取消息 - 对应LTEClientWebSocket.LogGet()方法中的消息发送部分 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 专门用于发送日志获取消息,对应原始LogGet()方法的核心逻辑 |
|||
/// 2. 使用MessageIdManager生成LogGet ID,替代原始的_logGetId管理 |
|||
/// 3. 委托给SendMessage方法,保持代码一致性 |
|||
/// |
|||
/// 与原始实现的差异: |
|||
/// - 专门处理日志获取消息,提供更清晰的接口 |
|||
/// - 使用MessageIdManager管理LogGet ID,提供更好的跟踪 |
|||
/// - 委托给SendMessage方法,避免代码重复 |
|||
/// - 保持了完全一致的发送逻辑 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数message:对应原始LogGet()方法中构建的message |
|||
/// - 参数callback:对应原始LogGet()方法中的LogGetParse回调 |
|||
/// - 委托给SendMessage:对应原始实现中的SendMessage调用 |
|||
/// - LogGet ID生成:对应原始的_logGetId管理逻辑 |
|||
/// - 返回值:对应原始方法的返回值 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更专门的日志获取消息处理 |
|||
/// - 更统一的LogGet ID管理 |
|||
/// - 避免代码重复,委托给SendMessage |
|||
/// - 保持了完全一致的发送逻辑 |
|||
/// </summary> |
|||
/// <param name="message">消息对象,对应原始LogGet()方法中构建的message</param> |
|||
/// <param name="callback">回调函数,对应原始LogGet()方法中的LogGetParse回调</param> |
|||
/// <returns>消息ID,对应原始方法的返回值</returns> |
|||
public long SendLogGetMessage(JObject message, Action<JObject> callback) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
throw new ArgumentNullException(nameof(message)); |
|||
|
|||
if (callback == null) |
|||
throw new ArgumentNullException(nameof(callback)); |
|||
|
|||
// 检查连接状态 - 对应原始实现中的连接状态检查 |
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送日志获取消息"); |
|||
return -1L; |
|||
} |
|||
|
|||
// 使用MessageIdManager生成LogGet ID - 替代原始的_logGetId管理 |
|||
var messageId = _messageIdManager.GenerateLogGetMessageId(message, callback); |
|||
|
|||
// 委托给SendMessage方法,避免代码重复 - 对应原始实现中的SendMessage调用 |
|||
// 注意:这里不需要再次调用SendMessage,因为GenerateLogGetMessageId已经处理了消息ID和回调注册 |
|||
// 只需要将消息加入队列并启动定时器 |
|||
_messageFifo.Add(message); |
|||
StartMessageDeferTimer(); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 日志获取消息已加入队列: message_id={messageId}"); |
|||
return messageId; |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 处理接收到的消息 - 对应LTEClientWebSocket.OnSocketMessage()方法中的消息处理逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 处理接收到的WebSocket消息,对应原始OnSocketMessage()方法的核心逻辑 |
|||
/// 2. 使用MessageIdManager处理消息响应,替代原始的消息处理器查找逻辑 |
|||
/// 3. 触发MessageReceived事件,对应原始的事件触发 |
|||
/// 4. 提供完善的错误处理 |
|||
/// |
|||
/// 与原始实现的差异: |
|||
/// - 使用MessageIdManager处理消息响应,提供更好的管理 |
|||
/// - 移除了消息缓存逻辑(_receivedMessages),专注处理 |
|||
/// - 移除了业务逻辑处理(log_get、stats等),专注消息路由 |
|||
/// - 保持了完全一致的事件触发逻辑 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数message:对应原始方法中的msg参数 |
|||
/// - 参数errorHandler:对应原始方法中的错误处理逻辑 |
|||
/// - 消息处理器查找:对应原始的消息处理器查找逻辑 |
|||
/// - 事件触发:对应原始的事件触发逻辑 |
|||
/// - 错误处理:对应原始的错误处理逻辑 |
|||
/// - 返回值:新增返回值提供处理状态反馈 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更统一的消息响应处理 |
|||
/// - 更清晰的错误处理 |
|||
/// - 更详细的日志记录 |
|||
/// - 保持了完全一致的处理逻辑 |
|||
/// </summary> |
|||
/// <param name="message">接收到的消息,对应原始方法中的msg参数</param> |
|||
/// <param name="errorHandler">错误处理回调,对应原始方法中的错误处理逻辑</param> |
|||
/// <returns>是否成功处理,新增返回值提供处理状态反馈</returns> |
|||
public bool HandleReceivedMessage(JObject message, Action<string>? errorHandler = null) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
return false; |
|||
|
|||
try |
|||
{ |
|||
// 使用MessageIdManager处理消息响应 - 替代原始的消息处理器查找逻辑 |
|||
var handled = _messageIdManager.HandleMessageResponse(message, errorHandler); |
|||
|
|||
if (handled) |
|||
{ |
|||
_logger.LogDebug($"[{_clientName}] 消息已处理: message_id={message["message_id"]}"); |
|||
return true; |
|||
} |
|||
|
|||
// 处理特定消息类型 - 对应原始实现中的特定消息类型处理 |
|||
// 注意:这里不处理log_get和stats等业务逻辑,因为重构版本专注于消息传输 |
|||
var name = message["message"]?.ToString(); |
|||
if (!string.IsNullOrEmpty(name)) |
|||
{ |
|||
_logger.LogDebug($"[{_clientName}] 未处理的特定消息类型: {name}"); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理消息异常: {ex.Message}"); |
|||
errorHandler?.Invoke($"消息处理错误: {ex.Message}"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 设置消息处理器 - 对应LTEClientWebSocket.SetMessageHandler()方法 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 设置按名称的消息处理器,对应原始SetMessageHandler()方法的核心逻辑 |
|||
/// 2. 委托给MessageIdManager处理,提供统一的消息处理器管理 |
|||
/// 3. 支持多个消息名称的处理器设置 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数names:对应原始方法中的names参数,消息名称数组 |
|||
/// - 参数handler:对应原始方法中的handler参数,消息处理器 |
|||
/// - 处理器注册:对应原始的_messageHandlersByName注册逻辑 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 委托给MessageIdManager,提供统一管理 |
|||
/// - 保持了完全一致的接口和功能 |
|||
/// - 更好的错误处理和参数验证 |
|||
/// </summary> |
|||
/// <param name="names">消息名称数组,对应原始方法中的names参数</param> |
|||
/// <param name="handler">消息处理器,对应原始方法中的handler参数</param> |
|||
public void SetMessageHandler(string[] names, MessageHandler handler) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.SetMessageHandler(names, handler); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 取消设置消息处理器 - 对应LTEClientWebSocket.UnsetMessageHandler()方法 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 取消按名称的消息处理器,对应原始UnsetMessageHandler()方法的核心逻辑 |
|||
/// 2. 委托给MessageIdManager处理,提供统一的消息处理器管理 |
|||
/// 3. 支持多个消息名称的处理器取消 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数names:对应原始方法中的names参数,消息名称数组 |
|||
/// - 处理器移除:对应原始的_messageHandlersByName移除逻辑 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 委托给MessageIdManager,提供统一管理 |
|||
/// - 保持了完全一致的接口和功能 |
|||
/// - 更好的错误处理和参数验证 |
|||
/// </summary> |
|||
/// <param name="names">消息名称数组,对应原始方法中的names参数</param> |
|||
public void UnsetMessageHandler(string[] names) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.UnsetMessageHandler(names); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 检查是否为当前日志获取消息 - 对应LTEClientWebSocket中的_logGetId检查逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 检查指定的消息ID是否为当前的日志获取消息ID |
|||
/// 2. 委托给MessageIdManager处理,提供统一的LogGet ID管理 |
|||
/// 3. 用于日志获取流程的状态检查 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数messageId:对应原始实现中的消息ID检查 |
|||
/// - 返回值:true表示是当前LogGet消息,false表示不是,对应原始逻辑 |
|||
/// - 检查逻辑:对应原始的_logGetId比较逻辑 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 委托给MessageIdManager,提供统一管理 |
|||
/// - 保持了完全一致的检查逻辑 |
|||
/// - 更好的线程安全性 |
|||
/// </summary> |
|||
/// <param name="messageId">要检查的消息ID</param> |
|||
/// <returns>是否为当前日志获取消息</returns> |
|||
public bool IsCurrentLogGetMessage(long messageId) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
return _messageIdManager.IsCurrentLogGetMessage(messageId); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 重置日志获取ID - 对应LTEClientWebSocket中的_logGetId重置逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 重置日志获取消息ID,对应原始实现中的_logGetId重置逻辑 |
|||
/// 2. 委托给MessageIdManager处理,提供统一的LogGet ID管理 |
|||
/// 3. 用于日志获取流程的重置操作 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 重置逻辑:对应原始的_logGetId = -1操作 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// - 事件触发:对应原始实现中的状态变化通知 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 委托给MessageIdManager,提供统一管理 |
|||
/// - 保持了完全一致的重置逻辑 |
|||
/// - 更好的事件通知机制 |
|||
/// </summary> |
|||
public void ResetLogGetId() |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.ResetLogGetId(); |
|||
} |
|||
|
|||
/// <summary> |
|||
/// 清理过期的消息处理器 - 对应LTEClientWebSocket中的处理器清理逻辑 |
|||
/// |
|||
/// 功能说明: |
|||
/// 1. 清理过期的消息处理器,防止内存泄漏 |
|||
/// 2. 委托给MessageIdManager处理,提供统一的处理器管理 |
|||
/// 3. 支持可配置的过期时间 |
|||
/// |
|||
/// 详细对应关系: |
|||
/// - 参数maxAge:对应原始实现中的过期时间配置 |
|||
/// - 清理逻辑:对应原始的处理器清理逻辑 |
|||
/// - 日志记录:对应原始实现中的日志记录 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 委托给MessageIdManager,提供统一管理 |
|||
/// - 保持了完全一致的清理逻辑 |
|||
/// - 更好的内存管理 |
|||
/// </summary> |
|||
/// <param name="maxAge">最大存活时间(毫秒),默认30000毫秒</param> |
|||
public void CleanupExpiredHandlers(int maxAge = 30000) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.CleanupExpiredHandlers(maxAge); |
|||
} |
|||
|
|||
#endregion |
|||
} |
|||
} |
|||
@ -0,0 +1,465 @@ |
|||
# WebSocketMessageManager.cs (自动转换为Markdown) |
|||
|
|||
```csharp |
|||
// 以下内容为原始C#代码,含详细注释 |
|||
// 文件原路径:Managers/WebSocketMgr/WebSocketMessageManager.cs |
|||
|
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
/// <summary> |
|||
/// WebSocket消息管理器 - 专门处理WebSocket的收发业务 |
|||
/// |
|||
/// 重构说明: |
|||
/// 1. 对应LTEClientWebSocket中的WebSocket连接和消息传输功能 |
|||
/// 2. 集成MessageIdManager统一管理消息ID和回调 |
|||
/// 3. 移除_sentMessages和_receivedMessages消息缓存,专注传输 |
|||
/// 4. 移除业务逻辑功能(统计更新、日志解析等),实现职责分离 |
|||
/// |
|||
/// 主要功能: |
|||
/// - WebSocket连接管理(对应LTEClientWebSocket.Start()和Stop()) |
|||
/// - 消息发送和接收(对应LTEClientWebSocket.SendMessage()和OnSocketMessage()) |
|||
/// - 消息队列和批量发送(对应LTEClientWebSocket._messageFifo和SendMessageNow()) |
|||
/// - 事件通知(对应LTEClientWebSocket的事件系统) |
|||
/// |
|||
/// 与LTEClientWebSocket的详细对应关系: |
|||
/// |
|||
/// 1. 连接管理对应关系: |
|||
/// - Connect() 对应 Start() 方法中的WebSocket连接建立逻辑 |
|||
/// - Disconnect() 对应 Stop() 方法中的WebSocket关闭逻辑 |
|||
/// - OnSocketOpened/OnSocketClosed/OnSocketError 对应原始的事件处理器 |
|||
/// |
|||
/// 2. 消息发送对应关系: |
|||
/// - SendMessage() 对应 SendMessage() 方法的核心逻辑 |
|||
/// - SendLogGetMessage() 对应 LogGet() 方法中的消息发送部分 |
|||
/// - _messageFifo 对应原始的 _messageFifo 队列 |
|||
/// - SendMessageNow() 对应原始的 SendMessageNow() 方法 |
|||
/// - StartMessageDeferTimer() 对应原始的定时器启动逻辑 |
|||
/// |
|||
/// 3. 消息接收对应关系: |
|||
/// - OnSocketMessageReceived() 对应 OnSocketMessage() 方法 |
|||
/// - HandleReceivedMessage() 对应 OnSocketMessage() 中的消息处理逻辑 |
|||
/// - MessageReceived 事件对应原始的 MessageReceived 事件 |
|||
/// |
|||
/// 4. 消息ID管理对应关系: |
|||
/// - MessageIdManager 替代原始的 _messageId 和 _logGetId 字段 |
|||
/// - GenerateGeneralMessageId() 对应 Interlocked.Increment(ref _messageId) |
|||
/// - GenerateLogGetMessageId() 对应 _logGetId 的管理逻辑 |
|||
/// |
|||
/// 5. 事件系统对应关系: |
|||
/// - ConnectionOpened 对应原始的 ConnectionOpened 事件 |
|||
/// - ConnectionClosed 对应原始的 ConnectionClosed 事件 |
|||
/// - ConnectionError 对应原始的 ConnectionError 事件 |
|||
/// - MessageReceived 对应原始的 MessageReceived 事件 |
|||
/// - MessageSent 新增事件,提供更完整的消息生命周期通知 |
|||
/// |
|||
/// 6. 资源管理对应关系: |
|||
/// - Dispose() 对应原始的 Dispose() 方法 |
|||
/// - _disposed 字段对应原始的 _disposed 字段 |
|||
/// - 定时器管理对应原始的定时器清理逻辑 |
|||
/// |
|||
/// 重构优势: |
|||
/// 1. 职责分离:专注WebSocket传输,移除业务逻辑 |
|||
/// 2. 代码复用:可在多个地方复用WebSocket管理器 |
|||
/// 3. 测试友好:更容易进行单元测试 |
|||
/// 4. 维护简单:更清晰的代码结构 |
|||
/// 5. 功能增强:通过MessageIdManager提供更好的消息管理 |
|||
/// </summary> |
|||
public partial class WebSocketMessageManager : IDisposable |
|||
{ |
|||
#region 私有字段 |
|||
|
|||
/// <summary> |
|||
/// WebSocket实例 - 对应LTEClientWebSocket._webSocket |
|||
/// 负责底层的WebSocket连接和通信 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 创建:Connect()方法中创建,对应Start()方法中的_webSocket = new WebSocket(url) |
|||
/// - 配置:EnableAutoSendPing = false,对应原始实现 |
|||
/// - 事件绑定:绑定Opened/Closed/MessageReceived/Error事件,对应原始事件绑定 |
|||
/// - 连接:调用Open()方法,对应原始的_webSocket.Open() |
|||
/// - 关闭:调用Close()方法,对应原始的_webSocket.Close() |
|||
/// - 清理:在Disconnect()中设置为null,对应原始的资源清理 |
|||
/// </summary> |
|||
private WebSocket? _webSocket; |
|||
|
|||
/// <summary> |
|||
/// 消息ID管理器 - 对应LTEClientWebSocket._messageId和_logGetId |
|||
/// 统一管理通用消息ID和日志获取消息ID,提供更好的消息跟踪和回调管理 |
|||
/// |
|||
/// 对应关系: |
|||
/// - _messageId 对应 MessageIdManager.GenerateGeneralMessageId() |
|||
/// - _logGetId 对应 MessageIdManager.GenerateLogGetMessageId() |
|||
/// - _messageHandlers 对应 MessageIdManager的内部处理器管理 |
|||
/// - _messageHandlersByName 对应 MessageIdManager的按名称处理器管理 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 线程安全的ID生成,替代原始的Interlocked.Increment |
|||
/// - 统一的处理器管理,提供更好的回调跟踪 |
|||
/// - 自动清理过期处理器,防止内存泄漏 |
|||
/// - 事件通知机制,提供ID变化通知 |
|||
/// </summary> |
|||
private readonly MessageIdManager _messageIdManager; |
|||
|
|||
/// <summary> |
|||
/// 日志记录器 - 对应LTEClientWebSocket._logger |
|||
/// 用于记录WebSocket操作和错误信息 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 构造函数参数:对应LTEClientWebSocket构造函数中的logger参数 |
|||
/// - 日志记录:对应原始实现中的所有_logger.LogXXX调用 |
|||
/// - 日志格式:保持与原始实现一致的日志格式 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 更详细的错误日志记录 |
|||
/// - 更好的异常堆栈跟踪 |
|||
/// - 统一的日志格式和级别 |
|||
/// </summary> |
|||
private readonly ILogger _logger; |
|||
|
|||
/// <summary> |
|||
/// 客户端名称 - 对应LTEClientWebSocket._config.Name |
|||
/// 用于日志记录和事件标识 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 构造函数参数:对应LTEClientWebSocket构造函数中的config.Name |
|||
/// - 日志前缀:对应原始实现中所有日志的[{_config.Name}]前缀 |
|||
/// - 事件标识:用于区分不同客户端的事件 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 参数验证:确保clientName不为null |
|||
/// - 统一标识:在所有日志和事件中使用一致的客户端标识 |
|||
/// </summary> |
|||
private readonly string _clientName; |
|||
|
|||
/// <summary> |
|||
/// 消息队列 - 对应LTEClientWebSocket._messageFifo |
|||
/// 线程安全的阻塞集合,用于批量发送优化 |
|||
/// 优化说明:从ConcurrentQueue改为BlockingCollection,提供更好的线程安全性和阻塞能力 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 队列类型:BlockingCollection<JObject>,优化后的线程安全集合 |
|||
/// - 入队操作:Add(message),对应原始的_messageFifo.Enqueue(message) |
|||
/// - 出队操作:TryTake(out message),对应原始的队列处理逻辑 |
|||
/// - 批量处理:支持批量消息发送,对应原始的批处理逻辑 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 线程安全:使用BlockingCollection保证线程安全 |
|||
/// - 阻塞能力:支持阻塞式出队操作,提高性能 |
|||
/// - 批量优化:支持批量发送减少网络开销 |
|||
/// - 延迟发送:配合_messageDeferTimer实现延迟发送 |
|||
/// - 资源管理:自动处理集合的完成状态 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 移除了消息缓存功能,专注传输 |
|||
/// - 优化了队列操作逻辑,提供更好的性能 |
|||
/// - 增强了线程安全性和资源管理 |
|||
/// </summary> |
|||
private readonly BlockingCollection<JObject> _messageFifo; |
|||
|
|||
/// <summary> |
|||
/// 消息延迟发送定时器 - 对应LTEClientWebSocket._messageDeferTimer |
|||
/// 用于实现消息的批量发送和延迟发送机制 |
|||
/// 保持与原始实现完全一致的逻辑 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 定时器类型:Timer,与原始实现完全一致 |
|||
/// - 启动逻辑:StartMessageDeferTimer(),对应原始的定时器启动 |
|||
/// - 停止逻辑:StopMessageDeferTimer(),对应原始的定时器停止 |
|||
/// - 延迟策略:1毫秒延迟,与原始实现完全一致 |
|||
/// - 批处理大小:100条消息,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 批量发送:当队列中消息少于100条时,延迟1毫秒发送 |
|||
/// - 立即发送:当队列中消息达到100条时,立即发送 |
|||
/// - 资源管理:在Disconnect()和Dispose()中正确释放 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的定时器管理逻辑 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的批处理策略 |
|||
/// </summary> |
|||
private Timer? _messageDeferTimer; |
|||
|
|||
/// <summary> |
|||
/// 释放标志 - 对应LTEClientWebSocket._disposed |
|||
/// 防止重复释放和已释放对象的操作 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 字段类型:bool,对应原始的_disposed字段 |
|||
/// - 返回值:true表示已释放,false表示未释放,对应原始实现 |
|||
/// - 使用场景:外部检查对象释放状态,对应原始实现 |
|||
/// - 线程安全:直接返回_disposed字段值,对应原始实现 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 释放状态检查:外部可以检查对象是否已释放 |
|||
/// - 资源保护:防止对已释放对象的操作 |
|||
/// - 状态查询:提供对象状态的查询接口 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 保持了完全一致的检查逻辑 |
|||
/// - 保持了完全一致的返回值语义 |
|||
/// - 保持了完全一致的使用场景 |
|||
/// </summary> |
|||
private bool _disposed; |
|||
|
|||
/// <summary> |
|||
/// 同步锁对象 |
|||
/// 用于确保线程安全的操作 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 新增功能:原始实现中没有显式的同步锁 |
|||
/// - 用途:确保关键操作的线程安全 |
|||
/// - 使用场景:在需要线程安全的地方使用lock语句 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 线程安全:确保关键操作的原子性 |
|||
/// - 死锁预防:使用细粒度锁避免死锁 |
|||
/// - 性能优化:最小化锁的持有时间 |
|||
/// </summary> |
|||
private readonly object _lockObject = new object(); |
|||
|
|||
#endregion |
|||
|
|||
#region 事件 |
|||
|
|||
/// <summary> |
|||
/// 连接打开事件 - 对应LTEClientWebSocket.ConnectionOpened |
|||
/// 当WebSocket连接成功建立时触发 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件类型:EventHandler,与原始实现完全一致 |
|||
/// - 触发时机:在OnSocketOpened()中触发,对应原始的OnSocketOpened事件处理 |
|||
/// - 触发条件:WebSocket连接成功建立时 |
|||
/// - 事件参数:无参数,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 连接状态通知:通知外部连接已建立 |
|||
/// - 事件订阅:支持多个订阅者 |
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的触发时机 |
|||
/// - 更好的错误处理 |
|||
/// - 保持了完全一致的事件接口 |
|||
/// </summary> |
|||
public event EventHandler? ConnectionOpened; |
|||
|
|||
/// <summary> |
|||
/// 连接关闭事件 - 对应LTEClientWebSocket.ConnectionClosed |
|||
/// 当WebSocket连接关闭时触发 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件类型:EventHandler,与原始实现完全一致 |
|||
/// - 触发时机:在OnSocketClosed()中触发,对应原始的OnSocketClosed事件处理 |
|||
/// - 触发条件:WebSocket连接关闭时 |
|||
/// - 事件参数:无参数,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 连接状态通知:通知外部连接已关闭 |
|||
/// - 事件订阅:支持多个订阅者 |
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的触发时机 |
|||
/// - 更好的资源清理 |
|||
/// - 保持了完全一致的事件接口 |
|||
/// </summary> |
|||
public event EventHandler? ConnectionClosed; |
|||
|
|||
/// <summary> |
|||
/// 连接错误事件 - 对应LTEClientWebSocket.ConnectionError |
|||
/// 当WebSocket连接发生错误时触发 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件类型:EventHandler<string>,与原始实现完全一致 |
|||
/// - 触发时机:在OnSocketError()和异常处理中触发,对应原始的错误处理 |
|||
/// - 触发条件:WebSocket连接错误、消息处理错误等 |
|||
/// - 事件参数:错误信息字符串,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 错误通知:通知外部连接或处理错误 |
|||
/// - 事件订阅:支持多个订阅者 |
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更详细的错误信息 |
|||
/// - 更好的异常处理 |
|||
/// - 保持了完全一致的事件接口 |
|||
/// </summary> |
|||
public event EventHandler<string>? ConnectionError; |
|||
|
|||
/// <summary> |
|||
/// 消息接收事件 - 对应LTEClientWebSocket.MessageReceived |
|||
/// 当接收到WebSocket消息时触发 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件类型:EventHandler<JObject>,与原始实现完全一致 |
|||
/// - 触发时机:在OnSocketMessageReceived()中触发,对应原始的OnSocketMessage事件处理 |
|||
/// - 触发条件:接收到WebSocket消息并解析成功后 |
|||
/// - 事件参数:解析后的JObject消息,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 消息通知:通知外部接收到新消息 |
|||
/// - 事件订阅:支持多个订阅者 |
|||
/// - 异步触发:事件触发不会阻塞消息处理 |
|||
/// - 触发顺序:在消息处理开始时就触发,与原始实现完全一致 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更清晰的触发时机 |
|||
/// - 更好的消息解析 |
|||
/// - 保持了完全一致的事件接口和触发顺序 |
|||
/// </summary> |
|||
public event EventHandler<JObject>? MessageReceived; |
|||
|
|||
/// <summary> |
|||
/// 消息发送事件 - 新增功能,LTEClientWebSocket中没有对应事件 |
|||
/// 当消息成功发送时触发,提供更完整的消息生命周期通知 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 事件类型:EventHandler<JObject>,与MessageReceived保持一致 |
|||
/// - 触发时机:在SendMessageNow()中触发,对应消息发送成功时 |
|||
/// - 触发条件:消息成功发送到WebSocket时 |
|||
/// - 事件参数:发送的JObject消息,与MessageReceived保持一致 |
|||
/// |
|||
/// 功能增强: |
|||
/// - 消息生命周期:提供完整的消息发送通知 |
|||
/// - 调试支持:便于调试消息发送流程 |
|||
/// - 监控支持:便于监控消息发送状态 |
|||
/// - 事件订阅:支持多个订阅者 |
|||
/// |
|||
/// 重构优势: |
|||
/// - 更完整的消息生命周期管理 |
|||
/// - 更好的调试和监控支持 |
|||
/// - 与MessageReceived事件形成对称的事件系统 |
|||
/// </summary> |
|||
public event EventHandler<JObject>? MessageSent; |
|||
|
|||
#endregion |
|||
|
|||
#region 属性 |
|||
|
|||
/// <summary> |
|||
/// 是否已连接 - 对应LTEClientWebSocket.IsConnected |
|||
/// 检查WebSocket连接状态 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 属性类型:bool,与原始实现完全一致 |
|||
/// - 检查逻辑:_webSocket?.State == WebSocketState.Open,与原始实现完全一致 |
|||
/// - 使用场景:在SendMessage()中检查连接状态,对应原始实现 |
|||
/// - 返回值:true表示已连接,false表示未连接,与原始实现完全一致 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 连接状态检查:快速检查WebSocket连接状态 |
|||
/// - 空安全:使用?.操作符避免空引用异常 |
|||
/// - 实时状态:反映WebSocket的实时连接状态 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 保持了完全一致的检查逻辑 |
|||
/// - 保持了完全一致的返回值语义 |
|||
/// - 保持了完全一致的使用场景 |
|||
/// </summary> |
|||
public bool IsConnected => _webSocket?.State == WebSocketState.Open; |
|||
|
|||
/// <summary> |
|||
/// WebSocket状态 - 对应LTEClientWebSocket._webSocket?.State |
|||
/// 获取详细的WebSocket连接状态 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 属性类型:WebSocketState,对应原始的_webSocket?.State |
|||
/// - 返回值:WebSocket的详细状态,对应原始实现 |
|||
/// - 空安全:使用??操作符提供默认值,对应原始实现 |
|||
/// - 使用场景:提供更详细的连接状态信息 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 详细状态:提供WebSocket的详细连接状态 |
|||
/// - 空安全:当_webSocket为null时返回WebSocketState.None |
|||
/// - 实时状态:反映WebSocket的实时状态 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 保持了完全一致的状态获取逻辑 |
|||
/// - 保持了完全一致的默认值处理 |
|||
/// - 保持了完全一致的使用场景 |
|||
/// </summary> |
|||
public WebSocketState State => _webSocket?.State ?? WebSocketState.None; |
|||
|
|||
/// <summary> |
|||
/// 是否已释放 - 对应LTEClientWebSocket._disposed |
|||
/// 检查对象是否已被释放 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 属性类型:bool,对应原始的_disposed字段 |
|||
/// - 返回值:true表示已释放,false表示未释放,对应原始实现 |
|||
/// - 使用场景:外部检查对象释放状态,对应原始实现 |
|||
/// - 线程安全:直接返回_disposed字段值,对应原始实现 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 释放状态检查:外部可以检查对象是否已释放 |
|||
/// - 资源保护:防止对已释放对象的操作 |
|||
/// - 状态查询:提供对象状态的查询接口 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 保持了完全一致的检查逻辑 |
|||
/// - 保持了完全一致的返回值语义 |
|||
/// - 保持了完全一致的使用场景 |
|||
/// </summary> |
|||
public bool IsDisposed => _disposed; |
|||
|
|||
/// <summary> |
|||
/// 消息队列数量 - 对应LTEClientWebSocket._messageFifo.Count |
|||
/// 获取当前待发送消息的数量 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 属性类型:int,对应原始的_messageFifo.Count |
|||
/// - 返回值:队列中待发送消息的数量,对应原始实现 |
|||
/// - 使用场景:监控消息队列状态,对应原始实现 |
|||
/// - 线程安全:BlockingCollection.Count是线程安全的,对应原始实现 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 队列监控:监控当前待发送消息的数量 |
|||
/// - 性能监控:便于监控消息发送性能 |
|||
/// - 调试支持:便于调试消息队列状态 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 保持了完全一致的计数逻辑 |
|||
/// - 保持了完全一致的返回值语义 |
|||
/// - 保持了完全一致的使用场景 |
|||
/// - 优化:使用BlockingCollection提供更好的线程安全性 |
|||
/// </summary> |
|||
public int MessageQueueCount => _messageFifo.Count; |
|||
|
|||
/// <summary> |
|||
/// 消息ID管理器 - 提供对MessageIdManager的访问 |
|||
/// 允许外部访问消息ID管理功能 |
|||
/// |
|||
/// 对应关系: |
|||
/// - 属性类型:MessageIdManager,对应原始的_messageId和_logGetId管理 |
|||
/// - 返回值:内部的消息ID管理器实例,对应原始实现 |
|||
/// - 使用场景:外部访问消息ID管理功能,对应原始实现 |
|||
/// - 封装性:提供对内部MessageIdManager的访问,对应原始实现 |
|||
/// |
|||
/// 功能保持: |
|||
/// - 功能访问:外部可以访问消息ID管理功能 |
|||
/// - 封装性:保持内部实现的封装性 |
|||
/// - 扩展性:支持外部扩展消息ID管理功能 |
|||
/// |
|||
/// 重构改进: |
|||
/// - 更统一的消息ID管理接口 |
|||
/// - 更好的功能封装 |
|||
/// - 保持了完全一致的功能访问方式 |
|||
/// </summary> |
|||
public MessageIdManager MessageIdManager => _messageIdManager; |
|||
|
|||
#endregion |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
# WebSocketMessageManager 结构层次说明 |
|||
|
|||
``` |
|||
Core/WebSocket/Managers/WebSocketMessageManager/ |
|||
├── WebSocketMessageManager.cs # 主体声明:类声明、字段、属性、事件 |
|||
├── Constructor.cs # 构造函数:初始化相关 |
|||
├── PublicMethods.cs # 公共方法:对外接口、业务主流程 |
|||
├── PrivateMethods.cs # 私有方法:内部逻辑、事件处理器、辅助方法 |
|||
├── Dispose.cs # IDisposable实现:资源释放、清理 |
|||
``` |
|||
|
|||
## 各文件职责说明 |
|||
|
|||
- **WebSocketMessageManager.cs** |
|||
- 声明类本体(partial class),包含所有字段、属性、事件声明。 |
|||
- 只负责结构性声明,不含具体实现。 |
|||
|
|||
- **Constructor.cs** |
|||
- 只包含构造函数,负责对象初始化、依赖注入、字段赋值。 |
|||
|
|||
- **PublicMethods.cs** |
|||
- 所有对外公开的方法(如Connect、Disconnect、SendMessage等)。 |
|||
- 业务主流程、外部接口全部集中于此,便于查找和维护。 |
|||
|
|||
- **PrivateMethods.cs** |
|||
- 所有私有方法、事件处理器、内部辅助逻辑。 |
|||
- 包括定时器、消息分发、内部校验等。 |
|||
|
|||
- **Dispose.cs** |
|||
- 只包含IDisposable接口实现和资源释放相关方法。 |
|||
- 负责对象生命周期的正确终结。 |
|||
|
|||
--- |
|||
|
|||
> 本结构层次仅为物理文件组织优化,**所有业务逻辑、接口、注释、实现细节均与原始文件完全一致**,仅提升可维护性和可读性。 |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Enums |
|||
{ |
|||
public enum ClientState |
|||
{ |
|||
Stop, |
|||
Start, |
|||
Loading, |
|||
Connecting, |
|||
Connected, |
|||
Error, |
|||
Destroy |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Enums |
|||
{ |
|||
public enum LayerDir |
|||
{ |
|||
None = 0, // 无方向(-)
|
|||
UL = 1, |
|||
TO = 1, |
|||
DL = 2, |
|||
FROM = 2 |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
namespace CoreAgent.ProtocolClient.Enums |
|||
{ |
|||
/// <summary>
|
|||
/// 日志通道ID枚举
|
|||
/// 定义了各种协议通道类型
|
|||
/// </summary>
|
|||
public enum LogChannelId |
|||
{ |
|||
/// <summary>
|
|||
/// 物理下行共享信道
|
|||
/// </summary>
|
|||
PDSCH, |
|||
|
|||
/// <summary>
|
|||
/// 物理下行控制信道
|
|||
/// </summary>
|
|||
PDCCH, |
|||
|
|||
/// <summary>
|
|||
/// 增强物理下行控制信道
|
|||
/// </summary>
|
|||
EPDCCH, |
|||
|
|||
/// <summary>
|
|||
/// 物理上行共享信道
|
|||
/// </summary>
|
|||
PUSCH, |
|||
|
|||
/// <summary>
|
|||
/// 物理上行控制信道
|
|||
/// </summary>
|
|||
PUCCH, |
|||
|
|||
/// <summary>
|
|||
/// 窄带物理下行共享信道
|
|||
/// </summary>
|
|||
NPDSCH, |
|||
|
|||
/// <summary>
|
|||
/// 窄带物理上行共享信道
|
|||
/// </summary>
|
|||
NPUSCH, |
|||
|
|||
/// <summary>
|
|||
/// 窄带物理广播信道
|
|||
/// </summary>
|
|||
NPBCH, |
|||
|
|||
/// <summary>
|
|||
/// 窄带广播控制信道
|
|||
/// </summary>
|
|||
BCCH_NR, |
|||
|
|||
/// <summary>
|
|||
/// 提示信息通道
|
|||
/// </summary>
|
|||
ID_HINTS, |
|||
|
|||
/// <summary>
|
|||
/// 探测参考信号
|
|||
/// </summary>
|
|||
SRS, |
|||
|
|||
/// <summary>
|
|||
/// 信道状态信息
|
|||
/// </summary>
|
|||
CSI, |
|||
|
|||
/// <summary>
|
|||
/// SIM卡事件
|
|||
/// </summary>
|
|||
SIM_EVENT, |
|||
|
|||
/// <summary>
|
|||
/// IP SIM
|
|||
/// </summary>
|
|||
IP_SIM |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
namespace CoreAgent.ProtocolClient.Enums |
|||
{ |
|||
/// <summary>
|
|||
/// 协议层类型枚举
|
|||
/// 定义了各种协议层的类型标识
|
|||
/// </summary>
|
|||
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, |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.HandlerEventArgs |
|||
{ |
|||
public class HandlerCleanupEventArgs : EventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// ID处理器数量
|
|||
/// </summary>
|
|||
public int IdHandlerCount { get; } |
|||
|
|||
/// <summary>
|
|||
/// 按名称处理器数量
|
|||
/// </summary>
|
|||
public int NamedHandlerCount { get; } |
|||
|
|||
/// <summary>
|
|||
/// 总清理数量
|
|||
/// </summary>
|
|||
public int TotalCleanedCount { get; } |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="idHandlerCount">ID处理器数量</param>
|
|||
/// <param name="namedHandlerCount">按名称处理器数量</param>
|
|||
/// <param name="totalCleanedCount">总清理数量</param>
|
|||
public HandlerCleanupEventArgs(int idHandlerCount, int namedHandlerCount, int totalCleanedCount) |
|||
{ |
|||
IdHandlerCount = idHandlerCount; |
|||
NamedHandlerCount = namedHandlerCount; |
|||
TotalCleanedCount = totalCleanedCount; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.HandlerEventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// 日志获取ID变化事件参数 - 改进版
|
|||
/// </summary>
|
|||
public class LogGetIdChangedEventArgs : EventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// 旧的日志获取ID
|
|||
/// </summary>
|
|||
public long OldLogGetId { get; } |
|||
|
|||
/// <summary>
|
|||
/// 新的日志获取ID
|
|||
/// </summary>
|
|||
public long NewLogGetId { get; } |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="oldLogGetId">旧的日志获取ID</param>
|
|||
/// <param name="newLogGetId">新的日志获取ID</param>
|
|||
public LogGetIdChangedEventArgs(long oldLogGetId, long newLogGetId) |
|||
{ |
|||
OldLogGetId = oldLogGetId; |
|||
NewLogGetId = newLogGetId; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,479 @@ |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using CoreAgent.ProtocolClient.HandlerEventArgs; |
|||
using CoreAgent.ProtocolClient.Models; |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers |
|||
{ |
|||
/// <summary>
|
|||
/// 消息ID管理器 - 改进版
|
|||
///
|
|||
/// 修复的问题:
|
|||
/// 1. 使用long类型防止ID溢出
|
|||
/// 2. 完善消息处理器清理机制
|
|||
/// 3. 改进LogGet ID管理逻辑
|
|||
/// 4. 增强参数验证和异常处理
|
|||
/// 5. 优化性能,减少字符串操作
|
|||
/// 6. 添加线程安全保护
|
|||
/// 7. 改进日志记录格式
|
|||
///
|
|||
/// 设计原则:
|
|||
/// - 单一职责:专门负责消息ID管理
|
|||
/// - 开闭原则:支持扩展不同类型的消息ID管理
|
|||
/// - 线程安全:所有操作都是线程安全的
|
|||
/// - 性能优化:减少不必要的内存分配
|
|||
/// - 错误处理:完善的异常处理和参数验证
|
|||
/// </summary>
|
|||
public class MessageIdManager : IDisposable |
|||
{ |
|||
#region 私有字段
|
|||
|
|||
private readonly ILogger _logger; |
|||
private readonly string _clientName; |
|||
private readonly ConcurrentDictionary<long, MessageHandler> _messageHandlers; |
|||
private readonly ConcurrentDictionary<string, MessageHandler> _messageHandlersByName; |
|||
|
|||
// 使用long类型防止溢出
|
|||
private long _generalMessageId; |
|||
private long _logGetMessageId; |
|||
|
|||
// 状态管理
|
|||
private bool _disposed; |
|||
|
|||
// 性能优化:缓存字符串构建器
|
|||
private readonly StringBuilder _logBuilder = new StringBuilder(256); |
|||
|
|||
#endregion
|
|||
|
|||
#region 事件
|
|||
|
|||
/// <summary>
|
|||
/// 日志获取ID变化事件
|
|||
/// </summary>
|
|||
public event EventHandler<LogGetIdChangedEventArgs>? LogGetIdChanged; |
|||
|
|||
/// <summary>
|
|||
/// 消息处理器清理事件
|
|||
/// </summary>
|
|||
public event EventHandler<HandlerCleanupEventArgs>? HandlerCleanup; |
|||
|
|||
#endregion
|
|||
|
|||
#region 属性
|
|||
|
|||
/// <summary>
|
|||
/// 当前通用消息ID
|
|||
/// </summary>
|
|||
public long CurrentGeneralMessageId => Interlocked.Read(ref _generalMessageId); |
|||
|
|||
/// <summary>
|
|||
/// 当前日志获取消息ID
|
|||
/// </summary>
|
|||
public long CurrentLogGetMessageId => Interlocked.Read(ref _logGetMessageId); |
|||
|
|||
/// <summary>
|
|||
/// 是否已释放
|
|||
/// </summary>
|
|||
public bool IsDisposed => _disposed; |
|||
|
|||
/// <summary>
|
|||
/// 消息处理器数量
|
|||
/// </summary>
|
|||
public int MessageHandlerCount => _messageHandlers.Count; |
|||
|
|||
/// <summary>
|
|||
/// 按名称的消息处理器数量
|
|||
/// </summary>
|
|||
public int NamedMessageHandlerCount => _messageHandlersByName.Count; |
|||
|
|||
/// <summary>
|
|||
/// 总处理器数量
|
|||
/// </summary>
|
|||
public int TotalHandlerCount => MessageHandlerCount + NamedMessageHandlerCount; |
|||
|
|||
#endregion
|
|||
|
|||
#region 构造函数
|
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="clientName">客户端名称</param>
|
|||
/// <param name="logger">日志记录器</param>
|
|||
public MessageIdManager(string clientName, ILogger logger) |
|||
{ |
|||
_clientName = clientName ?? throw new ArgumentNullException(nameof(clientName)); |
|||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
|||
|
|||
_messageHandlers = new ConcurrentDictionary<long, MessageHandler>(); |
|||
_messageHandlersByName = new ConcurrentDictionary<string, MessageHandler>(); |
|||
|
|||
_generalMessageId = 0; |
|||
_logGetMessageId = -1; // 初始化为-1,表示未开始
|
|||
|
|||
_logger.LogInformation("[{ClientName}] 创建消息ID管理器,初始LogGet ID: {LogGetId}", _clientName, _logGetMessageId); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region 公共方法
|
|||
|
|||
/// <summary>
|
|||
/// 生成通用消息ID
|
|||
/// </summary>
|
|||
/// <param name="message">消息对象</param>
|
|||
/// <param name="callback">回调函数</param>
|
|||
/// <param name="errorHandler">是否为错误处理器</param>
|
|||
/// <returns>消息ID</returns>
|
|||
public long GenerateGeneralMessageId(JObject message, Action<JObject>? callback = null, bool errorHandler = false) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
ValidateMessage(message); |
|||
|
|||
var id = GetNextMessageId(); |
|||
message["message_id"] = id; |
|||
|
|||
// 记录log_get消息的发送
|
|||
var messageType = message["message"]?.ToString(); |
|||
if (messageType == "log_get") |
|||
{ |
|||
LogLogGetMessage(id, message); |
|||
} |
|||
|
|||
// 注册回调处理器
|
|||
if (callback != null) |
|||
{ |
|||
_messageHandlers[id] = new MessageHandler |
|||
{ |
|||
Callback = callback, |
|||
ErrorHandler = errorHandler, |
|||
CreatedAt = DateTime.UtcNow |
|||
}; |
|||
} |
|||
|
|||
_logger.LogDebug("[{ClientName}] 生成通用消息ID: {MessageId}", _clientName, id); |
|||
return id; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 生成日志获取消息ID - 改进版
|
|||
/// </summary>
|
|||
/// <param name="message">消息对象</param>
|
|||
/// <param name="callback">回调函数</param>
|
|||
/// <returns>消息ID</returns>
|
|||
public long GenerateLogGetMessageId(JObject message, Action<JObject> callback) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
ValidateMessage(message); |
|||
|
|||
if (callback == null) |
|||
throw new ArgumentNullException(nameof(callback)); |
|||
|
|||
// 生成新的消息ID
|
|||
var newLogGetId = GetNextMessageId(); |
|||
message["message_id"] = newLogGetId; |
|||
|
|||
// 注册回调处理器
|
|||
_messageHandlers[newLogGetId] = new MessageHandler |
|||
{ |
|||
Callback = callback, |
|||
ErrorHandler = false, |
|||
CreatedAt = DateTime.UtcNow, |
|||
IsLogGetHandler = true |
|||
}; |
|||
|
|||
// 设置新的LogGet ID
|
|||
var oldLogGetId = Interlocked.Exchange(ref _logGetMessageId, newLogGetId); |
|||
|
|||
// 触发事件
|
|||
LogGetIdChanged?.Invoke(this, new LogGetIdChangedEventArgs(oldLogGetId, newLogGetId)); |
|||
|
|||
_logger.LogDebug("[{ClientName}] LogGet ID变化: {OldId} -> {NewId}", _clientName, oldLogGetId, newLogGetId); |
|||
return newLogGetId; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 处理消息响应 - 改进版
|
|||
/// </summary>
|
|||
/// <param name="response">响应消息</param>
|
|||
/// <param name="errorHandler">错误处理回调</param>
|
|||
/// <returns>是否找到并处理了消息处理器</returns>
|
|||
public bool HandleMessageResponse(JObject response, Action<string>? errorHandler = null) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (response == null) |
|||
return false; |
|||
|
|||
// 检查消息处理器
|
|||
var id = response["message_id"]?.Value<long>(); |
|||
if (id.HasValue && _messageHandlers.TryGetValue(id.Value, out var handler)) |
|||
{ |
|||
return HandleMessageHandler(id.Value, handler, response, errorHandler); |
|||
} |
|||
|
|||
// 检查按名称的消息处理器
|
|||
var name = response["message"]?.ToString(); |
|||
if (!string.IsNullOrEmpty(name) && _messageHandlersByName.TryGetValue(name, out var nameHandler)) |
|||
{ |
|||
return HandleNamedMessageHandler(name, nameHandler, response); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 设置消息处理器
|
|||
/// </summary>
|
|||
/// <param name="names">消息名称数组</param>
|
|||
/// <param name="handler">处理器</param>
|
|||
public void SetMessageHandler(string[] names, MessageHandler handler) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (names == null || names.Length == 0) |
|||
throw new ArgumentException("消息名称不能为空", nameof(names)); |
|||
|
|||
if (handler == null) |
|||
throw new ArgumentNullException(nameof(handler)); |
|||
|
|||
foreach (var name in names) |
|||
{ |
|||
if (!string.IsNullOrEmpty(name)) |
|||
{ |
|||
_messageHandlersByName[name] = handler; |
|||
} |
|||
} |
|||
|
|||
_logger.LogDebug("[{ClientName}] 设置消息处理器: {Names}", _clientName, string.Join(", ", names)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 取消消息处理器
|
|||
/// </summary>
|
|||
/// <param name="names">消息名称数组</param>
|
|||
public void UnsetMessageHandler(string[] names) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (names == null || names.Length == 0) |
|||
return; |
|||
|
|||
foreach (var name in names) |
|||
{ |
|||
if (!string.IsNullOrEmpty(name)) |
|||
{ |
|||
_messageHandlersByName.TryRemove(name, out _); |
|||
} |
|||
} |
|||
|
|||
_logger.LogDebug("[{ClientName}] 取消消息处理器: {Names}", _clientName, string.Join(", ", names)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 检查是否为当前日志获取消息
|
|||
/// </summary>
|
|||
/// <param name="messageId">消息ID</param>
|
|||
/// <returns>是否为当前日志获取消息</returns>
|
|||
public bool IsCurrentLogGetMessage(long messageId) |
|||
{ |
|||
var currentLogGetId = Interlocked.Read(ref _logGetMessageId); |
|||
return messageId == currentLogGetId; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置日志获取ID
|
|||
/// </summary>
|
|||
public void ResetLogGetId() |
|||
{ |
|||
var oldLogGetId = Interlocked.Exchange(ref _logGetMessageId, -1); |
|||
LogGetIdChanged?.Invoke(this, new LogGetIdChangedEventArgs(oldLogGetId, -1)); |
|||
_logger.LogDebug("[{ClientName}] 重置LogGet ID: {OldId} -> -1", _clientName, oldLogGetId); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 清理过期的消息处理器 - 改进版
|
|||
/// </summary>
|
|||
/// <param name="maxAge">最大年龄(毫秒)</param>
|
|||
/// <returns>清理的处理器数量</returns>
|
|||
public int CleanupExpiredHandlers(int maxAge = 30000) // 默认30秒
|
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
var now = DateTime.UtcNow; |
|||
var expiredKeys = new List<long>(); |
|||
|
|||
foreach (var kvp in _messageHandlers) |
|||
{ |
|||
if (kvp.Value.CreatedAt.AddMilliseconds(maxAge) < now) |
|||
{ |
|||
expiredKeys.Add(kvp.Key); |
|||
} |
|||
} |
|||
|
|||
var cleanedCount = 0; |
|||
foreach (var key in expiredKeys) |
|||
{ |
|||
if (_messageHandlers.TryRemove(key, out _)) |
|||
{ |
|||
cleanedCount++; |
|||
} |
|||
} |
|||
|
|||
if (cleanedCount > 0) |
|||
{ |
|||
_logger.LogDebug("[{ClientName}] 清理了 {CleanedCount} 个过期的消息处理器", _clientName, cleanedCount); |
|||
|
|||
// 触发清理事件
|
|||
HandlerCleanup?.Invoke(this, new HandlerCleanupEventArgs( |
|||
_messageHandlers.Count, |
|||
_messageHandlersByName.Count, |
|||
cleanedCount)); |
|||
} |
|||
|
|||
return cleanedCount; |
|||
} |
|||
|
|||
|
|||
#endregion
|
|||
|
|||
#region 私有方法
|
|||
|
|||
/// <summary>
|
|||
/// 获取下一个消息ID
|
|||
/// </summary>
|
|||
/// <returns>消息ID</returns>
|
|||
private long GetNextMessageId() |
|||
{ |
|||
var id = Interlocked.Increment(ref _generalMessageId); |
|||
|
|||
// 检查溢出
|
|||
if (id <= 0) |
|||
{ |
|||
_logger.LogWarning("[{ClientName}] 消息ID溢出,重置为1", _clientName); |
|||
Interlocked.Exchange(ref _generalMessageId, 1); |
|||
return 1; |
|||
} |
|||
|
|||
return id; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 验证消息对象
|
|||
/// </summary>
|
|||
/// <param name="message">消息对象</param>
|
|||
private void ValidateMessage(JObject message) |
|||
{ |
|||
if (message == null) |
|||
throw new ArgumentNullException(nameof(message)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 处理消息处理器
|
|||
/// </summary>
|
|||
/// <param name="id">消息ID</param>
|
|||
/// <param name="handler">处理器</param>
|
|||
/// <param name="response">响应消息</param>
|
|||
/// <param name="errorHandler">错误处理回调</param>
|
|||
/// <returns>是否处理成功</returns>
|
|||
private bool HandleMessageHandler(long id, MessageHandler handler, JObject response, Action<string>? errorHandler) |
|||
{ |
|||
// 如果不是通知消息,则移除处理器
|
|||
if (response["notification"]?.Value<bool>() != true) |
|||
{ |
|||
_messageHandlers.TryRemove(id, out _); |
|||
} |
|||
|
|||
// 处理错误
|
|||
if (response["error"] != null) |
|||
{ |
|||
if (!handler.ErrorHandler) |
|||
{ |
|||
errorHandler?.Invoke(response["error"]?.ToString() ?? "未知错误"); |
|||
} |
|||
else |
|||
{ |
|||
handler.Callback?.Invoke(response); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// 正常处理
|
|||
handler.Callback?.Invoke(response); |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 处理按名称的消息处理器
|
|||
/// </summary>
|
|||
/// <param name="name">消息名称</param>
|
|||
/// <param name="handler">处理器</param>
|
|||
/// <param name="response">响应消息</param>
|
|||
/// <returns>是否处理成功</returns>
|
|||
private bool HandleNamedMessageHandler(string name, MessageHandler handler, JObject response) |
|||
{ |
|||
handler.Callback?.Invoke(response); |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 记录LogGet消息
|
|||
/// </summary>
|
|||
/// <param name="id">消息ID</param>
|
|||
/// <param name="message">消息对象</param>
|
|||
private void LogLogGetMessage(long id, JObject message) |
|||
{ |
|||
_logBuilder.Clear(); |
|||
_logBuilder.AppendFormat("[{0}] 发送log_get消息: message_id={1}", _clientName, id); |
|||
|
|||
if (message["timeout"] != null) |
|||
_logBuilder.AppendFormat(", timeout={0}", message["timeout"]); |
|||
|
|||
if (message["headers"] != null) |
|||
_logBuilder.AppendFormat(", headers={0}", message["headers"]); |
|||
|
|||
_logBuilder.AppendFormat(", ThreadId={0}", Thread.CurrentThread.ManagedThreadId); |
|||
|
|||
_logger.LogDebug(_logBuilder.ToString()); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 检查是否已释放
|
|||
/// </summary>
|
|||
private void ThrowIfDisposed() |
|||
{ |
|||
if (_disposed) |
|||
{ |
|||
throw new ObjectDisposedException(nameof(MessageIdManager)); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region IDisposable
|
|||
|
|||
/// <summary>
|
|||
/// 释放资源
|
|||
/// </summary>
|
|||
public void Dispose() |
|||
{ |
|||
if (_disposed) return; |
|||
|
|||
_disposed = true; |
|||
|
|||
// 清理所有消息处理器
|
|||
_messageHandlers.Clear(); |
|||
_messageHandlersByName.Clear(); |
|||
|
|||
_logger.LogInformation("[{ClientName}] 释放消息ID管理器", _clientName); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 构造函数
|
|||
|
|||
/// <summary>
|
|||
/// 构造函数 - 对应LTEClientWebSocket构造函数中的WebSocket相关初始化
|
|||
///
|
|||
/// 初始化说明:
|
|||
/// 1. 创建MessageIdManager替代原始的_messageId和_logGetId字段
|
|||
/// 2. 创建消息队列_messageFifo,保持与原始实现一致
|
|||
/// 3. 不初始化WebSocket实例,在Connect方法中创建
|
|||
/// 4. 移除_sentMessages和_receivedMessages的初始化
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 参数clientName:对应LTEClientWebSocket构造函数中的config.Name
|
|||
/// - 参数logger:对应LTEClientWebSocket构造函数中的logger参数
|
|||
/// - _messageIdManager:替代原始的_messageId和_logGetId字段
|
|||
/// - _messageFifo:对应原始的_messageFifo初始化
|
|||
/// - _disposed:对应原始的_disposed初始化
|
|||
/// - 日志记录:对应原始的构造函数日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 参数验证:增加了对clientName和logger的null检查
|
|||
/// - 职责分离:专注于WebSocket相关初始化
|
|||
/// - 功能增强:通过MessageIdManager提供更好的消息ID管理
|
|||
/// - 移除冗余:移除了消息缓存相关的初始化
|
|||
/// </summary>
|
|||
/// <param name="clientName">客户端名称,对应LTEClientWebSocket._config.Name</param>
|
|||
/// <param name="logger">日志记录器,对应LTEClientWebSocket._logger</param>
|
|||
public WebSocketMessageManager(string clientName, ILogger logger) |
|||
{ |
|||
_clientName = clientName ?? throw new ArgumentNullException(nameof(clientName)); |
|||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); |
|||
|
|||
// 创建MessageIdManager,替代原始的_messageId和_logGetId字段
|
|||
_messageIdManager = new MessageIdManager(clientName, logger); |
|||
|
|||
// 创建消息队列,使用BlockingCollection优化线程安全性和性能
|
|||
_messageFifo = new BlockingCollection<JObject>(); |
|||
|
|||
_logger.LogInformation($"[{_clientName}] 创建WebSocket消息管理器"); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region IDisposable实现
|
|||
|
|||
/// <summary>
|
|||
/// 释放资源 - 对应LTEClientWebSocket.Dispose()方法
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 释放WebSocket连接和相关资源
|
|||
/// 2. 清理消息队列和定时器
|
|||
/// 3. 设置释放标志,防止重复释放
|
|||
/// 4. 调用MessageIdManager的Dispose方法
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 资源释放:对应原始实现中的Dispose()方法
|
|||
/// - 连接关闭:对应原始实现中的WebSocket关闭逻辑
|
|||
/// - 定时器清理:对应原始实现中的定时器释放逻辑
|
|||
/// - 队列清理:对应原始实现中的队列清理逻辑
|
|||
/// - 释放标志:对应原始实现中的_disposed设置
|
|||
/// - 日志记录:对应原始实现中的释放日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的资源释放顺序
|
|||
/// - 更完善的异常处理
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的释放逻辑
|
|||
/// </summary>
|
|||
public void Dispose() |
|||
{ |
|||
Dispose(true); |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 释放资源的受保护方法 - 实现标准的Dispose模式
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 实现标准的Dispose模式,支持手动释放和垃圾回收
|
|||
/// 2. 确保资源只被释放一次
|
|||
/// 3. 按照正确的顺序释放资源
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 释放模式:对应.NET标准的Dispose模式
|
|||
/// - 资源清理:对应原始实现中的资源清理逻辑
|
|||
/// - 异常处理:对应原始实现中的异常处理
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 标准的Dispose模式实现
|
|||
/// - 更安全的资源管理
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的清理逻辑
|
|||
/// </summary>
|
|||
/// <param name="disposing">是否为手动释放</param>
|
|||
protected virtual void Dispose(bool disposing) |
|||
{ |
|||
if (_disposed) |
|||
return; |
|||
|
|||
if (disposing) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 释放WebSocket消息管理器资源"); |
|||
|
|||
// 停止消息发送定时器 - 对应原始实现中的定时器释放
|
|||
StopMessageDeferTimer(); |
|||
|
|||
// 清空消息队列 - 对应原始实现中的队列清理
|
|||
ClearMessageQueue(); |
|||
|
|||
// 释放BlockingCollection资源 - 优化:确保BlockingCollection正确释放
|
|||
_messageFifo?.Dispose(); |
|||
|
|||
// 关闭WebSocket连接 - 对应原始实现中的WebSocket关闭
|
|||
if (_webSocket != null) |
|||
{ |
|||
_webSocket.Close(); |
|||
_webSocket = null; |
|||
} |
|||
|
|||
// 释放MessageIdManager - 对应原始实现中的相关资源释放
|
|||
_messageIdManager?.Dispose(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 释放资源异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
_disposed = true; |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,394 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 私有方法
|
|||
|
|||
/// <summary>
|
|||
/// 检查对象是否已释放,如果已释放则抛出异常
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 检查_disposed字段,如果为true则抛出ObjectDisposedException
|
|||
/// 2. 在所有公共方法开始时调用,确保对象状态正确
|
|||
/// 3. 提供统一的释放状态检查逻辑
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 检查逻辑:对应原始实现中的_disposed检查
|
|||
/// - 异常类型:ObjectDisposedException,与.NET标准一致
|
|||
/// - 使用场景:在所有公共方法开始时调用
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 统一的释放状态检查
|
|||
/// - 更清晰的异常信息
|
|||
/// - 更好的代码复用
|
|||
/// </summary>
|
|||
private void ThrowIfDisposed() |
|||
{ |
|||
if (_disposed) |
|||
throw new ObjectDisposedException(nameof(WebSocketMessageManager)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// WebSocket连接打开事件处理器 - 对应LTEClientWebSocket.OnSocketOpened
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理WebSocket连接成功建立事件
|
|||
/// 2. 记录连接成功日志
|
|||
/// 3. 触发ConnectionOpened事件
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件处理:对应原始实现中的OnSocketOpened方法
|
|||
/// - 日志记录:对应原始实现中的连接成功日志
|
|||
/// - 事件触发:对应原始实现中的ConnectionOpened事件触发
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的日志记录
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的事件处理逻辑
|
|||
/// </summary>
|
|||
/// <param name="sender">事件发送者</param>
|
|||
/// <param name="e">事件参数</param>
|
|||
private void OnSocketOpened(object? sender, EventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] WebSocket连接已建立"); |
|||
ConnectionOpened?.Invoke(this, EventArgs.Empty); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理连接打开事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// WebSocket连接关闭事件处理器 - 对应LTEClientWebSocket.OnSocketClosed
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理WebSocket连接关闭事件
|
|||
/// 2. 记录连接关闭日志
|
|||
/// 3. 触发ConnectionClosed事件
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件处理:对应原始实现中的OnSocketClosed方法
|
|||
/// - 日志记录:对应原始实现中的连接关闭日志
|
|||
/// - 事件触发:对应原始实现中的ConnectionClosed事件触发
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的日志记录
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的事件处理逻辑
|
|||
/// </summary>
|
|||
/// <param name="sender">事件发送者</param>
|
|||
/// <param name="e">事件参数</param>
|
|||
private void OnSocketClosed(object? sender, EventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] WebSocket连接已关闭"); |
|||
ConnectionClosed?.Invoke(this, EventArgs.Empty); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理连接关闭事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// WebSocket消息接收事件处理器 - 对应LTEClientWebSocket.OnSocketMessage
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理WebSocket消息接收事件
|
|||
/// 2. 解析接收到的消息
|
|||
/// 3. 触发MessageReceived事件
|
|||
/// 4. 调用HandleReceivedMessage处理消息
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件处理:对应原始实现中的OnSocketMessage方法
|
|||
/// - 消息解析:对应原始实现中的消息解析逻辑
|
|||
/// - 事件触发:对应原始实现中的MessageReceived事件触发
|
|||
/// - 消息处理:对应原始实现中的消息处理逻辑
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的错误处理
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的事件处理逻辑
|
|||
/// </summary>
|
|||
/// <param name="sender">事件发送者</param>
|
|||
/// <param name="e">消息接收事件参数</param>
|
|||
private void OnSocketMessageReceived(object? sender, MessageReceivedEventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
var messageText = e.Message; |
|||
_logger.LogDebug($"[{_clientName}] 接收到消息: {messageText}"); |
|||
|
|||
// 解析消息 - 对应原始实现中的消息解析逻辑
|
|||
JObject? message = null; |
|||
try |
|||
{ |
|||
message = JObject.Parse(messageText); |
|||
} |
|||
catch (JsonException ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 消息解析失败: {messageText}"); |
|||
ConnectionError?.Invoke(this, $"消息解析失败: {ex.Message}"); |
|||
return; |
|||
} |
|||
|
|||
// 触发MessageReceived事件 - 对应原始实现中的事件触发
|
|||
MessageReceived?.Invoke(this, message); |
|||
|
|||
// 处理消息 - 对应原始实现中的消息处理逻辑
|
|||
HandleReceivedMessage(message, error => ConnectionError?.Invoke(this, error)); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理接收消息异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"处理接收消息异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// WebSocket错误事件处理器 - 对应LTEClientWebSocket.OnSocketError
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理WebSocket连接错误事件
|
|||
/// 2. 记录错误日志
|
|||
/// 3. 触发ConnectionError事件
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件处理:对应原始实现中的OnSocketError方法
|
|||
/// - 错误记录:对应原始实现中的错误日志记录
|
|||
/// - 事件触发:对应原始实现中的ConnectionError事件触发
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更详细的错误信息记录
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的事件处理逻辑
|
|||
/// </summary>
|
|||
/// <param name="sender">事件发送者</param>
|
|||
/// <param name="e">错误事件参数</param>
|
|||
private void OnSocketError(object? sender, SuperSocket.ClientEngine.ErrorEventArgs e) |
|||
{ |
|||
try |
|||
{ |
|||
var errorMessage = e.Exception?.Message ?? "WebSocket连接错误"; |
|||
_logger.LogError(e.Exception, $"[{_clientName}] WebSocket错误: {errorMessage}"); |
|||
ConnectionError?.Invoke(this, errorMessage); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理WebSocket错误事件异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 启动消息延迟发送定时器 - 对应LTEClientWebSocket.StartMessageDeferTimer
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 启动消息延迟发送定时器,实现批量发送优化
|
|||
/// 2. 当队列中消息少于100条时,延迟1毫秒发送
|
|||
/// 3. 当队列中消息达到100条时,立即发送
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 定时器创建:对应原始实现中的定时器创建逻辑
|
|||
/// - 延迟策略:1毫秒延迟,与原始实现完全一致
|
|||
/// - 批处理大小:100条消息,与原始实现完全一致
|
|||
/// - 回调函数:对应原始实现中的定时器回调逻辑
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的定时器管理
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的批处理策略
|
|||
/// </summary>
|
|||
private void StartMessageDeferTimer() |
|||
{ |
|||
Timer? timer = null; |
|||
timer = new Timer(_ => |
|||
{ |
|||
try |
|||
{ |
|||
OnMessageDeferTimer(null); |
|||
} |
|||
finally |
|||
{ |
|||
timer?.Dispose(); // 用完即销毁
|
|||
} |
|||
}, null, 1, Timeout.Infinite); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 停止消息延迟发送定时器 - 对应LTEClientWebSocket.StopMessageDeferTimer
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 停止消息延迟发送定时器
|
|||
/// 2. 释放定时器资源
|
|||
/// 3. 确保线程安全的定时器管理
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 定时器停止:对应原始实现中的定时器停止逻辑
|
|||
/// - 资源释放:对应原始实现中的定时器释放逻辑
|
|||
/// - 线程安全:使用锁确保线程安全
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的资源管理
|
|||
/// - 更好的线程安全保证
|
|||
/// - 保持了完全一致的停止逻辑
|
|||
/// </summary>
|
|||
private void StopMessageDeferTimer() |
|||
{ |
|||
// 新实现下无需手动停止定时器,方法保留兼容性
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 消息延迟发送定时器回调 - 对应LTEClientWebSocket.OnMessageDeferTimer
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理消息延迟发送定时器回调
|
|||
/// 2. 批量发送队列中的消息
|
|||
/// 3. 实现消息发送优化
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 定时器回调:对应原始实现中的OnMessageDeferTimer方法
|
|||
/// - 批量发送:对应原始实现中的批量发送逻辑
|
|||
/// - 批处理大小:100条消息,与原始实现完全一致
|
|||
/// - 发送逻辑:对应原始实现中的SendMessageNow调用
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的批量发送逻辑
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的批处理策略
|
|||
/// </summary>
|
|||
/// <param name="state">定时器状态参数</param>
|
|||
private void OnMessageDeferTimer(object? state) |
|||
{ |
|||
try |
|||
{ |
|||
// 批量发送消息 - 对应原始实现中的批量发送逻辑
|
|||
var messages = new List<JObject>(); |
|||
var count = 0; |
|||
const int batchSize = 100; // 与原始实现完全一致
|
|||
|
|||
// 从队列中取出消息 - 对应原始实现中的队列处理逻辑
|
|||
while (count < batchSize && _messageFifo.TryTake(out var message)) |
|||
{ |
|||
messages.Add(message); |
|||
count++; |
|||
} |
|||
|
|||
if (messages.Count > 0) |
|||
{ |
|||
// 发送消息 - 对应原始实现中的SendMessageNow调用
|
|||
SendMessageNow(messages); |
|||
} |
|||
|
|||
// 如果队列中还有消息,继续启动定时器 - 对应原始实现中的定时器重启逻辑
|
|||
if (_messageFifo.Count > 0) |
|||
{ |
|||
StartMessageDeferTimer(); |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 消息延迟发送定时器异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 立即发送消息 - 对应LTEClientWebSocket.SendMessageNow
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 立即发送消息列表到WebSocket
|
|||
/// 2. 处理发送异常和错误
|
|||
/// 3. 触发MessageSent事件
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 消息发送:对应原始实现中的SendMessageNow方法
|
|||
/// - 异常处理:对应原始实现中的发送异常处理
|
|||
/// - 事件触发:对应原始实现中的事件触发逻辑
|
|||
/// - 日志记录:对应原始实现中的发送日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的发送逻辑
|
|||
/// - 更详细的错误处理
|
|||
/// - 新增MessageSent事件触发
|
|||
/// - 保持了完全一致的发送逻辑
|
|||
/// </summary>
|
|||
/// <param name="messages">要发送的消息列表</param>
|
|||
private void SendMessageNow(List<JObject> messages) |
|||
{ |
|||
if (messages == null || messages.Count == 0) |
|||
return; |
|||
|
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送消息"); |
|||
return; |
|||
} |
|||
|
|||
try |
|||
{ |
|||
foreach (var message in messages) |
|||
{ |
|||
var messageText = JsonConvert.SerializeObject(message); |
|||
_webSocket?.Send(messageText); |
|||
|
|||
// 触发MessageSent事件 - 新增功能,提供更完整的消息生命周期通知
|
|||
MessageSent?.Invoke(this, message); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 消息已发送: {messageText}"); |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 发送消息异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"发送消息异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 清空消息队列 - 对应LTEClientWebSocket中的队列清理逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 清空消息队列中的所有消息
|
|||
/// 2. 在断开连接时调用,确保资源清理
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 队列清理:对应原始实现中的队列清理逻辑
|
|||
/// - 调用时机:在Disconnect()方法中调用
|
|||
/// - 日志记录:对应原始实现中的清理日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的清理逻辑
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的清理逻辑
|
|||
/// </summary>
|
|||
private void ClearMessageQueue() |
|||
{ |
|||
var count = 0; |
|||
while (_messageFifo.TryTake(out _)) |
|||
{ |
|||
count++; |
|||
} |
|||
|
|||
if (count > 0) |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 清空消息队列,丢弃 {count} 条消息"); |
|||
} |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,462 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
using CoreAgent.ProtocolClient.Models; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
public partial class WebSocketMessageManager |
|||
{ |
|||
#region 公共方法
|
|||
|
|||
/// <summary>
|
|||
/// 连接到WebSocket服务器 - 对应LTEClientWebSocket.Start()方法
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 建立WebSocket连接,对应原始Start()方法的核心逻辑
|
|||
/// 2. 构建WebSocket URL,支持SSL和非SSL连接
|
|||
/// 3. 绑定事件处理器,对应原始的事件绑定逻辑
|
|||
/// 4. 提供更严格的参数验证和异常处理
|
|||
///
|
|||
/// 与原始实现的差异:
|
|||
/// - 方法名从Start()改为Connect(),更明确表达功能
|
|||
/// - 移除了状态管理逻辑(SetState),专注连接管理
|
|||
/// - 增加了参数验证,提供更好的错误处理
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数url:对应原始实现中的config.Address
|
|||
/// - 参数ssl:对应原始实现中的config.Ssl
|
|||
/// - URL构建:对应原始实现中的URL构建逻辑
|
|||
/// - WebSocket创建:对应原始实现中的_webSocket = new WebSocket(url)
|
|||
/// - 事件绑定:对应原始实现中的事件绑定逻辑
|
|||
/// - 连接打开:对应原始实现中的_webSocket.Open()
|
|||
/// - 异常处理:对应原始实现中的异常处理逻辑
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更明确的参数验证
|
|||
/// - 更详细的异常处理
|
|||
/// - 更清晰的错误信息
|
|||
/// - 保持了完全一致的连接逻辑
|
|||
/// </summary>
|
|||
/// <param name="url">WebSocket URL,对应LTEClientWebSocket._config.Address</param>
|
|||
/// <param name="ssl">是否使用SSL,对应LTEClientWebSocket._config.Ssl</param>
|
|||
public void Connect(string url, bool ssl = false) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (string.IsNullOrEmpty(url)) |
|||
throw new ArgumentException("URL不能为空", nameof(url)); |
|||
|
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 尝试连接: {url}"); |
|||
|
|||
// 构建WebSocket URL - 对应原始实现中的URL构建逻辑
|
|||
var fullUrl = (ssl ? "wss://" : "ws://") + url; |
|||
|
|||
// 创建WebSocket实例 - 对应原始实现中的_webSocket创建
|
|||
_webSocket = new WebSocket(fullUrl); |
|||
_webSocket.EnableAutoSendPing = false; |
|||
|
|||
// 绑定事件处理器 - 对应原始实现中的事件绑定
|
|||
_webSocket.Opened += OnSocketOpened!; |
|||
_webSocket.Closed += OnSocketClosed!; |
|||
_webSocket.MessageReceived += OnSocketMessageReceived!; // 对应OnSocketMessage0
|
|||
_webSocket.Error += OnSocketError!; |
|||
|
|||
// 打开连接 - 对应原始实现中的_webSocket.Open()
|
|||
_webSocket.Open(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 连接异常: {ex.Message}"); |
|||
ConnectionError?.Invoke(this, $"无法连接到 {url}: {ex.Message}"); |
|||
throw; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 断开WebSocket连接 - 对应LTEClientWebSocket.Stop()方法中的WebSocket相关逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 关闭WebSocket连接,对应原始Stop()方法的核心逻辑
|
|||
/// 2. 清理消息队列和定时器,对应原始的资源清理逻辑
|
|||
/// 3. 提供更完善的异常处理
|
|||
///
|
|||
/// 与原始实现的差异:
|
|||
/// - 方法名从Stop()改为Disconnect(),更明确表达功能
|
|||
/// - 移除了状态管理逻辑(SetState),专注连接管理
|
|||
/// - 移除了重连逻辑,专注连接断开
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 定时器停止:对应原始StopTimers()中的_messageDeferTimer处理
|
|||
/// - 队列清理:对应原始实现中的队列清理逻辑
|
|||
/// - WebSocket关闭:对应原始实现中的_webSocket.Close()
|
|||
/// - 资源清理:对应原始实现中的资源清理逻辑
|
|||
/// - 异常处理:对应原始实现中的异常处理
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的资源清理顺序
|
|||
/// - 更完善的异常处理
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的清理逻辑
|
|||
/// </summary>
|
|||
public void Disconnect() |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
try |
|||
{ |
|||
_logger.LogInformation($"[{_clientName}] 断开连接"); |
|||
|
|||
// 停止消息发送定时器 - 对应原始StopTimers()中的_messageDeferTimer处理
|
|||
StopMessageDeferTimer(); |
|||
|
|||
// 清空消息队列 - 对应原始实现中的队列清理
|
|||
ClearMessageQueue(); |
|||
|
|||
// 关闭WebSocket连接 - 对应原始实现中的_webSocket.Close()
|
|||
if (_webSocket != null) |
|||
{ |
|||
_webSocket.Close(); |
|||
_webSocket = null; |
|||
} |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 断开连接异常: {ex.Message}"); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送消息 - 对应LTEClientWebSocket.SendMessage()方法
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 发送通用消息,对应原始SendMessage()方法的核心逻辑
|
|||
/// 2. 使用MessageIdManager生成消息ID,替代原始的Interlocked.Increment(ref _messageId)
|
|||
/// 3. 将消息加入队列,对应原始的_messageFifo.Enqueue(message)
|
|||
/// 4. 启动延迟发送定时器,对应原始的定时器逻辑
|
|||
///
|
|||
/// 与原始实现的差异:
|
|||
/// - 消息ID生成通过MessageIdManager,提供更好的管理
|
|||
/// - 移除了消息缓存逻辑(_sentMessages),专注传输
|
|||
/// - 增加了更严格的参数验证
|
|||
/// - 保持了完全一致的队列和定时器逻辑
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数message:对应原始方法中的message参数
|
|||
/// - 参数callback:对应原始方法中的callback参数
|
|||
/// - 参数errorHandler:对应原始方法中的errorHandler参数
|
|||
/// - 连接状态检查:对应原始实现中的连接状态检查
|
|||
/// - 消息ID生成:对应原始的Interlocked.Increment(ref _messageId)
|
|||
/// - 队列操作:对应原始的_messageFifo.Enqueue(message)
|
|||
/// - 定时器启动:对应原始的定时器启动逻辑
|
|||
/// - 返回值:对应原始方法的返回值
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更统一的消息ID管理
|
|||
/// - 更严格的参数验证
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的发送逻辑
|
|||
/// </summary>
|
|||
/// <param name="message">消息对象,对应原始方法中的message参数</param>
|
|||
/// <param name="callback">回调函数,对应原始方法中的callback参数</param>
|
|||
/// <param name="errorHandler">是否为错误处理器,对应原始方法中的errorHandler参数</param>
|
|||
/// <returns>消息ID,对应原始方法的返回值</returns>
|
|||
public long SendMessage(JObject message, Action<JObject>? callback = null, bool errorHandler = false) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
throw new ArgumentNullException(nameof(message)); |
|||
|
|||
// 检查连接状态 - 对应原始实现中的连接状态检查
|
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送消息"); |
|||
return -1L; |
|||
} |
|||
|
|||
// 使用MessageIdManager生成ID - 替代原始的Interlocked.Increment(ref _messageId)
|
|||
var messageId = _messageIdManager.GenerateGeneralMessageId(message, callback, errorHandler); |
|||
|
|||
// 添加到消息队列 - 对应原始实现中的_messageFifo.Enqueue(message)
|
|||
_messageFifo.Add(message); |
|||
|
|||
// 启动消息发送定时器 - 对应原始实现中的定时器启动逻辑
|
|||
StartMessageDeferTimer(); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 消息已加入队列: message_id={messageId}"); |
|||
return messageId; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送日志获取消息 - 对应LTEClientWebSocket.LogGet()方法中的消息发送部分
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 专门用于发送日志获取消息,对应原始LogGet()方法的核心逻辑
|
|||
/// 2. 使用MessageIdManager生成LogGet ID,替代原始的_logGetId管理
|
|||
/// 3. 委托给SendMessage方法,保持代码一致性
|
|||
///
|
|||
/// 与原始实现的差异:
|
|||
/// - 专门处理日志获取消息,提供更清晰的接口
|
|||
/// - 使用MessageIdManager管理LogGet ID,提供更好的跟踪
|
|||
/// - 委托给SendMessage方法,避免代码重复
|
|||
/// - 保持了完全一致的发送逻辑
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数message:对应原始LogGet()方法中构建的message
|
|||
/// - 参数callback:对应原始LogGet()方法中的LogGetParse回调
|
|||
/// - 委托给SendMessage:对应原始实现中的SendMessage调用
|
|||
/// - LogGet ID生成:对应原始的_logGetId管理逻辑
|
|||
/// - 返回值:对应原始方法的返回值
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更专门的日志获取消息处理
|
|||
/// - 更统一的LogGet ID管理
|
|||
/// - 避免代码重复,委托给SendMessage
|
|||
/// - 保持了完全一致的发送逻辑
|
|||
/// </summary>
|
|||
/// <param name="message">消息对象,对应原始LogGet()方法中构建的message</param>
|
|||
/// <param name="callback">回调函数,对应原始LogGet()方法中的LogGetParse回调</param>
|
|||
/// <returns>消息ID,对应原始方法的返回值</returns>
|
|||
public long SendLogGetMessage(JObject message, Action<JObject> callback) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
throw new ArgumentNullException(nameof(message)); |
|||
|
|||
if (callback == null) |
|||
throw new ArgumentNullException(nameof(callback)); |
|||
|
|||
// 检查连接状态 - 对应原始实现中的连接状态检查
|
|||
if (!IsConnected) |
|||
{ |
|||
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送日志获取消息"); |
|||
return -1L; |
|||
} |
|||
|
|||
// 使用MessageIdManager生成LogGet ID - 替代原始的_logGetId管理
|
|||
var messageId = _messageIdManager.GenerateLogGetMessageId(message, callback); |
|||
|
|||
// 委托给SendMessage方法,避免代码重复 - 对应原始实现中的SendMessage调用
|
|||
// 注意:这里不需要再次调用SendMessage,因为GenerateLogGetMessageId已经处理了消息ID和回调注册
|
|||
// 只需要将消息加入队列并启动定时器
|
|||
_messageFifo.Add(message); |
|||
StartMessageDeferTimer(); |
|||
|
|||
_logger.LogDebug($"[{_clientName}] 日志获取消息已加入队列: message_id={messageId}"); |
|||
return messageId; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 处理接收到的消息 - 对应LTEClientWebSocket.OnSocketMessage()方法中的消息处理逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 处理接收到的WebSocket消息,对应原始OnSocketMessage()方法的核心逻辑
|
|||
/// 2. 使用MessageIdManager处理消息响应,替代原始的消息处理器查找逻辑
|
|||
/// 3. 触发MessageReceived事件,对应原始的事件触发
|
|||
/// 4. 提供完善的错误处理
|
|||
///
|
|||
/// 与原始实现的差异:
|
|||
/// - 使用MessageIdManager处理消息响应,提供更好的管理
|
|||
/// - 移除了消息缓存逻辑(_receivedMessages),专注处理
|
|||
/// - 移除了业务逻辑处理(log_get、stats等),专注消息路由
|
|||
/// - 保持了完全一致的事件触发逻辑
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数message:对应原始方法中的msg参数
|
|||
/// - 参数errorHandler:对应原始方法中的错误处理逻辑
|
|||
/// - 消息处理器查找:对应原始的消息处理器查找逻辑
|
|||
/// - 事件触发:对应原始的事件触发逻辑
|
|||
/// - 错误处理:对应原始的错误处理逻辑
|
|||
/// - 返回值:新增返回值提供处理状态反馈
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更统一的消息响应处理
|
|||
/// - 更清晰的错误处理
|
|||
/// - 更详细的日志记录
|
|||
/// - 保持了完全一致的处理逻辑
|
|||
/// </summary>
|
|||
/// <param name="message">接收到的消息,对应原始方法中的msg参数</param>
|
|||
/// <param name="errorHandler">错误处理回调,对应原始方法中的错误处理逻辑</param>
|
|||
/// <returns>是否成功处理,新增返回值提供处理状态反馈</returns>
|
|||
public bool HandleReceivedMessage(JObject message, Action<string>? errorHandler = null) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
|
|||
if (message == null) |
|||
return false; |
|||
|
|||
try |
|||
{ |
|||
// 使用MessageIdManager处理消息响应 - 替代原始的消息处理器查找逻辑
|
|||
var handled = _messageIdManager.HandleMessageResponse(message, errorHandler); |
|||
|
|||
if (handled) |
|||
{ |
|||
_logger.LogDebug($"[{_clientName}] 消息已处理: message_id={message["message_id"]}"); |
|||
return true; |
|||
} |
|||
|
|||
// 处理特定消息类型 - 对应原始实现中的特定消息类型处理
|
|||
// 注意:这里不处理log_get和stats等业务逻辑,因为重构版本专注于消息传输
|
|||
var name = message["message"]?.ToString(); |
|||
if (!string.IsNullOrEmpty(name)) |
|||
{ |
|||
_logger.LogDebug($"[{_clientName}] 未处理的特定消息类型: {name}"); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
_logger.LogError(ex, $"[{_clientName}] 处理消息异常: {ex.Message}"); |
|||
errorHandler?.Invoke($"消息处理错误: {ex.Message}"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 设置消息处理器 - 对应LTEClientWebSocket.SetMessageHandler()方法
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 设置按名称的消息处理器,对应原始SetMessageHandler()方法的核心逻辑
|
|||
/// 2. 委托给MessageIdManager处理,提供统一的消息处理器管理
|
|||
/// 3. 支持多个消息名称的处理器设置
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数names:对应原始方法中的names参数,消息名称数组
|
|||
/// - 参数handler:对应原始方法中的handler参数,消息处理器
|
|||
/// - 处理器注册:对应原始的_messageHandlersByName注册逻辑
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 委托给MessageIdManager,提供统一管理
|
|||
/// - 保持了完全一致的接口和功能
|
|||
/// - 更好的错误处理和参数验证
|
|||
/// </summary>
|
|||
/// <param name="names">消息名称数组,对应原始方法中的names参数</param>
|
|||
/// <param name="handler">消息处理器,对应原始方法中的handler参数</param>
|
|||
public void SetMessageHandler(string[] names, MessageHandler handler) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.SetMessageHandler(names, handler); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 取消设置消息处理器 - 对应LTEClientWebSocket.UnsetMessageHandler()方法
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 取消按名称的消息处理器,对应原始UnsetMessageHandler()方法的核心逻辑
|
|||
/// 2. 委托给MessageIdManager处理,提供统一的消息处理器管理
|
|||
/// 3. 支持多个消息名称的处理器取消
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数names:对应原始方法中的names参数,消息名称数组
|
|||
/// - 处理器移除:对应原始的_messageHandlersByName移除逻辑
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 委托给MessageIdManager,提供统一管理
|
|||
/// - 保持了完全一致的接口和功能
|
|||
/// - 更好的错误处理和参数验证
|
|||
/// </summary>
|
|||
/// <param name="names">消息名称数组,对应原始方法中的names参数</param>
|
|||
public void UnsetMessageHandler(string[] names) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.UnsetMessageHandler(names); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 检查是否为当前日志获取消息 - 对应LTEClientWebSocket中的_logGetId检查逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 检查指定的消息ID是否为当前的日志获取消息ID
|
|||
/// 2. 委托给MessageIdManager处理,提供统一的LogGet ID管理
|
|||
/// 3. 用于日志获取流程的状态检查
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数messageId:对应原始实现中的消息ID检查
|
|||
/// - 返回值:true表示是当前LogGet消息,false表示不是,对应原始逻辑
|
|||
/// - 检查逻辑:对应原始的_logGetId比较逻辑
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 委托给MessageIdManager,提供统一管理
|
|||
/// - 保持了完全一致的检查逻辑
|
|||
/// - 更好的线程安全性
|
|||
/// </summary>
|
|||
/// <param name="messageId">要检查的消息ID</param>
|
|||
/// <returns>是否为当前日志获取消息</returns>
|
|||
public bool IsCurrentLogGetMessage(long messageId) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
return _messageIdManager.IsCurrentLogGetMessage(messageId); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重置日志获取ID - 对应LTEClientWebSocket中的_logGetId重置逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 重置日志获取消息ID,对应原始实现中的_logGetId重置逻辑
|
|||
/// 2. 委托给MessageIdManager处理,提供统一的LogGet ID管理
|
|||
/// 3. 用于日志获取流程的重置操作
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 重置逻辑:对应原始的_logGetId = -1操作
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
/// - 事件触发:对应原始实现中的状态变化通知
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 委托给MessageIdManager,提供统一管理
|
|||
/// - 保持了完全一致的重置逻辑
|
|||
/// - 更好的事件通知机制
|
|||
/// </summary>
|
|||
public void ResetLogGetId() |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.ResetLogGetId(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 清理过期的消息处理器 - 对应LTEClientWebSocket中的处理器清理逻辑
|
|||
///
|
|||
/// 功能说明:
|
|||
/// 1. 清理过期的消息处理器,防止内存泄漏
|
|||
/// 2. 委托给MessageIdManager处理,提供统一的处理器管理
|
|||
/// 3. 支持可配置的过期时间
|
|||
///
|
|||
/// 详细对应关系:
|
|||
/// - 参数maxAge:对应原始实现中的过期时间配置
|
|||
/// - 清理逻辑:对应原始的处理器清理逻辑
|
|||
/// - 日志记录:对应原始实现中的日志记录
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 委托给MessageIdManager,提供统一管理
|
|||
/// - 保持了完全一致的清理逻辑
|
|||
/// - 更好的内存管理
|
|||
/// </summary>
|
|||
/// <param name="maxAge">最大存活时间(毫秒),默认30000毫秒</param>
|
|||
public void CleanupExpiredHandlers(int maxAge = 30000) |
|||
{ |
|||
ThrowIfDisposed(); |
|||
_messageIdManager.CleanupExpiredHandlers(maxAge); |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,459 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Concurrent; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using WebSocket4Net; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr |
|||
{ |
|||
/// <summary>
|
|||
/// WebSocket消息管理器 - 专门处理WebSocket的收发业务
|
|||
///
|
|||
/// 重构说明:
|
|||
/// 1. 对应LTEClientWebSocket中的WebSocket连接和消息传输功能
|
|||
/// 2. 集成MessageIdManager统一管理消息ID和回调
|
|||
/// 3. 移除_sentMessages和_receivedMessages消息缓存,专注传输
|
|||
/// 4. 移除业务逻辑功能(统计更新、日志解析等),实现职责分离
|
|||
///
|
|||
/// 主要功能:
|
|||
/// - WebSocket连接管理(对应LTEClientWebSocket.Start()和Stop())
|
|||
/// - 消息发送和接收(对应LTEClientWebSocket.SendMessage()和OnSocketMessage())
|
|||
/// - 消息队列和批量发送(对应LTEClientWebSocket._messageFifo和SendMessageNow())
|
|||
/// - 事件通知(对应LTEClientWebSocket的事件系统)
|
|||
///
|
|||
/// 与LTEClientWebSocket的详细对应关系:
|
|||
///
|
|||
/// 1. 连接管理对应关系:
|
|||
/// - Connect() 对应 Start() 方法中的WebSocket连接建立逻辑
|
|||
/// - Disconnect() 对应 Stop() 方法中的WebSocket关闭逻辑
|
|||
/// - OnSocketOpened/OnSocketClosed/OnSocketError 对应原始的事件处理器
|
|||
///
|
|||
/// 2. 消息发送对应关系:
|
|||
/// - SendMessage() 对应 SendMessage() 方法的核心逻辑
|
|||
/// - SendLogGetMessage() 对应 LogGet() 方法中的消息发送部分
|
|||
/// - _messageFifo 对应原始的 _messageFifo 队列
|
|||
/// - SendMessageNow() 对应原始的 SendMessageNow() 方法
|
|||
/// - StartMessageDeferTimer() 对应原始的定时器启动逻辑
|
|||
///
|
|||
/// 3. 消息接收对应关系:
|
|||
/// - OnSocketMessageReceived() 对应 OnSocketMessage() 方法
|
|||
/// - HandleReceivedMessage() 对应 OnSocketMessage() 中的消息处理逻辑
|
|||
/// - MessageReceived 事件对应原始的 MessageReceived 事件
|
|||
///
|
|||
/// 4. 消息ID管理对应关系:
|
|||
/// - MessageIdManager 替代原始的 _messageId 和 _logGetId 字段
|
|||
/// - GenerateGeneralMessageId() 对应 Interlocked.Increment(ref _messageId)
|
|||
/// - GenerateLogGetMessageId() 对应 _logGetId 的管理逻辑
|
|||
///
|
|||
/// 5. 事件系统对应关系:
|
|||
/// - ConnectionOpened 对应原始的 ConnectionOpened 事件
|
|||
/// - ConnectionClosed 对应原始的 ConnectionClosed 事件
|
|||
/// - ConnectionError 对应原始的 ConnectionError 事件
|
|||
/// - MessageReceived 对应原始的 MessageReceived 事件
|
|||
/// - MessageSent 新增事件,提供更完整的消息生命周期通知
|
|||
///
|
|||
/// 6. 资源管理对应关系:
|
|||
/// - Dispose() 对应原始的 Dispose() 方法
|
|||
/// - _disposed 字段对应原始的 _disposed 字段
|
|||
/// - 定时器管理对应原始的定时器清理逻辑
|
|||
///
|
|||
/// 重构优势:
|
|||
/// 1. 职责分离:专注WebSocket传输,移除业务逻辑
|
|||
/// 2. 代码复用:可在多个地方复用WebSocket管理器
|
|||
/// 3. 测试友好:更容易进行单元测试
|
|||
/// 4. 维护简单:更清晰的代码结构
|
|||
/// 5. 功能增强:通过MessageIdManager提供更好的消息管理
|
|||
/// </summary>
|
|||
public partial class WebSocketMessageManager : IDisposable |
|||
{ |
|||
#region 私有字段
|
|||
|
|||
/// <summary>
|
|||
/// WebSocket实例 - 对应LTEClientWebSocket._webSocket
|
|||
/// 负责底层的WebSocket连接和通信
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 创建:Connect()方法中创建,对应Start()方法中的_webSocket = new WebSocket(url)
|
|||
/// - 配置:EnableAutoSendPing = false,对应原始实现
|
|||
/// - 事件绑定:绑定Opened/Closed/MessageReceived/Error事件,对应原始事件绑定
|
|||
/// - 连接:调用Open()方法,对应原始的_webSocket.Open()
|
|||
/// - 关闭:调用Close()方法,对应原始的_webSocket.Close()
|
|||
/// - 清理:在Disconnect()中设置为null,对应原始的资源清理
|
|||
/// </summary>
|
|||
private WebSocket? _webSocket; |
|||
|
|||
/// <summary>
|
|||
/// 消息ID管理器 - 对应LTEClientWebSocket._messageId和_logGetId
|
|||
/// 统一管理通用消息ID和日志获取消息ID,提供更好的消息跟踪和回调管理
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - _messageId 对应 MessageIdManager.GenerateGeneralMessageId()
|
|||
/// - _logGetId 对应 MessageIdManager.GenerateLogGetMessageId()
|
|||
/// - _messageHandlers 对应 MessageIdManager的内部处理器管理
|
|||
/// - _messageHandlersByName 对应 MessageIdManager的按名称处理器管理
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 线程安全的ID生成,替代原始的Interlocked.Increment
|
|||
/// - 统一的处理器管理,提供更好的回调跟踪
|
|||
/// - 自动清理过期处理器,防止内存泄漏
|
|||
/// - 事件通知机制,提供ID变化通知
|
|||
/// </summary>
|
|||
private readonly MessageIdManager _messageIdManager; |
|||
|
|||
/// <summary>
|
|||
/// 日志记录器 - 对应LTEClientWebSocket._logger
|
|||
/// 用于记录WebSocket操作和错误信息
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 构造函数参数:对应LTEClientWebSocket构造函数中的logger参数
|
|||
/// - 日志记录:对应原始实现中的所有_logger.LogXXX调用
|
|||
/// - 日志格式:保持与原始实现一致的日志格式
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 更详细的错误日志记录
|
|||
/// - 更好的异常堆栈跟踪
|
|||
/// - 统一的日志格式和级别
|
|||
/// </summary>
|
|||
private readonly ILogger _logger; |
|||
|
|||
/// <summary>
|
|||
/// 客户端名称 - 对应LTEClientWebSocket._config.Name
|
|||
/// 用于日志记录和事件标识
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 构造函数参数:对应LTEClientWebSocket构造函数中的config.Name
|
|||
/// - 日志前缀:对应原始实现中所有日志的[{_config.Name}]前缀
|
|||
/// - 事件标识:用于区分不同客户端的事件
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 参数验证:确保clientName不为null
|
|||
/// - 统一标识:在所有日志和事件中使用一致的客户端标识
|
|||
/// </summary>
|
|||
private readonly string _clientName; |
|||
|
|||
/// <summary>
|
|||
/// 消息队列 - 对应LTEClientWebSocket._messageFifo
|
|||
/// 线程安全的阻塞集合,用于批量发送优化
|
|||
/// 优化说明:从ConcurrentQueue改为BlockingCollection,提供更好的线程安全性和阻塞能力
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 队列类型:BlockingCollection<JObject>,优化后的线程安全集合
|
|||
/// - 入队操作:Add(message),对应原始的_messageFifo.Enqueue(message)
|
|||
/// - 出队操作:TryTake(out message),对应原始的队列处理逻辑
|
|||
/// - 批量处理:支持批量消息发送,对应原始的批处理逻辑
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 线程安全:使用BlockingCollection保证线程安全
|
|||
/// - 阻塞能力:支持阻塞式出队操作,提高性能
|
|||
/// - 批量优化:支持批量发送减少网络开销
|
|||
/// - 延迟发送:配合_messageDeferTimer实现延迟发送
|
|||
/// - 资源管理:自动处理集合的完成状态
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 移除了消息缓存功能,专注传输
|
|||
/// - 优化了队列操作逻辑,提供更好的性能
|
|||
/// - 增强了线程安全性和资源管理
|
|||
/// </summary>
|
|||
private readonly BlockingCollection<JObject> _messageFifo; |
|||
|
|||
/// <summary>
|
|||
/// 消息延迟发送定时器 - 对应LTEClientWebSocket._messageDeferTimer
|
|||
/// 用于实现消息的批量发送和延迟发送机制
|
|||
/// 保持与原始实现完全一致的逻辑
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 定时器类型:Timer,与原始实现完全一致
|
|||
/// - 启动逻辑:StartMessageDeferTimer(),对应原始的定时器启动
|
|||
/// - 停止逻辑:StopMessageDeferTimer(),对应原始的定时器停止
|
|||
/// - 延迟策略:1毫秒延迟,与原始实现完全一致
|
|||
/// - 批处理大小:100条消息,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 批量发送:当队列中消息少于100条时,延迟1毫秒发送
|
|||
/// - 立即发送:当队列中消息达到100条时,立即发送
|
|||
/// - 资源管理:在Disconnect()和Dispose()中正确释放
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的定时器管理逻辑
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的批处理策略
|
|||
/// </summary>
|
|||
private Timer? _messageDeferTimer; |
|||
|
|||
/// <summary>
|
|||
/// 释放标志 - 对应LTEClientWebSocket._disposed
|
|||
/// 防止重复释放和已释放对象的操作
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 字段类型:bool,对应原始的_disposed字段
|
|||
/// - 返回值:true表示已释放,false表示未释放,对应原始实现
|
|||
/// - 使用场景:外部检查对象释放状态,对应原始实现
|
|||
/// - 线程安全:直接返回_disposed字段值,对应原始实现
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 释放状态检查:外部可以检查对象是否已释放
|
|||
/// - 资源保护:防止对已释放对象的操作
|
|||
/// - 状态查询:提供对象状态的查询接口
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 保持了完全一致的检查逻辑
|
|||
/// - 保持了完全一致的返回值语义
|
|||
/// - 保持了完全一致的使用场景
|
|||
/// </summary>
|
|||
private bool _disposed; |
|||
|
|||
/// <summary>
|
|||
/// 同步锁对象
|
|||
/// 用于确保线程安全的操作
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 新增功能:原始实现中没有显式的同步锁
|
|||
/// - 用途:确保关键操作的线程安全
|
|||
/// - 使用场景:在需要线程安全的地方使用lock语句
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 线程安全:确保关键操作的原子性
|
|||
/// - 死锁预防:使用细粒度锁避免死锁
|
|||
/// - 性能优化:最小化锁的持有时间
|
|||
/// </summary>
|
|||
private readonly object _lockObject = new object(); |
|||
|
|||
#endregion
|
|||
|
|||
#region 事件
|
|||
|
|||
/// <summary>
|
|||
/// 连接打开事件 - 对应LTEClientWebSocket.ConnectionOpened
|
|||
/// 当WebSocket连接成功建立时触发
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件类型:EventHandler,与原始实现完全一致
|
|||
/// - 触发时机:在OnSocketOpened()中触发,对应原始的OnSocketOpened事件处理
|
|||
/// - 触发条件:WebSocket连接成功建立时
|
|||
/// - 事件参数:无参数,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 连接状态通知:通知外部连接已建立
|
|||
/// - 事件订阅:支持多个订阅者
|
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的触发时机
|
|||
/// - 更好的错误处理
|
|||
/// - 保持了完全一致的事件接口
|
|||
/// </summary>
|
|||
public event EventHandler? ConnectionOpened; |
|||
|
|||
/// <summary>
|
|||
/// 连接关闭事件 - 对应LTEClientWebSocket.ConnectionClosed
|
|||
/// 当WebSocket连接关闭时触发
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件类型:EventHandler,与原始实现完全一致
|
|||
/// - 触发时机:在OnSocketClosed()中触发,对应原始的OnSocketClosed事件处理
|
|||
/// - 触发条件:WebSocket连接关闭时
|
|||
/// - 事件参数:无参数,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 连接状态通知:通知外部连接已关闭
|
|||
/// - 事件订阅:支持多个订阅者
|
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的触发时机
|
|||
/// - 更好的资源清理
|
|||
/// - 保持了完全一致的事件接口
|
|||
/// </summary>
|
|||
public event EventHandler? ConnectionClosed; |
|||
|
|||
/// <summary>
|
|||
/// 连接错误事件 - 对应LTEClientWebSocket.ConnectionError
|
|||
/// 当WebSocket连接发生错误时触发
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件类型:EventHandler<string>,与原始实现完全一致
|
|||
/// - 触发时机:在OnSocketError()和异常处理中触发,对应原始的错误处理
|
|||
/// - 触发条件:WebSocket连接错误、消息处理错误等
|
|||
/// - 事件参数:错误信息字符串,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 错误通知:通知外部连接或处理错误
|
|||
/// - 事件订阅:支持多个订阅者
|
|||
/// - 异步触发:事件触发不会阻塞WebSocket操作
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更详细的错误信息
|
|||
/// - 更好的异常处理
|
|||
/// - 保持了完全一致的事件接口
|
|||
/// </summary>
|
|||
public event EventHandler<string>? ConnectionError; |
|||
|
|||
/// <summary>
|
|||
/// 消息接收事件 - 对应LTEClientWebSocket.MessageReceived
|
|||
/// 当接收到WebSocket消息时触发
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件类型:EventHandler<JObject>,与原始实现完全一致
|
|||
/// - 触发时机:在OnSocketMessageReceived()中触发,对应原始的OnSocketMessage事件处理
|
|||
/// - 触发条件:接收到WebSocket消息并解析成功后
|
|||
/// - 事件参数:解析后的JObject消息,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 消息通知:通知外部接收到新消息
|
|||
/// - 事件订阅:支持多个订阅者
|
|||
/// - 异步触发:事件触发不会阻塞消息处理
|
|||
/// - 触发顺序:在消息处理开始时就触发,与原始实现完全一致
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更清晰的触发时机
|
|||
/// - 更好的消息解析
|
|||
/// - 保持了完全一致的事件接口和触发顺序
|
|||
/// </summary>
|
|||
public event EventHandler<JObject>? MessageReceived; |
|||
|
|||
/// <summary>
|
|||
/// 消息发送事件 - 新增功能,LTEClientWebSocket中没有对应事件
|
|||
/// 当消息成功发送时触发,提供更完整的消息生命周期通知
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 事件类型:EventHandler<JObject>,与MessageReceived保持一致
|
|||
/// - 触发时机:在SendMessageNow()中触发,对应消息发送成功时
|
|||
/// - 触发条件:消息成功发送到WebSocket时
|
|||
/// - 事件参数:发送的JObject消息,与MessageReceived保持一致
|
|||
///
|
|||
/// 功能增强:
|
|||
/// - 消息生命周期:提供完整的消息发送通知
|
|||
/// - 调试支持:便于调试消息发送流程
|
|||
/// - 监控支持:便于监控消息发送状态
|
|||
/// - 事件订阅:支持多个订阅者
|
|||
///
|
|||
/// 重构优势:
|
|||
/// - 更完整的消息生命周期管理
|
|||
/// - 更好的调试和监控支持
|
|||
/// - 与MessageReceived事件形成对称的事件系统
|
|||
/// </summary>
|
|||
public event EventHandler<JObject>? MessageSent; |
|||
|
|||
#endregion
|
|||
|
|||
#region 属性
|
|||
|
|||
/// <summary>
|
|||
/// 是否已连接 - 对应LTEClientWebSocket.IsConnected
|
|||
/// 检查WebSocket连接状态
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 属性类型:bool,与原始实现完全一致
|
|||
/// - 检查逻辑:_webSocket?.State == WebSocketState.Open,与原始实现完全一致
|
|||
/// - 使用场景:在SendMessage()中检查连接状态,对应原始实现
|
|||
/// - 返回值:true表示已连接,false表示未连接,与原始实现完全一致
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 连接状态检查:快速检查WebSocket连接状态
|
|||
/// - 空安全:使用?.操作符避免空引用异常
|
|||
/// - 实时状态:反映WebSocket的实时连接状态
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 保持了完全一致的检查逻辑
|
|||
/// - 保持了完全一致的返回值语义
|
|||
/// - 保持了完全一致的使用场景
|
|||
/// </summary>
|
|||
public bool IsConnected => _webSocket?.State == WebSocketState.Open; |
|||
|
|||
/// <summary>
|
|||
/// WebSocket状态 - 对应LTEClientWebSocket._webSocket?.State
|
|||
/// 获取详细的WebSocket连接状态
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 属性类型:WebSocketState,对应原始的_webSocket?.State
|
|||
/// - 返回值:WebSocket的详细状态,对应原始实现
|
|||
/// - 空安全:使用??操作符提供默认值,对应原始实现
|
|||
/// - 使用场景:提供更详细的连接状态信息
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 详细状态:提供WebSocket的详细连接状态
|
|||
/// - 空安全:当_webSocket为null时返回WebSocketState.None
|
|||
/// - 实时状态:反映WebSocket的实时状态
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 保持了完全一致的状态获取逻辑
|
|||
/// - 保持了完全一致的默认值处理
|
|||
/// - 保持了完全一致的使用场景
|
|||
/// </summary>
|
|||
public WebSocketState State => _webSocket?.State ?? WebSocketState.None; |
|||
|
|||
/// <summary>
|
|||
/// 是否已释放 - 对应LTEClientWebSocket._disposed
|
|||
/// 检查对象是否已被释放
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 属性类型:bool,对应原始的_disposed字段
|
|||
/// - 返回值:true表示已释放,false表示未释放,对应原始实现
|
|||
/// - 使用场景:外部检查对象释放状态,对应原始实现
|
|||
/// - 线程安全:直接返回_disposed字段值,对应原始实现
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 释放状态检查:外部可以检查对象是否已释放
|
|||
/// - 资源保护:防止对已释放对象的操作
|
|||
/// - 状态查询:提供对象状态的查询接口
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 保持了完全一致的检查逻辑
|
|||
/// - 保持了完全一致的返回值语义
|
|||
/// - 保持了完全一致的使用场景
|
|||
/// </summary>
|
|||
public bool IsDisposed => _disposed; |
|||
|
|||
/// <summary>
|
|||
/// 消息队列数量 - 对应LTEClientWebSocket._messageFifo.Count
|
|||
/// 获取当前待发送消息的数量
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 属性类型:int,对应原始的_messageFifo.Count
|
|||
/// - 返回值:队列中待发送消息的数量,对应原始实现
|
|||
/// - 使用场景:监控消息队列状态,对应原始实现
|
|||
/// - 线程安全:BlockingCollection.Count是线程安全的,对应原始实现
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 队列监控:监控当前待发送消息的数量
|
|||
/// - 性能监控:便于监控消息发送性能
|
|||
/// - 调试支持:便于调试消息队列状态
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 保持了完全一致的计数逻辑
|
|||
/// - 保持了完全一致的返回值语义
|
|||
/// - 保持了完全一致的使用场景
|
|||
/// - 优化:使用BlockingCollection提供更好的线程安全性
|
|||
/// </summary>
|
|||
public int MessageQueueCount => _messageFifo.Count; |
|||
|
|||
/// <summary>
|
|||
/// 消息ID管理器 - 提供对MessageIdManager的访问
|
|||
/// 允许外部访问消息ID管理功能
|
|||
///
|
|||
/// 对应关系:
|
|||
/// - 属性类型:MessageIdManager,对应原始的_messageId和_logGetId管理
|
|||
/// - 返回值:内部的消息ID管理器实例,对应原始实现
|
|||
/// - 使用场景:外部访问消息ID管理功能,对应原始实现
|
|||
/// - 封装性:提供对内部MessageIdManager的访问,对应原始实现
|
|||
///
|
|||
/// 功能保持:
|
|||
/// - 功能访问:外部可以访问消息ID管理功能
|
|||
/// - 封装性:保持内部实现的封装性
|
|||
/// - 扩展性:支持外部扩展消息ID管理功能
|
|||
///
|
|||
/// 重构改进:
|
|||
/// - 更统一的消息ID管理接口
|
|||
/// - 更好的功能封装
|
|||
/// - 保持了完全一致的功能访问方式
|
|||
/// </summary>
|
|||
public MessageIdManager MessageIdManager => _messageIdManager; |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
# WebSocketMessageManager 结构层次说明 |
|||
|
|||
``` |
|||
Core/WebSocket/Managers/WebSocketMessageManager/ |
|||
├── WebSocketMessageManager.cs # 主体声明:类声明、字段、属性、事件 |
|||
├── Constructor.cs # 构造函数:初始化相关 |
|||
├── PublicMethods.cs # 公共方法:对外接口、业务主流程 |
|||
├── PrivateMethods.cs # 私有方法:内部逻辑、事件处理器、辅助方法 |
|||
├── Dispose.cs # IDisposable实现:资源释放、清理 |
|||
``` |
|||
|
|||
## 各文件职责说明 |
|||
|
|||
- **WebSocketMessageManager.cs** |
|||
- 声明类本体(partial class),包含所有字段、属性、事件声明。 |
|||
- 只负责结构性声明,不含具体实现。 |
|||
|
|||
- **Constructor.cs** |
|||
- 只包含构造函数,负责对象初始化、依赖注入、字段赋值。 |
|||
|
|||
- **PublicMethods.cs** |
|||
- 所有对外公开的方法(如Connect、Disconnect、SendMessage等)。 |
|||
- 业务主流程、外部接口全部集中于此,便于查找和维护。 |
|||
|
|||
- **PrivateMethods.cs** |
|||
- 所有私有方法、事件处理器、内部辅助逻辑。 |
|||
- 包括定时器、消息分发、内部校验等。 |
|||
|
|||
- **Dispose.cs** |
|||
- 只包含IDisposable接口实现和资源释放相关方法。 |
|||
- 负责对象生命周期的正确终结。 |
|||
|
|||
--- |
|||
|
|||
> 本结构层次仅为物理文件组织优化,**所有业务逻辑、接口、注释、实现细节均与原始文件完全一致**,仅提升可维护性和可读性。 |
|||
@ -0,0 +1,222 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Newtonsoft.Json; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// 小区配置实体,对应无线参数配置
|
|||
/// 用于存储LTE小区的各种物理层和协议层配置参数
|
|||
/// 支持JSON序列化,属性名与外部API保持一致
|
|||
/// </summary>
|
|||
public class CellConfig |
|||
{ |
|||
/// <summary>下行天线数量</summary>
|
|||
[JsonProperty("n_antenna_dl")] |
|||
public int NAntennaDl { get; set; } |
|||
|
|||
/// <summary>上行天线数量</summary>
|
|||
[JsonProperty("n_antenna_ul")] |
|||
public int NAntennaUl { get; set; } |
|||
|
|||
/// <summary>下行传输层数</summary>
|
|||
[JsonProperty("n_layer_dl")] |
|||
public int NLayerDl { get; set; } |
|||
|
|||
/// <summary>上行传输层数</summary>
|
|||
[JsonProperty("n_layer_ul")] |
|||
public int NLayerUl { get; set; } |
|||
|
|||
/// <summary>天线增益(dB)</summary>
|
|||
[JsonProperty("gain")] |
|||
public int Gain { get; set; } |
|||
|
|||
/// <summary>上行链路是否禁用</summary>
|
|||
[JsonProperty("ul_disabled")] |
|||
public bool UlDisabled { get; set; } |
|||
|
|||
/// <summary>射频端口号</summary>
|
|||
[JsonProperty("rf_port")] |
|||
public int RfPort { get; set; } |
|||
|
|||
/// <summary>下行QAM调制阶数</summary>
|
|||
[JsonProperty("dl_qam")] |
|||
public int DlQam { get; set; } |
|||
|
|||
/// <summary>上行QAM调制阶数</summary>
|
|||
[JsonProperty("ul_qam")] |
|||
public int UlQam { get; set; } |
|||
|
|||
/// <summary>物理小区标识(PCI)</summary>
|
|||
[JsonProperty("n_id_cell")] |
|||
public int NIdCell { get; set; } |
|||
|
|||
/// <summary>下行资源块数量</summary>
|
|||
[JsonProperty("n_rb_dl")] |
|||
public int NRbDl { get; set; } |
|||
|
|||
/// <summary>上行资源块数量</summary>
|
|||
[JsonProperty("n_rb_ul")] |
|||
public int NRbUl { get; set; } |
|||
|
|||
/// <summary>下行E-UTRA绝对射频信道号</summary>
|
|||
[JsonProperty("dl_earfcn")] |
|||
public int DlEarfcn { get; set; } |
|||
|
|||
/// <summary>上行E-UTRA绝对射频信道号</summary>
|
|||
[JsonProperty("ul_earfcn")] |
|||
public int UlEarfcn { get; set; } |
|||
|
|||
/// <summary>LTE频段号</summary>
|
|||
[JsonProperty("band")] |
|||
public int Band { get; set; } |
|||
|
|||
/// <summary>下行载波频率(Hz)</summary>
|
|||
[JsonProperty("dl_freq")] |
|||
public long DlFreq { get; set; } |
|||
|
|||
/// <summary>上行载波频率(Hz)</summary>
|
|||
[JsonProperty("ul_freq")] |
|||
public long UlFreq { get; set; } |
|||
|
|||
/// <summary>双工模式(FDD/TDD)</summary>
|
|||
[JsonProperty("mode")] |
|||
public string Mode { get; set; } = string.Empty; |
|||
|
|||
/// <summary>PRACH序列索引</summary>
|
|||
[JsonProperty("prach_sequence_index")] |
|||
public int PrachSequenceIndex { get; set; } |
|||
|
|||
/// <summary>下行循环前缀类型</summary>
|
|||
[JsonProperty("dl_cyclic_prefix")] |
|||
public string DlCyclicPrefix { get; set; } = string.Empty; |
|||
|
|||
/// <summary>上行循环前缀类型</summary>
|
|||
[JsonProperty("ul_cyclic_prefix")] |
|||
public string UlCyclicPrefix { get; set; } = string.Empty; |
|||
|
|||
/// <summary>PRACH配置索引</summary>
|
|||
[JsonProperty("prach_config_index")] |
|||
public int PrachConfigIndex { get; set; } |
|||
|
|||
/// <summary>PRACH频域偏移</summary>
|
|||
[JsonProperty("prach_freq_offset")] |
|||
public int PrachFreqOffset { get; set; } |
|||
|
|||
/// <summary>PUCCH delta shift参数</summary>
|
|||
[JsonProperty("delta_pucch_shift")] |
|||
public int DeltaPucchShift { get; set; } |
|||
|
|||
/// <summary>CQI报告的资源块数量</summary>
|
|||
[JsonProperty("n_rb_cqi")] |
|||
public int NRbCqi { get; set; } |
|||
|
|||
/// <summary>循环移位天线端口数量</summary>
|
|||
[JsonProperty("n_cs_an")] |
|||
public int NCsAn { get; set; } |
|||
|
|||
/// <summary>PUCCH资源配置列表</summary>
|
|||
[JsonProperty("pucch_allocation")] |
|||
public List<PucchAllocation> PucchAllocation { get; set; } = new(); |
|||
|
|||
/// <summary>PUCCH ACK/NACK起始位置</summary>
|
|||
[JsonProperty("pucch_ack_nack_start")] |
|||
public int PucchAckNackStart { get; set; } |
|||
|
|||
/// <summary>PUCCH保留资源块列表</summary>
|
|||
[JsonProperty("pucch_reserved_rbs")] |
|||
public List<int> PucchReservedRbs { get; set; } = new(); |
|||
|
|||
/// <summary>调度请求(SR)资源数量</summary>
|
|||
[JsonProperty("sr_resource_count")] |
|||
public int SrResourceCount { get; set; } |
|||
|
|||
/// <summary>CQI资源数量</summary>
|
|||
[JsonProperty("cqi_resource_count")] |
|||
public int CqiResourceCount { get; set; } |
|||
|
|||
/// <summary>SRS资源配置</summary>
|
|||
[JsonProperty("srs_resources")] |
|||
public SrsResources SrsResources { get; set; } = new(); |
|||
|
|||
/// <summary>保证比特率(GBR)配置</summary>
|
|||
[JsonProperty("gbr")] |
|||
public GbrConfig Gbr { get; set; } = new(); |
|||
|
|||
/// <summary>跟踪区域码(TAC)</summary>
|
|||
[JsonProperty("tac")] |
|||
public int Tac { get; set; } |
|||
|
|||
/// <summary>公共陆地移动网络(PLMN)列表</summary>
|
|||
[JsonProperty("plmn_list")] |
|||
public List<PlmnItem> PlmnList { get; set; } = new(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// PUCCH资源配置结构
|
|||
/// 定义物理上行控制信道的资源配置参数
|
|||
/// </summary>
|
|||
public class PucchAllocation |
|||
{ |
|||
/// <summary>PUCCH格式类型</summary>
|
|||
[JsonProperty("type")] |
|||
public string Type { get; set; } = string.Empty; |
|||
|
|||
/// <summary>分配的资源块数量</summary>
|
|||
[JsonProperty("rbs")] |
|||
public int Rbs { get; set; } |
|||
|
|||
/// <summary>PUCCH参数n</summary>
|
|||
[JsonProperty("n")] |
|||
public int N { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// SRS资源配置结构
|
|||
/// 定义探测参考信号的资源配置参数
|
|||
/// </summary>
|
|||
public class SrsResources |
|||
{ |
|||
/// <summary>频域偏移</summary>
|
|||
[JsonProperty("offsets")] |
|||
public int Offsets { get; set; } |
|||
|
|||
/// <summary>频点数量</summary>
|
|||
[JsonProperty("freqs")] |
|||
public int Freqs { get; set; } |
|||
|
|||
/// <summary>总资源数量</summary>
|
|||
[JsonProperty("total")] |
|||
public int Total { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 保证比特率(GBR)配置结构
|
|||
/// 定义服务质量相关的比特率限制
|
|||
/// </summary>
|
|||
public class GbrConfig |
|||
{ |
|||
/// <summary>下行速率限制(bps)</summary>
|
|||
[JsonProperty("dl_limit")] |
|||
public int DlLimit { get; set; } |
|||
|
|||
/// <summary>上行速率限制(bps)</summary>
|
|||
[JsonProperty("ul_limit")] |
|||
public int UlLimit { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// PLMN配置项
|
|||
/// 定义公共陆地移动网络的配置信息
|
|||
/// </summary>
|
|||
public class PlmnItem |
|||
{ |
|||
/// <summary>PLMN编码(MCC+MNC)</summary>
|
|||
[JsonProperty("plmn")] |
|||
public string Plmn { get; set; } = string.Empty; |
|||
|
|||
/// <summary>是否为保留PLMN</summary>
|
|||
[JsonProperty("reserved")] |
|||
public bool Reserved { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
|
|||
/// <summary>
|
|||
/// 客户端配置
|
|||
/// </summary>
|
|||
public class ClientConfig |
|||
{ |
|||
/// <summary>
|
|||
/// 客户端名称
|
|||
/// </summary>
|
|||
public string Name { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 服务器地址
|
|||
/// </summary>
|
|||
public string Address { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 是否启用
|
|||
/// </summary>
|
|||
public bool Enabled { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 密码
|
|||
/// </summary>
|
|||
public string Password { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 重连延迟(毫秒)
|
|||
/// </summary>
|
|||
public int ReconnectDelay { get; set; } = 5000; |
|||
|
|||
/// <summary>
|
|||
/// 是否启用SSL
|
|||
/// </summary>
|
|||
public bool Ssl { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 日志配置
|
|||
/// </summary>
|
|||
public ClientLogsConfig Logs { get; set; } = new(); |
|||
|
|||
/// <summary>
|
|||
/// 是否只读
|
|||
/// </summary>
|
|||
public bool Readonly { get; set; } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 模型
|
|||
/// </summary>
|
|||
public string Model { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 客户端日志配置
|
|||
/// </summary>
|
|||
public class ClientLogsConfig |
|||
{ |
|||
/// <summary>
|
|||
/// 日志层配置
|
|||
/// </summary>
|
|||
public Dictionary<string, LogLayerConfig> Layers { get; set; } = new(); |
|||
|
|||
/// <summary>
|
|||
/// 是否启用信号日志
|
|||
/// </summary>
|
|||
public bool? Signal { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 是否启用控制信道日志
|
|||
/// </summary>
|
|||
public bool? Cch { get; set; } |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 日志层配置
|
|||
/// </summary>
|
|||
public class LogLayerConfig |
|||
{ |
|||
/// <summary>
|
|||
/// 日志级别
|
|||
/// </summary>
|
|||
[Required] |
|||
public string Level { get; set; } = "warn"; |
|||
|
|||
/// <summary>
|
|||
/// 最大大小
|
|||
/// </summary>
|
|||
public int MaxSize { get; set; } = 1; |
|||
|
|||
/// <summary>
|
|||
/// 是否包含负载
|
|||
/// </summary>
|
|||
public bool Payload { get; set; } = false; |
|||
|
|||
/// <summary>
|
|||
/// 过滤器(用于兼容性)
|
|||
/// </summary>
|
|||
public string Filter { get; set; } = "warn"; |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// 日志层配置帮助类
|
|||
/// 提供预定义的日志层配置,用于不同协议层的日志记录控制
|
|||
/// 支持LTE协议栈各层的日志级别、大小限制和过滤规则配置
|
|||
/// </summary>
|
|||
public static class LogLayerHelp |
|||
{ |
|||
/// <summary>
|
|||
/// 获取默认的LTE协议层日志配置
|
|||
/// 包含PHY、MAC、RLC、PDCP、RRC、NAS等各层的预定义配置
|
|||
/// </summary>
|
|||
/// <returns>协议层名称到配置的映射字典</returns>
|
|||
public static Dictionary<string, LogLayerConfig> GetDefaultCustomLayerConfigs() |
|||
{ |
|||
// 直接返回静态配置,避免不必要的嵌套和动态解析
|
|||
return new Dictionary<string, LogLayerConfig> |
|||
{ |
|||
["PHY"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "info" }, |
|||
["MAC"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "info" }, |
|||
["RLC"] = new LogLayerConfig { Level = "info", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["PDCP"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = false, Filter = "warn" }, |
|||
["RRC"] = new LogLayerConfig { Level = "debug", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
["NAS"] = new LogLayerConfig { Level = "debug", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
["S1AP"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["NGAP"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["GTPU"] = new LogLayerConfig { Level = "info", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["X2AP"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["XnAP"] = new LogLayerConfig { Level = "info", MaxSize = 1000, Payload = false, Filter = "info" }, |
|||
["M2AP"] = new LogLayerConfig { Level = "info", MaxSize = 1000, Payload = false, Filter = "info" } |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取IMS协议层的日志配置
|
|||
/// 包含IMS、CX、RX、SIP、MEDIA、MMS等IMS相关协议的配置
|
|||
/// </summary>
|
|||
/// <returns>IMS协议层名称到配置的映射字典</returns>
|
|||
public static Dictionary<string, LogLayerConfig> GetIMSCustomLayerConfigs() |
|||
{ |
|||
// 直接返回静态配置,避免不必要的嵌套和动态解析
|
|||
return new Dictionary<string, LogLayerConfig> |
|||
{ |
|||
["IMS"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
["CX"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
["RX"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = false, Filter = "debug" }, |
|||
["SIP"] = new LogLayerConfig { Level = "debug", MaxSize = 1000, Payload = false, Filter = "debug" }, |
|||
["MEDIA"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
["MMS"] = new LogLayerConfig { Level = "warn", MaxSize = 1000, Payload = true, Filter = "debug" }, |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using Newtonsoft.Json.Linq; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// 消息处理器模型
|
|||
/// 用于处理WebSocket消息的回调和错误处理
|
|||
/// 支持不同类型的消息处理器,包括普通消息、错误消息和日志获取消息
|
|||
/// </summary>
|
|||
public class MessageHandler |
|||
{ |
|||
/// <summary>
|
|||
/// 消息处理回调函数
|
|||
/// 当接收到消息时会被调用的委托函数
|
|||
/// </summary>
|
|||
public Action<JObject>? Callback { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 标识是否为错误处理器
|
|||
/// 当为true时,该处理器专门用于处理错误消息
|
|||
/// </summary>
|
|||
public bool ErrorHandler { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 处理器创建时间
|
|||
/// 用于跟踪处理器的生命周期和超时管理
|
|||
/// </summary>
|
|||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow; |
|||
|
|||
/// <summary>
|
|||
/// 标识是否为日志获取处理器
|
|||
/// 当为true时,该处理器专门用于处理日志获取相关的消息
|
|||
/// </summary>
|
|||
public bool IsLogGetHandler { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// LTE协议能力信息模型
|
|||
/// 用于存储用户设备(UE)的LTE协议栈能力信息,包括频段支持、UE类别等
|
|||
/// </summary>
|
|||
public class ProtocolCaps |
|||
{ |
|||
/// <summary>
|
|||
/// 用户设备唯一标识符
|
|||
/// </summary>
|
|||
public int UeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 支持的LTE频段列表
|
|||
/// </summary>
|
|||
public List<int> Bands { get; set; } = new List<int>(); |
|||
|
|||
/// <summary>
|
|||
/// UE类别(可选)
|
|||
/// </summary>
|
|||
public int? Category { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 下行UE类别(可选)
|
|||
/// </summary>
|
|||
public int? CategoryDl { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 上行UE类别(可选)
|
|||
/// </summary>
|
|||
public int? CategoryUl { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 协议能力数据列表
|
|||
/// </summary>
|
|||
public List<object> Data { get; set; } = new List<object>(); |
|||
|
|||
/// <summary>
|
|||
/// 数据项计数
|
|||
/// </summary>
|
|||
public int Count { get; set; } = 0; |
|||
|
|||
/// <summary>
|
|||
/// 频段组合列表
|
|||
/// </summary>
|
|||
public List<object> BandComb { get; set; } = new List<object>(); |
|||
|
|||
/// <summary>
|
|||
/// ASN.1编码数据列表
|
|||
/// </summary>
|
|||
public List<object> Asn1 { get; set; } = new List<object>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// ProtocolCaps扩展方法类
|
|||
/// 提供ProtocolCaps相关的工具方法和扩展功能
|
|||
/// </summary>
|
|||
public static class ProtocolCapsExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// UE能力MIMO层数映射字典
|
|||
/// 定义不同MIMO配置对应的层数
|
|||
/// </summary>
|
|||
private static readonly Dictionary<string, int> UE_CAPS_MIMO = new Dictionary<string, int> |
|||
{ |
|||
{ "twoLayers", 2 }, |
|||
{ "fourLayers", 4 }, |
|||
{ "eightLayers", 8 } |
|||
}; |
|||
|
|||
/// <summary>
|
|||
/// 获取UE类别信息的字符串表示
|
|||
/// 优先返回DL/UL类别组合,如果没有则返回通用类别
|
|||
/// </summary>
|
|||
/// <param name="caps">协议能力信息对象</param>
|
|||
/// <returns>格式化的类别信息字符串</returns>
|
|||
public static string GetCategory(this ProtocolCaps caps) |
|||
{ |
|||
List<string> categories = new List<string>(); |
|||
|
|||
if (caps.CategoryDl.HasValue) |
|||
{ |
|||
categories.Add($"DL={caps.CategoryDl.Value}"); |
|||
} |
|||
|
|||
if (caps.CategoryUl.HasValue) |
|||
{ |
|||
categories.Add($"UL={caps.CategoryUl.Value}"); |
|||
} |
|||
|
|||
if (categories.Count > 0) |
|||
{ |
|||
return string.Join(",", categories); |
|||
} |
|||
|
|||
if (caps.Category.HasValue) |
|||
{ |
|||
return caps.Category.Value.ToString(); |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,212 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Text.RegularExpressions; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
public class ProtocolLog |
|||
{ |
|||
#region 基础属性
|
|||
/// <summary>
|
|||
/// 日志唯一标识符
|
|||
/// </summary>
|
|||
public int Id { get; set; } |
|||
/// <summary>
|
|||
/// 时间戳(毫秒)
|
|||
/// </summary>
|
|||
public long Timestamp { get; set; } |
|||
/// <summary>
|
|||
/// 协议层(PHY, RRC, NAS, MAC等)
|
|||
/// </summary>
|
|||
public string Layer { get; set; } = string.Empty; |
|||
/// <summary>
|
|||
/// 传输方向(UL/DL)
|
|||
/// </summary>
|
|||
public int Direction { get; set; } |
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
public string Message { get; set; } = string.Empty; |
|||
/// <summary>
|
|||
/// 消息信息类型
|
|||
/// </summary>
|
|||
public int? Info { get; set; } |
|||
/// <summary>
|
|||
/// UE标识符
|
|||
/// </summary>
|
|||
public int? UeId { get; set; } |
|||
/// <summary>
|
|||
/// RNTI(无线网络临时标识符)
|
|||
/// </summary>
|
|||
public int? Rnti { get; set; } |
|||
/// <summary>
|
|||
/// 日志数据内容
|
|||
/// </summary>
|
|||
public List<string> Data { get; set; } = new(); |
|||
/// <summary>
|
|||
/// 是否已解码
|
|||
/// </summary>
|
|||
public bool Decoded { get; set; } |
|||
/// <summary>
|
|||
/// 标记信息
|
|||
/// </summary>
|
|||
public string? Marker { get; set; } |
|||
/// <summary>
|
|||
/// SIP原始消息内容
|
|||
/// </summary>
|
|||
public string? Msg0 { get; set; } |
|||
/// <summary>
|
|||
/// 小区标识(所有层通用)
|
|||
/// </summary>
|
|||
public int? Cell { get; set; } |
|||
#endregion
|
|||
|
|||
#region PHY层相关属性
|
|||
public PhyFields Phy { get; set; } = new(); |
|||
#endregion
|
|||
|
|||
#region 数据相关属性
|
|||
public DataFields DataInfo { get; set; } = new(); |
|||
#endregion
|
|||
|
|||
#region MAC层相关属性
|
|||
public MacFields Mac { get; set; } = new(); |
|||
#endregion
|
|||
} |
|||
|
|||
// PHY层分组
|
|||
public class PhyFields |
|||
{ |
|||
/// <summary>
|
|||
/// 物理信道类型
|
|||
/// </summary>
|
|||
public string? Channel { get; set; } |
|||
/// <summary>
|
|||
/// 帧号
|
|||
/// </summary>
|
|||
public int? Frame { get; set; } |
|||
/// <summary>
|
|||
/// 子帧号
|
|||
/// </summary>
|
|||
public int? Subframe { get; set; } |
|||
/// <summary>
|
|||
/// 时隙号
|
|||
/// </summary>
|
|||
public int? Slot { get; set; } |
|||
/// <summary>
|
|||
/// 符号号
|
|||
/// </summary>
|
|||
public int? Symbol { get; set; } |
|||
/// <summary>
|
|||
/// 天线端口
|
|||
/// </summary>
|
|||
public int? AntennaPort { get; set; } |
|||
/// <summary>
|
|||
/// 资源块起始位置
|
|||
/// </summary>
|
|||
public int? RbStart { get; set; } |
|||
/// <summary>
|
|||
/// 资源块数量
|
|||
/// </summary>
|
|||
public int? RbCount { get; set; } |
|||
/// <summary>
|
|||
/// 调制编码方案
|
|||
/// </summary>
|
|||
public int? Mcs { get; set; } |
|||
/// <summary>
|
|||
/// 传输块大小
|
|||
/// </summary>
|
|||
public int? Tbs { get; set; } |
|||
/// <summary>
|
|||
/// HARQ进程ID
|
|||
/// </summary>
|
|||
public int? HarqId { get; set; } |
|||
/// <summary>
|
|||
/// HARQ新数据指示
|
|||
/// </summary>
|
|||
public bool? HarqNdi { get; set; } |
|||
/// <summary>
|
|||
/// HARQ重传次数
|
|||
/// </summary>
|
|||
public int? HarqRedundancyVersion { get; set; } |
|||
} |
|||
|
|||
// 数据相关分组
|
|||
public class DataFields |
|||
{ |
|||
/// <summary>
|
|||
/// IP长度
|
|||
/// </summary>
|
|||
public int? IpLen { get; set; } |
|||
/// <summary>
|
|||
/// SDU长度
|
|||
/// </summary>
|
|||
public int? SduLen { get; set; } |
|||
/// <summary>
|
|||
/// 链路ID
|
|||
/// </summary>
|
|||
public LinkIds? LinkIds { get; set; } |
|||
/// <summary>
|
|||
/// 信号记录
|
|||
/// </summary>
|
|||
public Dictionary<string, object>? SignalRecord { get; set; } |
|||
} |
|||
|
|||
// MAC层分组
|
|||
public class MacFields |
|||
{ |
|||
/// <summary>
|
|||
/// 功率余量报告(PHR)
|
|||
/// </summary>
|
|||
public int? Phr { get; set; } |
|||
/// <summary>
|
|||
/// 上行缓冲区大小
|
|||
/// </summary>
|
|||
public int? UlBufferSize { get; set; } |
|||
/// <summary>
|
|||
/// MAC填充长度
|
|||
/// </summary>
|
|||
public int? MacPad { get; set; } |
|||
/// <summary>
|
|||
/// MAC数据长度
|
|||
/// </summary>
|
|||
public int? MacLen { get; set; } |
|||
/// <summary>
|
|||
/// 定时提前量(TA)
|
|||
/// </summary>
|
|||
public int? Ta { get; set; } |
|||
} |
|||
|
|||
public class LinkIds |
|||
{ |
|||
/// <summary>
|
|||
/// Core链路ID
|
|||
/// </summary>
|
|||
public int? Core { get; set; } |
|||
/// <summary>
|
|||
/// Ran链路ID
|
|||
/// </summary>
|
|||
public int? Ran { get; set; } |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// ProtocolLog扩展方法类
|
|||
/// 提供ProtocolLog相关的工具方法和扩展功能
|
|||
/// </summary>
|
|||
public static class ProtocolLogExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// 获取协议日志数据的字符串表示
|
|||
/// </summary>
|
|||
/// <param name="log">协议日志对象</param>
|
|||
/// <returns>格式化的日志数据字符串</returns>
|
|||
public static string GetProtocolLogData(this ProtocolLog log) |
|||
{ |
|||
return string.Join("\n", log.Data); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using System.ComponentModel.DataAnnotations.Schema; |
|||
using CoreAgent.ProtocolClient.Enums; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// 协议日志详情实体
|
|||
/// 用于存储解析后的协议日志详细信息到数据库
|
|||
/// </summary>
|
|||
[Table("ProtocolLogDetails")] |
|||
public class ProtocolLogDetail |
|||
{ |
|||
/// <summary>
|
|||
/// 主键ID
|
|||
/// </summary>
|
|||
[Key] |
|||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] |
|||
public long Id { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 协议层类型
|
|||
/// </summary>
|
|||
[Required] |
|||
[Column("LayerType")] |
|||
public ProtocolLayer LayerType { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息详情集合(JSON格式存储)
|
|||
/// </summary>
|
|||
[Column("MessageDetail", TypeName = "TEXT")] |
|||
public string? MessageDetailJson { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 小区ID
|
|||
/// </summary>
|
|||
[Column("CellID")] |
|||
public int? CellID { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 国际移动用户识别码
|
|||
/// </summary>
|
|||
[Column("IMSI", TypeName = "VARCHAR(20)")] |
|||
[MaxLength(20)] |
|||
public string? IMSI { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 日志方向类型
|
|||
/// </summary>
|
|||
[Required] |
|||
[Column("Direction")] |
|||
public int Direction { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 用户设备ID
|
|||
/// </summary>
|
|||
[Column("UEID")] |
|||
public int? UEID { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 公共陆地移动网络标识
|
|||
/// </summary>
|
|||
[Column("PLMN", TypeName = "VARCHAR(10)")] |
|||
[MaxLength(10)] |
|||
public string? PLMN { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时间间隔(毫秒)
|
|||
/// </summary>
|
|||
[Column("TimeMs")] |
|||
public long TimeMs { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时间戳
|
|||
/// </summary>
|
|||
[Required] |
|||
[Column("Timestamp")] |
|||
public long Timestamp { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 信息字段
|
|||
/// </summary>
|
|||
[Column("Info", TypeName = "TEXT")] |
|||
public string? Info { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息字段
|
|||
/// </summary>
|
|||
[Column("Message", TypeName = "TEXT")] |
|||
public string? Message { get; set; } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 消息详情集合(非数据库字段,用于业务逻辑)
|
|||
/// </summary>
|
|||
[NotMapped] |
|||
public IEnumerable<string>? MessageDetail |
|||
{ |
|||
get => !string.IsNullOrEmpty(MessageDetailJson) |
|||
? Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<string>>(MessageDetailJson) |
|||
: null; |
|||
set => MessageDetailJson = value != null |
|||
? Newtonsoft.Json.JsonConvert.SerializeObject(value) |
|||
: null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 时间间隔(用于业务逻辑)
|
|||
/// </summary>
|
|||
[NotMapped] |
|||
public TimeSpan Time |
|||
{ |
|||
get => TimeSpan.FromMilliseconds(TimeMs); |
|||
set => TimeMs = (long)value.TotalMilliseconds; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,168 @@ |
|||
using Newtonsoft.Json.Linq; |
|||
using Newtonsoft.Json; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
public record class ProtocolLogJson |
|||
{ |
|||
/// <summary>
|
|||
/// 消息ID
|
|||
/// </summary>
|
|||
[JsonProperty("message_id")] |
|||
public int? MessageId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息头信息
|
|||
/// </summary>
|
|||
[JsonProperty("headers")] |
|||
public string[]? Headers { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 消息内容
|
|||
/// </summary>
|
|||
[JsonProperty("message")] |
|||
public string Message { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时间戳
|
|||
/// </summary>
|
|||
[JsonProperty("time")] |
|||
public double? Time { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 日志明细
|
|||
/// </summary>
|
|||
[JsonProperty("logs")] |
|||
public JToken? Logs { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 初始化协议日志实体类的新实例
|
|||
/// </summary>
|
|||
/// <param name="message">消息内容</param>
|
|||
/// <param name="type">消息类型</param>
|
|||
/// <param name="version">协议版本</param>
|
|||
/// <param name="time">时间戳</param>
|
|||
/// <param name="utc">UTC时间戳</param>
|
|||
/// <param name="logs">日志明细</param>
|
|||
/// <param name="messageId">消息ID</param>
|
|||
/// <param name="headers">消息头信息</param>
|
|||
public ProtocolLogJson( |
|||
string message, |
|||
string? type, |
|||
string? version, |
|||
double? time, |
|||
double? utc, |
|||
JToken? logs, |
|||
int? messageId, |
|||
string[]? headers) |
|||
{ |
|||
Message = message; |
|||
Time = time; |
|||
Logs = logs; |
|||
MessageId = messageId ?? 0; |
|||
Headers = headers; |
|||
} |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 协议日志明细
|
|||
/// </summary>
|
|||
public class ProtocolLogDetailJson |
|||
{ |
|||
/// <summary>
|
|||
/// 源信息
|
|||
/// </summary>
|
|||
[JsonProperty("src")] |
|||
public string Src { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 索引
|
|||
/// </summary>
|
|||
[JsonProperty("idx")] |
|||
public int Idx { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 日志级别
|
|||
/// </summary>
|
|||
[JsonProperty("level")] |
|||
public int Level { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 方向
|
|||
/// </summary>
|
|||
[JsonProperty("dir")] |
|||
public string Dir { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时间戳
|
|||
/// </summary>
|
|||
[JsonProperty("timestamp")] |
|||
public long Timestamp { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 小区信息
|
|||
/// </summary>
|
|||
[JsonProperty("cell")] |
|||
public int? Cell { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 数据列表
|
|||
/// </summary>
|
|||
[JsonProperty("data")] |
|||
public List<string> Data { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 层信息
|
|||
/// </summary>
|
|||
[JsonProperty("layer")] |
|||
public string Layer { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// UE标识
|
|||
/// </summary>
|
|||
[JsonProperty("ue_id")] |
|||
public int? UeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 帧信息
|
|||
/// </summary>
|
|||
[JsonProperty("frame")] |
|||
public int? Frame { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时隙信息
|
|||
/// </summary>
|
|||
[JsonProperty("slot")] |
|||
public int? Slot { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 帧信息
|
|||
/// </summary>
|
|||
[JsonProperty("channel")] |
|||
public string? Channel { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时隙信息
|
|||
/// </summary>
|
|||
[JsonProperty("rnti")] |
|||
public int? Rnti { get; set; } |
|||
|
|||
|
|||
/// <summary>
|
|||
/// 深拷贝当前对象
|
|||
/// </summary>
|
|||
public ProtocolLogDetailJson DeepClone() |
|||
{ |
|||
// 通过序列化和反序列化实现深拷贝
|
|||
var json = JsonConvert.SerializeObject(this); |
|||
return JsonConvert.DeserializeObject<ProtocolLogDetailJson>(json) |
|||
?? throw new InvalidOperationException("深拷贝失败,反序列化结果为 null"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,324 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// TMSI匹配处理器
|
|||
/// 负责处理TMSI匹配和UE链的构建,从根节点获取IMSI并分配给整个链
|
|||
/// </summary>
|
|||
public class TmsiMatchProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// TMSI到UE ID的映射表
|
|||
/// </summary>
|
|||
private readonly Dictionary<uint, int> _tmsiToUeId; |
|||
|
|||
/// <summary>
|
|||
/// 请求TMSI到UE ID的映射表
|
|||
/// </summary>
|
|||
private readonly Dictionary<uint, int> _requestTmsiToUeId; |
|||
|
|||
/// <summary>
|
|||
/// IMSI到UE ID的映射表
|
|||
/// </summary>
|
|||
private readonly Dictionary<string, List<int>> _imsiToUeId; |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="tmsiToUeId">TMSI到UE ID的映射表</param>
|
|||
/// <param name="requestTmsiToUeId">请求TMSI到UE ID的映射表</param>
|
|||
/// <param name="imsiToUeId">IMSI到UE ID的映射表</param>
|
|||
public TmsiMatchProcessor( |
|||
Dictionary<uint, int> tmsiToUeId, |
|||
Dictionary<uint, int> requestTmsiToUeId, |
|||
Dictionary<string, List<int>> imsiToUeId) |
|||
{ |
|||
_tmsiToUeId = tmsiToUeId ?? new Dictionary<uint, int>(); |
|||
_requestTmsiToUeId = requestTmsiToUeId ?? new Dictionary<uint, int>(); |
|||
_imsiToUeId = imsiToUeId ?? new Dictionary<string, List<int>>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 生成TMSI匹配结果
|
|||
/// 先构建树形结构,从根节点获取IMSI,然后平铺成列表
|
|||
/// </summary>
|
|||
/// <returns>TMSI匹配结果列表</returns>
|
|||
public List<TmsiMatchResult> GenerateTmsiMatches() |
|||
{ |
|||
var matches = new List<TmsiMatchResult>(); |
|||
|
|||
// 构建UE链的树形结构
|
|||
var ueChains = BuildUeChains(); |
|||
|
|||
// 遍历RequestTmsiToUeId,查找在TmsiToUeId中是否有相同的TMSI
|
|||
foreach (var requestKvp in _requestTmsiToUeId) |
|||
{ |
|||
uint tmsi = requestKvp.Key; |
|||
int requestUeId = requestKvp.Value; |
|||
|
|||
// 检查TmsiToUeId中是否存在相同的TMSI
|
|||
if (_tmsiToUeId.TryGetValue(tmsi, out int receiveUeId)) |
|||
{ |
|||
// 从UE链中获取IMSI
|
|||
string imsi = GetImsiFromUeChain(receiveUeId, ueChains); |
|||
|
|||
// 创建匹配结果
|
|||
var matchResult = new TmsiMatchResult(tmsi, requestUeId, receiveUeId, imsi); |
|||
matches.Add(matchResult); |
|||
} |
|||
} |
|||
|
|||
return matches; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 构建UE链的树形结构
|
|||
/// 根据RequestTmsiToUeId和TmsiToUeId的映射关系构建链式结构
|
|||
/// </summary>
|
|||
/// <returns>UE链的字典,键为链的根节点UE ID,值为链中的所有UE ID</returns>
|
|||
private Dictionary<int, List<int>> BuildUeChains() |
|||
{ |
|||
var ueChains = new Dictionary<int, List<int>>(); |
|||
var processedUeIds = new HashSet<int>(); |
|||
|
|||
// 遍历所有TMSI匹配关系,构建链式结构
|
|||
foreach (var requestKvp in _tmsiToUeId) |
|||
{ |
|||
uint tmsi = requestKvp.Key; |
|||
int requestUeId = requestKvp.Value; |
|||
|
|||
if (_requestTmsiToUeId.TryGetValue(tmsi, out int receiveUeId)) |
|||
{ |
|||
// 如果这个UE ID还没有被处理过
|
|||
if (!processedUeIds.Contains(requestUeId) && !processedUeIds.Contains(receiveUeId)) |
|||
{ |
|||
var chain = BuildChainFromUe(requestUeId, receiveUeId); |
|||
if (chain.Count > 0) |
|||
{ |
|||
// 使用链的根节点(最外层节点)作为键
|
|||
int rootUeId = chain[0]; |
|||
ueChains[rootUeId] = chain; |
|||
|
|||
// 标记所有UE ID为已处理
|
|||
foreach (int ueId in chain) |
|||
{ |
|||
processedUeIds.Add(ueId); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return ueChains; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 从指定的UE ID开始构建链式结构
|
|||
/// </summary>
|
|||
/// <param name="requestUeId">请求UE ID</param>
|
|||
/// <param name="receiveUeId">接收UE ID</param>
|
|||
/// <returns>链中的所有UE ID列表</returns>
|
|||
private List<int> BuildChainFromUe(int requestUeId, int receiveUeId) |
|||
{ |
|||
var chain = new List<int>(); |
|||
var visited = new HashSet<int>(); |
|||
|
|||
// 从requestUeId开始,沿着链式关系查找
|
|||
int currentUeId = requestUeId; |
|||
while (currentUeId > 0 && !visited.Contains(currentUeId)) |
|||
{ |
|||
chain.Add(currentUeId); |
|||
visited.Add(currentUeId); |
|||
|
|||
// 查找下一个UE ID(在TmsiToUeId中查找当前UE ID作为receiveUeId的情况)
|
|||
currentUeId = FindNextUeIdInChain(currentUeId); |
|||
} |
|||
|
|||
return chain; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 在链中查找下一个UE ID
|
|||
/// </summary>
|
|||
/// <param name="currentUeId">当前UE ID</param>
|
|||
/// <returns>下一个UE ID,如果没有找到则返回-1</returns>
|
|||
private int FindNextUeIdInChain(int currentUeId) |
|||
{ |
|||
// 在RequestTmsiToUeId中查找当前UE ID作为receiveUeId的情况
|
|||
foreach (var kvp in _requestTmsiToUeId) |
|||
{ |
|||
if (_tmsiToUeId.TryGetValue(kvp.Key, out int receiveUeId) && receiveUeId == currentUeId) |
|||
{ |
|||
return kvp.Value; // 返回对应的requestUeId
|
|||
} |
|||
} |
|||
|
|||
return -1; // 没有找到下一个UE ID
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 从UE链中获取IMSI
|
|||
/// 优先从链的根节点(最外层节点)获取IMSI
|
|||
/// </summary>
|
|||
/// <param name="ueId">当前UE ID</param>
|
|||
/// <param name="ueChains">UE链字典</param>
|
|||
/// <returns>对应的IMSI,如果未找到则返回空字符串</returns>
|
|||
private string GetImsiFromUeChain(int ueId, Dictionary<int, List<int>> ueChains) |
|||
{ |
|||
// 查找当前UE ID所在的链
|
|||
foreach (var chain in ueChains.Values) |
|||
{ |
|||
if (chain.Contains(ueId)) |
|||
{ |
|||
// 从链的根节点(最外层节点)开始查找IMSI
|
|||
foreach (int chainUeId in chain) |
|||
{ |
|||
string imsi = GetImsiForUeId(chainUeId); |
|||
if (!string.IsNullOrEmpty(imsi)) |
|||
{ |
|||
return imsi; |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 根据UE ID获取对应的IMSI
|
|||
/// 优先查找当前UE ID,如果未找到则查找整个UE链中的IMSI
|
|||
/// </summary>
|
|||
/// <param name="ueId">UE ID</param>
|
|||
/// <returns>对应的IMSI,如果未找到则返回空字符串</returns>
|
|||
private string GetImsiForUeId(int ueId) |
|||
{ |
|||
// 1. 首先查找当前UE ID对应的IMSI
|
|||
foreach (var imsiMapping in _imsiToUeId) |
|||
{ |
|||
if (imsiMapping.Value.Contains(ueId)) |
|||
{ |
|||
return imsiMapping.Key; |
|||
} |
|||
} |
|||
|
|||
// 2. 如果当前UE ID没有IMSI,查找整个UE链中的IMSI
|
|||
// 遍历所有IMSI映射,查找是否有任何UE ID对应的IMSI
|
|||
foreach (var imsiMapping in _imsiToUeId) |
|||
{ |
|||
if (!string.IsNullOrEmpty(imsiMapping.Key)) |
|||
{ |
|||
return imsiMapping.Key; |
|||
} |
|||
} |
|||
|
|||
return string.Empty; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取UE链的统计信息
|
|||
/// </summary>
|
|||
/// <returns>UE链统计信息</returns>
|
|||
public UeChainStats GetUeChainStats() |
|||
{ |
|||
var ueChains = BuildUeChains(); |
|||
|
|||
return new UeChainStats |
|||
{ |
|||
TotalChains = ueChains.Count, |
|||
TotalUeIds = ueChains.Values.Sum(chain => chain.Count), |
|||
AverageChainLength = ueChains.Count > 0 ? (double)ueChains.Values.Sum(chain => chain.Count) / ueChains.Count : 0, |
|||
MaxChainLength = ueChains.Count > 0 ? ueChains.Values.Max(chain => chain.Count) : 0, |
|||
MinChainLength = ueChains.Count > 0 ? ueChains.Values.Min(chain => chain.Count) : 0 |
|||
}; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 获取所有UE链的详细信息
|
|||
/// </summary>
|
|||
/// <returns>UE链详细信息列表</returns>
|
|||
public List<UeChainInfo> GetUeChainDetails() |
|||
{ |
|||
var ueChains = BuildUeChains(); |
|||
var chainInfos = new List<UeChainInfo>(); |
|||
|
|||
foreach (var kvp in ueChains) |
|||
{ |
|||
int rootUeId = kvp.Key; |
|||
var chain = kvp.Value; |
|||
string imsi = GetImsiFromUeChain(rootUeId, ueChains); |
|||
|
|||
chainInfos.Add(new UeChainInfo |
|||
{ |
|||
RootUeId = rootUeId, |
|||
ChainLength = chain.Count, |
|||
UeIds = chain.ToList(), |
|||
Imsi = imsi |
|||
}); |
|||
} |
|||
|
|||
return chainInfos; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// UE链统计信息
|
|||
/// </summary>
|
|||
public class UeChainStats |
|||
{ |
|||
/// <summary>
|
|||
/// 总链数
|
|||
/// </summary>
|
|||
public int TotalChains { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 总UE ID数
|
|||
/// </summary>
|
|||
public int TotalUeIds { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 平均链长度
|
|||
/// </summary>
|
|||
public double AverageChainLength { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 最大链长度
|
|||
/// </summary>
|
|||
public int MaxChainLength { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 最小链长度
|
|||
/// </summary>
|
|||
public int MinChainLength { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// UE链详细信息
|
|||
/// </summary>
|
|||
public class UeChainInfo |
|||
{ |
|||
/// <summary>
|
|||
/// 根节点UE ID
|
|||
/// </summary>
|
|||
public int RootUeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 链长度
|
|||
/// </summary>
|
|||
public int ChainLength { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 链中的所有UE ID
|
|||
/// </summary>
|
|||
public List<int> UeIds { get; set; } = new List<int>(); |
|||
|
|||
/// <summary>
|
|||
/// 对应的IMSI
|
|||
/// </summary>
|
|||
public string Imsi { get; set; } = string.Empty; |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
using System; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// TMSI匹配结果模型
|
|||
/// 用于存储通过TMSI匹配的请求UE ID和接收UE ID
|
|||
/// </summary>
|
|||
public class TmsiMatchResult |
|||
{ |
|||
/// <summary>
|
|||
/// TMSI标识符
|
|||
/// </summary>
|
|||
public uint Tmsi { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 请求UE ID
|
|||
/// </summary>
|
|||
public int RequestUeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 接收UE ID
|
|||
/// </summary>
|
|||
public int ReceiveUeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// IMSI标识符
|
|||
/// </summary>
|
|||
public string Imsi { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="tmsi">TMSI标识符</param>
|
|||
/// <param name="requestUeId">请求UE ID</param>
|
|||
/// <param name="receiveUeId">接收UE ID</param>
|
|||
/// <param name="imsi">IMSI标识符</param>
|
|||
public TmsiMatchResult(uint tmsi, int requestUeId, int receiveUeId, string imsi = "") |
|||
{ |
|||
Tmsi = tmsi; |
|||
RequestUeId = requestUeId; |
|||
ReceiveUeId = receiveUeId; |
|||
Imsi = imsi; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 重写ToString方法,提供友好的字符串表示
|
|||
/// </summary>
|
|||
/// <returns>格式化的字符串</returns>
|
|||
public override string ToString() |
|||
{ |
|||
var imsiInfo = string.IsNullOrEmpty(Imsi) ? "" : $", IMSI: {Imsi}"; |
|||
return $"TMSI: 0x{Tmsi:X8}, RequestUE: {RequestUeId}, ReceiveUE: {ReceiveUeId}{imsiInfo}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CoreAgent.ProtocolClient.Models |
|||
{ |
|||
/// <summary>
|
|||
/// 用户设备(UE)信息模型
|
|||
/// 用于存储用户设备的基本信息,包括标识符、设备能力等
|
|||
/// </summary>
|
|||
public class UeInfo |
|||
{ |
|||
/// <summary>
|
|||
/// 用户设备唯一标识符
|
|||
/// </summary>
|
|||
public int UeId { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 国际移动用户识别码(IMSI)
|
|||
/// 用于唯一标识移动网络中的用户
|
|||
/// </summary>
|
|||
public string? Imsi { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 国际移动设备识别码(IMEI)
|
|||
/// 用于唯一标识移动设备硬件
|
|||
/// </summary>
|
|||
public string? Imei { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 协议能力信息
|
|||
/// 包含UE支持的协议栈能力和配置
|
|||
/// </summary>
|
|||
public ProtocolCaps? Caps { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 帧信息模型
|
|||
/// 用于存储无线帧相关的时序信息
|
|||
/// </summary>
|
|||
public class FrameInfo |
|||
{ |
|||
/// <summary>
|
|||
/// 最后处理的帧号
|
|||
/// </summary>
|
|||
public int Last { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 超帧号(Hyper Frame Number)
|
|||
/// 用于LTE系统中的帧同步
|
|||
/// </summary>
|
|||
public int Hfn { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 时间戳(毫秒)
|
|||
/// 默认为-1表示未初始化
|
|||
/// </summary>
|
|||
public long Timestamp { get; set; } = -1; |
|||
} |
|||
} |
|||
@ -0,0 +1,153 @@ |
|||
# Models文件夹修改记录 |
|||
|
|||
## 修改日期 |
|||
2024年12月19日 |
|||
|
|||
## 修改概述 |
|||
对Models文件夹中的所有文件进行了命名规范检查和注释改进,主要涉及以下几个方面: |
|||
|
|||
### 1. 命名规范修复 |
|||
|
|||
#### ProtocolCaps.cs |
|||
- **修复方法命名**:将 `getCategory` 改为 `GetCategory`(PascalCase) |
|||
- **修复变量命名**:将 `Cat` 改为 `categories`,`Caps` 改为 `caps` |
|||
- **修复字符串拼接**:修正了类别信息的格式化逻辑 |
|||
- **修复扩展方法类命名**:将 `ProtocolCapsExtend` 改为 `ProtocolCapsExtensions` |
|||
|
|||
#### UEInfo.cs |
|||
- **修复类命名**:将 `UEInfo` 改为 `UeInfo`(PascalCase) |
|||
- **修复文件名**:将 `UEInfo.cs` 重命名为 `UeInfo.cs` |
|||
- **保持一致性**:确保所有类名都遵循C#命名约定 |
|||
|
|||
#### CellConfig.cs |
|||
- **保持JSON序列化兼容性**:保留原有的下划线命名法用于JSON序列化 |
|||
- **添加JsonProperty特性**:为所有属性添加了 `[JsonProperty]` 特性,确保与外部API的命名约定保持一致 |
|||
- **C#属性名使用PascalCase**:在C#代码中使用标准的PascalCase命名 |
|||
- **双重命名支持**: |
|||
- C#属性名:`NAntennaDl`、`NLayerDl` 等(PascalCase) |
|||
- JSON属性名:`n_antenna_dl`、`n_layer_dl` 等(下划线命名法) |
|||
|
|||
#### ProtocolLog.cs |
|||
- **修复扩展方法类命名**:将 `ProtocolLogExtend` 改为 `ProtocolLogExtensions` |
|||
- **添加详细注释**:为扩展方法类和方法添加了完整的注释 |
|||
|
|||
### 2. 类名规范检查 |
|||
|
|||
#### 文件名与类名对应关系 |
|||
所有文件的命名都符合C#规范: |
|||
|
|||
| 文件名 | 主要类名 | 其他类名 | 状态 | |
|||
|--------|----------|----------|------| |
|||
| `CellConfig.cs` | `CellConfig` | `PucchAllocation`, `SrsResources`, `GbrConfig`, `PlmnItem` | ✅ | |
|||
| `ClientConfig.cs` | `ClientConfig` | `ClientLogsConfig`, `LogLayerConfig` | ✅ | |
|||
| `LogLayerHelp.cs` | `LogLayerHelp` | 无 | ✅ | |
|||
| `MessageHandler.cs` | `MessageHandler` | 无 | ✅ | |
|||
| `ProtocolCaps.cs` | `ProtocolCaps` | `ProtocolCapsExtensions` | ✅ | |
|||
| `ProtocolLog.cs` | `ProtocolLog` | `PhyFields`, `DataFields`, `MacFields`, `LinkIds`, `ProtocolLogExtensions` | ✅ | |
|||
| `ProtocolLogDetail.cs` | `ProtocolLogDetail` | 无 | ✅ | |
|||
| `ProtocolLogJson.cs` | `ProtocolLogJson` | `ProtocolLogDetailJson` | ✅ | |
|||
| `TmsiMatchProcessor.cs` | `TmsiMatchProcessor` | `UeChainStats`, `UeChainInfo` | ✅ | |
|||
| `TmsiMatchResult.cs` | `TmsiMatchResult` | 无 | ✅ | |
|||
| `UeInfo.cs` | `UeInfo` | `FrameInfo` | ✅ | |
|||
|
|||
### 3. 注释改进 |
|||
|
|||
#### ProtocolCaps.cs |
|||
- 添加了详细的类注释,说明LTE协议能力信息的用途 |
|||
- 为所有属性添加了详细的中文注释 |
|||
- 为扩展方法类添加了说明注释 |
|||
- 改进了方法注释,包含参数和返回值说明 |
|||
|
|||
#### UEInfo.cs |
|||
- 添加了详细的类注释,说明用户设备信息模型的用途 |
|||
- 为所有属性添加了详细的中文注释,包括IMSI、IMEI等技术术语说明 |
|||
- 为FrameInfo类添加了详细的注释 |
|||
|
|||
#### CellConfig.cs |
|||
- 添加了详细的类注释,说明小区配置的用途和JSON序列化支持 |
|||
- 为所有属性添加了详细的中文注释,包括技术参数说明 |
|||
- 为嵌套类添加了详细的注释说明 |
|||
- 明确说明了JSON序列化的命名约定 |
|||
|
|||
#### MessageHandler.cs |
|||
- 改进了类注释,详细说明了消息处理器的功能 |
|||
- 为所有属性添加了更详细的注释说明 |
|||
|
|||
#### LogLayerHelp.cs |
|||
- 添加了详细的类注释,说明日志层配置帮助类的用途 |
|||
- 为方法添加了详细的注释,说明返回值的含义 |
|||
|
|||
#### ProtocolLog.cs |
|||
- 为扩展方法类添加了详细的注释 |
|||
- 为扩展方法添加了参数和返回值说明 |
|||
|
|||
### 4. 代码质量改进 |
|||
|
|||
#### ProtocolCaps.cs |
|||
- 修复了字符串拼接逻辑错误 |
|||
- 改进了变量命名,提高代码可读性 |
|||
- 优化了条件判断逻辑 |
|||
- 修复了扩展方法类命名 |
|||
|
|||
#### CellConfig.cs |
|||
- 添加了Newtonsoft.Json引用 |
|||
- 实现了双重命名支持,既符合C#命名约定,又保持JSON序列化兼容性 |
|||
- 改进了注释的可读性和准确性 |
|||
|
|||
#### ProtocolLog.cs |
|||
- 修复了扩展方法类命名,符合C#约定 |
|||
- 添加了详细的注释说明 |
|||
|
|||
## 修改文件列表 |
|||
|
|||
1. **ProtocolCaps.cs** - 修复方法命名、扩展方法类命名和注释 |
|||
2. **UEInfo.cs** - 修复类命名、文件名和注释 |
|||
3. **CellConfig.cs** - 添加JSON序列化特性,保持API兼容性 |
|||
4. **MessageHandler.cs** - 改进注释 |
|||
5. **LogLayerHelp.cs** - 改进注释 |
|||
6. **ProtocolLog.cs** - 修复扩展方法类命名和注释 |
|||
|
|||
## 影响范围 |
|||
|
|||
- 所有修改都遵循C#命名约定 |
|||
- 注释改进提高了代码的可维护性 |
|||
- CellConfig保持了与外部API的完全兼容性 |
|||
- 扩展方法类命名符合C#约定 |
|||
- 没有破坏现有的JSON序列化功能 |
|||
|
|||
## 重要说明 |
|||
|
|||
### CellConfig的JSON序列化设计 |
|||
- **设计原则**:保持与外部API的命名约定一致性 |
|||
- **实现方式**:使用 `[JsonProperty]` 特性指定JSON属性名 |
|||
- **优势**: |
|||
- C#代码使用标准PascalCase命名,符合C#约定 |
|||
- JSON序列化使用下划线命名法,与外部API保持一致 |
|||
- 无需修改现有API调用代码 |
|||
- 支持双向序列化和反序列化 |
|||
|
|||
### 扩展方法类命名规范 |
|||
- **C#约定**:扩展方法类应以 `Extensions` 结尾 |
|||
- **修改内容**: |
|||
- `ProtocolCapsExtend` → `ProtocolCapsExtensions` |
|||
- `ProtocolLogExtend` → `ProtocolLogExtensions` |
|||
|
|||
### 示例 |
|||
```csharp |
|||
// C#属性名(PascalCase) |
|||
public int NAntennaDl { get; set; } |
|||
|
|||
// JSON序列化后的名称(下划线命名法) |
|||
[JsonProperty("n_antenna_dl")] |
|||
|
|||
// 扩展方法类命名(符合C#约定) |
|||
public static class ProtocolCapsExtensions |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
- CellConfig的修改确保了向后兼容性,不会影响现有的API调用 |
|||
- 扩展方法类重命名可能需要更新相关的引用代码 |
|||
- 其他文件的命名修改可能需要更新相关的引用代码 |
|||
- 建议在部署前进行完整的测试,确保所有功能正常工作 |
|||
- 特别注意JSON序列化/反序列化功能的测试 |
|||
Loading…
Reference in new issue