WebSocketHelper
WebSocketHelper 帮助类
Section titled “WebSocketHelper 帮助类”WebSocketHelper 是一个 WebSocket 客户端和服务器辅助类,为 WebSocket 通信提供了丰富的功能,包括连接管理、消息收发、心跳检测、自动重连、消息队列、事件驱动模型、线程安全操作、自动资源管理等,旨在封装 WebSocket 的复杂性,使 WebSocket 的使用更加简单和可靠。
- 🔄 自动连接管理和重连机制
- 💓 内置心跳检测功能
- 📨 支持文本和二进制消息收发
- 📦 消息队列支持(断线时缓存消息)
- ⚡ 事件驱动的异步编程模型
- 🔒 线程安全的操作
- 🧹 自动资源管理和清理
- 🖥️ 内置 WebSocket 服务器支持
WebSocketHelper 客户端
Section titled “WebSocketHelper 客户端”public class WebSocketHelper : IDisposablepublic WebSocketHelper( int heartbeatInterval = 30000, int maxReconnectAttempts = 5, int reconnectDelay = 5000, int receiveBufferSize = 4096, int sendBufferSize = 4096, TimeSpan? connectionTimeout = null, Action<ClientWebSocketOptions> configureOptions = null)| 参数名 | 类型 | 描述 | | -------------------- | ------------------------------ | ---------------------------- | | heartbeatInterval | int | 心跳检测间隔(毫秒),默认 30000ms,0 表示禁用 | | maxReconnectAttempts | int | 最大重连次数,默认 5 次,0 表示无限重连 | | reconnectDelay | int | 重连延迟时间(毫秒),默认 5000ms | | receiveBufferSize | int | 接收缓冲区大小(字节),默认 4096 | | sendBufferSize | int | 发送缓冲区大小(字节),默认 4096 | | connectionTimeout | TimeSpan? | 连接超时时间,默认 30 秒 | | configureOptions | Action<ClientWebSocketOptions> | WebSocket 选项配置委托 |
// 使用默认配置var wsHelper = new WebSocketHelper();
// 自定义配置var wsHelper = new WebSocketHelper( heartbeatInterval: 10000, maxReconnectAttempts: 3, reconnectDelay: 2000, receiveBufferSize: 8192, sendBufferSize: 8192, connectionTimeout: TimeSpan.FromSeconds(60));
// 使用配置委托设置 SSLvar wsHelper = new WebSocketHelper(configureOptions: options =>{ options.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => true;});| 属性名 | 类型 | 描述 | | ------------------ | -------------- | --------------------- | | State | WebSocketState | 获取当前 WebSocket 连接状态 | | IsConnected | bool | 获取是否已建立连接 | | ConnectedUri | Uri | 获取当前连接的 URI | | AutoReconnect | bool | 获取或设置是否启用自动重连,默认 true | | EnableMessageQueue | bool | 获取或设置是否启用消息队列,默认 true | | QueuedMessageCount | int | 获取消息队列中的消息数量 |
OnConnected
Section titled “OnConnected”连接成功时触发
public event EventHandler<WebSocketConnectedEventArgs> OnConnected;OnDisconnected
Section titled “OnDisconnected”连接断开时触发
public event EventHandler<WebSocketDisconnectedEventArgs> OnDisconnected;OnMessageReceived
Section titled “OnMessageReceived”接收到文本消息时触发
public event EventHandler<WebSocketMessageReceivedEventArgs> OnMessageReceived;OnBinaryReceived
Section titled “OnBinaryReceived”接收到二进制消息时触发
public event EventHandler<WebSocketBinaryReceivedEventArgs> OnBinaryReceived;OnError
Section titled “OnError”发生错误时触发
public event EventHandler<WebSocketErrorEventArgs> OnError;OnHeartbeat
Section titled “OnHeartbeat”心跳检测时触发
public event EventHandler<WebSocketHeartbeatEventArgs> OnHeartbeat;OnReconnecting
Section titled “OnReconnecting”重连时触发
public event EventHandler<WebSocketReconnectingEventArgs> OnReconnecting;OnMessageSent
Section titled “OnMessageSent”消息发送完成时触发
public event EventHandler<WebSocketMessageSentEventArgs> OnMessageSent;ConnectAsync
Section titled “ConnectAsync”连接到 WebSocket 服务器
public Task ConnectAsync(Uri uri, CancellationToken cancellationToken = default)| 参数名 | 类型 | 描述 | | ----------------- | ----------------- | --------------- | | uri | Uri | WebSocket 服务器地址 | | cancellationToken | CancellationToken | 取消令牌 |
异常:
- ArgumentNullException: URI 为空时抛出
- InvalidOperationException: 已经在连接中时抛出
DisconnectAsync
Section titled “DisconnectAsync”断开 WebSocket 连接
public Task DisconnectAsync( WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure, string statusDescription = "Normal closure", CancellationToken cancellationToken = default)ReconnectAsync
Section titled “ReconnectAsync”重新连接到 WebSocket 服务器
public Task ReconnectAsync(CancellationToken cancellationToken = default)异常:
- InvalidOperationException: 没有可重连的 URI 时抛出
SendMessageAsync
Section titled “SendMessageAsync”发送文本消息
public Task SendMessageAsync(string message, CancellationToken cancellationToken = default)注意: 如果未连接且启用了消息队列,消息将被缓存到队列中。
SendBinaryAsync
Section titled “SendBinaryAsync”发送二进制消息
public Task SendBinaryAsync(byte[] data, CancellationToken cancellationToken = default)SendMessagesAsync
Section titled “SendMessagesAsync”批量发送文本消息
public Task SendMessagesAsync(IEnumerable<string> messages, CancellationToken cancellationToken = default)ClearMessageQueue
Section titled “ClearMessageQueue”清空消息队列
public void ClearMessageQueue()WebSocketServerHelper 服务器
Section titled “WebSocketServerHelper 服务器”public class WebSocketServerHelper : IDisposablepublic WebSocketServerHelper(int heartbeatIntervalSec = 30)public WebSocketServerHelper(int port, int heartbeatIntervalSec = 30)| 参数名 | 类型 | 描述 | | -------------------- | --- | ------------------------ | | port | int | 服务器端口(仅用于标识) | | heartbeatIntervalSec | int | 心跳检测间隔(秒),默认 30 秒,0 表示禁用 |
| 属性名 | 类型 | 描述 | | -------------------- | -------------------- | ----------------- | | ConnectedClientCount | int | 获取当前连接的客户端数量 | | IsRunning | bool | 获取服务器是否正在运行 | | ConnectedClientIds | IEnumerable<string> | 获取所有已连接的客户端 ID 列表 | | GroupNames | IEnumerable<string> | 获取所有组名称 |
OnServerStarted
Section titled “OnServerStarted”服务器启动时触发
public event EventHandler OnServerStarted;OnServerStopped
Section titled “OnServerStopped”服务器停止时触发
public event EventHandler OnServerStopped;OnClientConnected
Section titled “OnClientConnected”客户端连接时触发
public event EventHandler<ClientConnectedEventArgs> OnClientConnected;OnClientDisconnected
Section titled “OnClientDisconnected”客户端断开连接时触发
public event EventHandler<ClientDisconnectedEventArgs> OnClientDisconnected;OnMessageReceived
Section titled “OnMessageReceived”收到消息时触发
public event EventHandler<MessageReceivedEventArgs> OnMessageReceived;OnMessageSent
Section titled “OnMessageSent”发送消息时触发
public event EventHandler<MessageSentEventArgs> OnMessageSent;OnHeartbeat
Section titled “OnHeartbeat”心跳检测时触发
public event EventHandler<HeartbeatEventArgs> OnHeartbeat;OnError
Section titled “OnError”发生错误时触发
public event EventHandler<WebSocketErrorEventArgs> OnError;StartServerAsync
Section titled “StartServerAsync”启动 WebSocket 服务器
public Task StartServerAsync(IEnumerable<string> prefixes)public Task StartServerAsync(string prefix)| 参数名 | 类型 | 描述 | | -------- | -------------------- | ------------ | | prefixes | IEnumerable<string> | 监听的 URL 前缀列表 | | prefix | string | 监听的 URL 前缀 |
示例:
var server = new WebSocketServerHelper(heartbeatIntervalSec: 30);await server.StartServerAsync("http://localhost:8080/");StopServer
Section titled “StopServer”停止 WebSocket 服务器
public void StopServer()SendMessageToClientAsync
Section titled “SendMessageToClientAsync”向指定客户端发送消息
public Task SendMessageToClientAsync(string clientId, string message, CancellationToken cancellationToken = default)SendBinaryToClientAsync
Section titled “SendBinaryToClientAsync”向指定客户端发送二进制消息
public Task SendBinaryToClientAsync(string clientId, byte[] data, CancellationToken cancellationToken = default)BroadcastMessageAsync
Section titled “BroadcastMessageAsync”广播消息给所有连接的客户端
public Task BroadcastMessageAsync(string message, CancellationToken cancellationToken = default)public Task BroadcastMessageAsync(string message, string excludeClientId, CancellationToken cancellationToken = default)BroadcastToGroupAsync
Section titled “BroadcastToGroupAsync”向指定组广播消息
public Task BroadcastToGroupAsync(string groupName, string message, CancellationToken cancellationToken = default)DisconnectClient
Section titled “DisconnectClient”断开指定客户端连接
public void DisconnectClient(string clientId, WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure, string statusDescription = "Normal closure")GetClientInfo
Section titled “GetClientInfo”获取客户端信息
public ClientInfo GetClientInfo(string clientId)SetClientCustomInfo
Section titled “SetClientCustomInfo”设置客户端自定义信息
public void SetClientCustomInfo(string clientId, object customInfo)AddClientToGroup
Section titled “AddClientToGroup”将客户端添加到组
public void AddClientToGroup(string clientId, string groupName)RemoveClientFromGroup
Section titled “RemoveClientFromGroup”将客户端从组中移除
public void RemoveClientFromGroup(string clientId, string groupName)GetClientsInGroup
Section titled “GetClientsInGroup”获取组中的所有客户端 ID
public IEnumerable<string> GetClientsInGroup(string groupName)WebSocketConnectedEventArgs
Section titled “WebSocketConnectedEventArgs”| 属性名 | 类型 | 描述 | | ------------- | -------- | ------- | | Uri | Uri | 连接的 URI | | ConnectedTime | DateTime | 连接时间 |
WebSocketDisconnectedEventArgs
Section titled “WebSocketDisconnectedEventArgs”| 属性名 | 类型 | 描述 | | ----------------- | -------------------- | ---- | | CloseStatus | WebSocketCloseStatus | 关闭状态 | | StatusDescription | string | 状态描述 | | DisconnectedTime | DateTime | 断开时间 |
WebSocketMessageReceivedEventArgs
Section titled “WebSocketMessageReceivedEventArgs”| 属性名 | 类型 | 描述 | | ------------ | -------- | ---- | | Message | string | 消息内容 | | ReceivedTime | DateTime | 接收时间 |
WebSocketBinaryReceivedEventArgs
Section titled “WebSocketBinaryReceivedEventArgs”| 属性名 | 类型 | 描述 | | ------------ | -------- | ----- | | Data | byte[] | 二进制数据 | | ReceivedTime | DateTime | 接收时间 |
WebSocketErrorEventArgs
Section titled “WebSocketErrorEventArgs”| 属性名 | 类型 | 描述 | | --------- | --------- | ---------------- | | ClientId | string | 客户端 ID(可能为 null) | | Exception | Exception | 异常信息 | | ErrorTime | DateTime | 发生时间 |
WebSocketHeartbeatEventArgs
Section titled “WebSocketHeartbeatEventArgs”| 属性名 | 类型 | 描述 | | ------------- | -------- | --------- | | IsSuccess | bool | 是否成功 | | HeartbeatTime | DateTime | 心跳时间 | | ErrorMessage | string | 错误消息(如果有) |
WebSocketReconnectingEventArgs
Section titled “WebSocketReconnectingEventArgs”| 属性名 | 类型 | 描述 | | ---------------- | -------- | ------ | | Attempt | int | 当前重连次数 | | MaxAttempts | int | 最大重连次数 | | ReconnectingTime | DateTime | 重连时间 |
WebSocketMessageSentEventArgs
Section titled “WebSocketMessageSentEventArgs”| 属性名 | 类型 | 描述 | | -------- | -------- | -------- | | Message | string | 消息内容 | | IsBinary | bool | 是否是二进制消息 | | SentTime | DateTime | 发送时间 |
ClientInfo
Section titled “ClientInfo”| 属性名 | 类型 | 描述 | | ------------------ | -------- | ---------- | | ClientId | string | 客户端 ID | | ConnectedTime | DateTime | 连接时间 | | RemoteEndPoint | EndPoint | 远程端点 | | UserAgent | string | User-Agent | | LastHeartbeatTime | DateTime | 最后心跳时间 | | CustomInfo | object | 自定义信息 | | ConnectionDuration | TimeSpan | 连接持续时间 |
客户端基本使用
Section titled “客户端基本使用”using System;using System.Threading.Tasks;using Chet.Utils.Helpers;
class Program{ static async Task Main(string[] args) { var wsHelper = new WebSocketHelper();
// 订阅事件 wsHelper.OnConnected += (sender, e) => Console.WriteLine($"Connected to {e.Uri} at {e.ConnectedTime}");
wsHelper.OnDisconnected += (sender, e) => Console.WriteLine($"Disconnected: {e.CloseStatus} - {e.StatusDescription}");
wsHelper.OnMessageReceived += (sender, e) => Console.WriteLine($"Received: {e.Message}");
wsHelper.OnBinaryReceived += (sender, e) => Console.WriteLine($"Received binary data: {e.Data.Length} bytes");
wsHelper.OnError += (sender, e) => Console.WriteLine($"Error: {e.Exception.Message}");
wsHelper.OnHeartbeat += (sender, e) => Console.WriteLine($"Heartbeat: {(e.IsSuccess ? "Success" : e.ErrorMessage)}");
wsHelper.OnReconnecting += (sender, e) => Console.WriteLine($"Reconnecting: attempt {e.Attempt}/{e.MaxAttempts}");
try { await wsHelper.ConnectAsync(new Uri("wss://echo.websocket.org")); await wsHelper.SendMessageAsync("Hello WebSocket!"); await Task.Delay(5000); await wsHelper.DisconnectAsync(); } catch (Exception ex) { Console.WriteLine($"Exception: {ex.Message}"); } finally { wsHelper.Dispose(); } }}服务器基本使用
Section titled “服务器基本使用”using System;using System.Threading.Tasks;using Chet.Utils.Helpers;
class Program{ static async Task Main(string[] args) { var server = new WebSocketServerHelper(heartbeatIntervalSec: 30);
// 订阅事件 server.OnServerStarted += (sender, e) => Console.WriteLine("Server started");
server.OnClientConnected += (sender, e) => Console.WriteLine($"Client connected: {e.ClientInfo.ClientId}");
server.OnClientDisconnected += (sender, e) => Console.WriteLine($"Client disconnected: {e.ClientId}");
server.OnMessageReceived += async (sender, e) => { Console.WriteLine($"Message from {e.ClientId}: {e.Message}"); await server.SendMessageToClientAsync(e.ClientId, $"Echo: {e.Message}"); };
server.OnError += (sender, e) => Console.WriteLine($"Error: {e.Exception.Message}");
try { await server.StartServerAsync("http://localhost:8080/"); Console.WriteLine("Press any key to stop..."); Console.ReadKey(); } finally { server.Dispose(); } }}消息队列使用
Section titled “消息队列使用”var wsHelper = new WebSocketHelper();wsHelper.EnableMessageQueue = true;
// 即使未连接,消息也会被缓存await wsHelper.SendMessageAsync("Message 1");await wsHelper.SendMessageAsync("Message 2");
Console.WriteLine($"Queued messages: {wsHelper.QueuedMessageCount}"); // 输出: 2
// 连接后自动发送队列中的消息await wsHelper.ConnectAsync(new Uri("wss://example.com"));var server = new WebSocketServerHelper();
server.OnClientConnected += (sender, e) =>{ // 将客户端添加到特定组 server.AddClientToGroup(e.ClientInfo.ClientId, "chat-room");};
// 向组广播消息await server.BroadcastToGroupAsync("chat-room", "Hello everyone in the chat room!");1. 正确处理生命周期
Section titled “1. 正确处理生命周期”public class WebSocketService : IDisposable{ private WebSocketHelper _webSocketHelper; private bool _disposed;
public async Task StartAsync() { _webSocketHelper = new WebSocketHelper(); _webSocketHelper.OnMessageReceived += OnMessageReceived; await _webSocketHelper.ConnectAsync(new Uri("wss://server")); }
public async Task StopAsync() { if (_webSocketHelper != null) { await _webSocketHelper.DisconnectAsync(); _webSocketHelper.OnMessageReceived -= OnMessageReceived; _webSocketHelper.Dispose(); _webSocketHelper = null; } }
public void Dispose() { if (!_disposed) { StopAsync().GetAwaiter().GetResult(); _disposed = true; } }}2. 异常处理
Section titled “2. 异常处理”try{ await wsHelper.ConnectAsync(new Uri("wss://server"));}catch (WebSocketException wsex){ Console.WriteLine($"WebSocket error: {wsex.Message}");}catch (OperationCanceledException){ Console.WriteLine("Connection cancelled");}catch (Exception ex){ Console.WriteLine($"General error: {ex.Message}");}3. 消息处理
Section titled “3. 消息处理”wsHelper.OnMessageReceived += async (sender, e) =>{ try { var data = JsonSerializer.Deserialize<YourDataType>(e.Message); await ProcessMessageAsync(data); } catch (JsonException jsonEx) { Console.WriteLine($"Failed to parse message: {jsonEx.Message}"); }};- 线程安全: WebSocketHelper 设计为线程安全,可以在多个线程中同时调用其方法。
- 资源管理: 使用完毕后请调用 Dispose() 方法释放资源,或者使用 using 语句。
- 异常处理: 网络操作可能会抛出各种异常,建议始终使用 try-catch 包装关键操作。
- 自动重连: 类内置自动重连机制,但不会无限重试,达到最大重连次数后会彻底断开连接。
- 心跳检测: 默认每 30 秒发送一次心跳包,可以通过构造函数自定义间隔或禁用。
- 消息队列: 启用消息队列后,断线时的消息会被缓存,重连后自动发送。
此类基于 .NET Standard 2.0+ 实现,兼容以下平台:
- .NET Core 2.0+
- .NET Framework 4.6.1+
- .NET 5.0+
- 检查 URI 格式是否正确(应以 ws:// 或 wss:// 开头)
- 确认网络连接正常
- 检查防火墙设置
- 验证服务器是否可用
消息无法发送
Section titled “消息无法发送”- 确认连接状态为 Open
- 检查消息大小是否超出限制
- 查看是否有异常事件被触发
- 检查网络延迟
- 调整心跳间隔时间
- 确认服务器支持 Ping/Pong 帧
服务器启动失败
Section titled “服务器启动失败”- 确保端口未被占用
- 检查 URL 前缀格式(必须以 / 结尾)
- 确保有足够的权限监听指定端口