using System.Collections.Specialized; using System.Net.WebSockets; using System.Text; namespace XFEExtension.NetCore.CyberComm; /// /// CyberComm客户端 /// public class CyberCommClient { private int reconnectTimes = -1; #region 公共属性 /// /// 指定的WS服务器URL /// public string? ServerURL { get; set; } /// /// 是否已连接 /// public bool IsConnected { get; private set; } = false; /// /// 是否自动重连 /// public bool AutoReconnect { get; set; } /// /// 自动重连最大次数 /// public int ReconnectMaxTimes { get; set; } = -1; /// /// 自动重连尝试间隔 /// public int ReconnectTryDelay { get; set; } = 100; /// /// 是否自动接收完整消息 /// public bool AutoReceiveCompletedMessage { get; set; } /// /// 收到消息时触发 /// public event EventHandler? MessageReceived; /// /// 连接关闭时触发 /// public event EventHandler? ConnectionClosed; /// /// 连接成功时触发 /// public event EventHandler? Connected; /// /// WebSocket客户端 /// public ClientWebSocket? ClientWebSocket { get; private set; } #endregion #region 公有方法 /// /// 启动CyberComm客户端 /// /// public async Task StartCyberCommClient() { StartConnect: ClientWebSocket = new ClientWebSocket(); reconnectTimes++; try { Uri serverUri = new(ServerURL!); await ClientWebSocket.ConnectAsync(serverUri, CancellationToken.None); } catch (Exception ex) { if (IsConnected == true) { ConnectionClosed?.Invoke(this, EventArgs.Empty); } IsConnected = false; if (AutoReconnect) { if (reconnectTimes <= ReconnectMaxTimes || ReconnectMaxTimes == -1) { Thread.Sleep(ReconnectTryDelay); goto StartConnect; } } else { MessageReceived?.Invoke(this, new CyberCommClientEventArgsImpl(ClientWebSocket, new XFECyberCommException("连接服务器时发生异常", ex))); return; } } Connected?.Invoke(this, EventArgs.Empty); reconnectTimes = 0; while (ClientWebSocket.State == WebSocketState.Open) { try { byte[] receiveBuffer = new byte[1024]; WebSocketReceiveResult receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); var bufferList = new List(); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); //ReceiveCompletedMessageByUsingWhile if (AutoReceiveCompletedMessage) { while (!receiveResult.EndOfMessage) { receiveResult = await ClientWebSocket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); bufferList.AddRange(receiveBuffer.Take(receiveResult.Count)); } } var receivedBinaryBuffer = bufferList.ToArray(); if (receiveResult.MessageType == WebSocketMessageType.Text) { var receivedMessage = Encoding.UTF8.GetString(receivedBinaryBuffer); MessageReceived?.Invoke(this, new CyberCommClientEventArgsImpl(ClientWebSocket, receivedMessage)); } if (receiveResult.MessageType == WebSocketMessageType.Binary) { MessageReceived?.Invoke(this, new CyberCommClientEventArgsImpl(ClientWebSocket, receivedBinaryBuffer)); } if (receiveResult.MessageType == WebSocketMessageType.Close) { await ClientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); break; } } catch (Exception ex) { if (IsConnected == true) { ConnectionClosed?.Invoke(this, EventArgs.Empty); } IsConnected = false; if (AutoReconnect) { if (AutoReconnect) { Thread.Sleep(ReconnectTryDelay); if (reconnectTimes <= ReconnectMaxTimes || ReconnectMaxTimes == -1) goto StartConnect; } } else { MessageReceived?.Invoke(this, new CyberCommClientEventArgsImpl(ClientWebSocket, new XFECyberCommException("与服务器端通讯期间发生异常", ex))); return; } } } if (AutoReconnect) { goto StartConnect; } ConnectionClosed?.Invoke(this, EventArgs.Empty); } /// /// 发送文本消息 /// /// 待发送的文本 /// 发送进程 public async Task SendTextMessage(string message) { try { byte[] sendBuffer = Encoding.UTF8.GetBytes(message); await ClientWebSocket!.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("客户端发送文本到服务器时出现异常", ex); } } /// /// 发送二进制消息 /// /// 待发送的二进制数据 /// 发送进程 public async Task SendBinaryMessage(byte[] message) { try { await ClientWebSocket!.SendAsync(new ArraySegment(message), WebSocketMessageType.Binary, true, CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("客户端发送二进制数据到服务器时出现异常", ex); } } /// /// 关闭CyberComm客户端 /// /// public async Task CloseCyberCommClient() { await ClientWebSocket!.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); } #endregion #region 构造函数 /// /// CyberComm客户端 /// /// WS服务器地址 /// 是否自动重连 /// 是否自动接收完整消息 public CyberCommClient(string serverURL, bool autoReconnect = true, bool autoReceiveCompletedMessage = true) { AutoReconnect = autoReconnect; AutoReceiveCompletedMessage = autoReceiveCompletedMessage; ServerURL = serverURL; } /// /// CyberComm客户端 /// public CyberCommClient() { } #endregion } #region 事件参数及其实现类 /// /// CyberComm客户端事件参数 /// public abstract class CyberCommClientEventArgs : EventArgs { /// /// 消息类型 /// public BackMessageType MessageType { get; } /// /// 当前WebSocket /// public ClientWebSocket CurrentWebSocket { get; } /// /// 文本消息 /// public string? TextMessage { get; } /// /// 异常消息(如果有的话) /// public XFECyberCommException? Exception { get; } /// /// 二进制消息 /// public byte[]? BinaryMessage { get; } /// /// 发送文本消息 /// /// 待发送的文本 /// /// 发送进程 public async Task ReplyMessage(string message) { try { byte[] sendBuffer = Encoding.UTF8.GetBytes(message); await CurrentWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("收到服务器端数据后客户端回复文本数据时出现异常", ex); } } /// /// 关闭连接 /// /// public async Task Close() { try { await CurrentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection Closed", CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("关闭客户端连接时出现异常", ex); } } internal CyberCommClientEventArgs(ClientWebSocket clientWebSocket, string message) { CurrentWebSocket = clientWebSocket; TextMessage = message; MessageType = BackMessageType.Text; } internal CyberCommClientEventArgs(ClientWebSocket clientWebSocket, byte[] bytes) { CurrentWebSocket = clientWebSocket; BinaryMessage = bytes; MessageType = BackMessageType.Binary; } internal CyberCommClientEventArgs(ClientWebSocket clientWebSocket, XFECyberCommException ex) { CurrentWebSocket = clientWebSocket; Exception = ex; MessageType = BackMessageType.Error; } } /// /// CyberComm服务器事件参数 /// public abstract class CyberCommServerEventArgs { /// /// 消息类型 /// public BackMessageType MessageType { get; } /// /// 当前WebSocket /// public WebSocket CurrentWebSocket { get; } /// /// 客户端请求头 /// public NameValueCollection WSHeader { get; } /// /// 异常消息(如果有的话) /// public XFECyberCommException? Exception { get; } /// /// 客户端IP地址 /// public string IpAddress { get; } /// /// 文本消息 /// public string? TextMessage { get; } /// /// 二进制消息 /// public byte[]? BinaryMessage { get; } /// /// 发送文本消息 /// /// 待发送的文本 /// /// 发送进程 public async Task ReplyMessage(string message) { try { byte[] sendBuffer = Encoding.UTF8.GetBytes(message); await CurrentWebSocket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("收到客户端数据后服务器端回复文本时出现异常", ex); } } /// /// 发送二进制消息 /// /// 二进制消息 /// /// public async Task ReplyBinaryMessage(byte[] bytes) { try { await CurrentWebSocket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Binary, true, CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("收到客户端数据后服务器端回复二进制数据时出现异常", ex); } } /// /// 关闭连接 /// /// public async Task Close() { try { await CurrentWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection Closed", CancellationToken.None); } catch (Exception ex) { throw new XFECyberCommException("关闭服务器端连接时出现异常", ex); } } /// /// 强制关闭连接 /// /// public void ForceClose() { try { CurrentWebSocket.Abort(); } catch (Exception ex) { throw new XFECyberCommException("强制关闭服务器端连接时出现异常", ex); } } internal CyberCommServerEventArgs(WebSocket webSocket, string message, string ipAddress, NameValueCollection wsHeader) { CurrentWebSocket = webSocket; TextMessage = message; IpAddress = ipAddress; MessageType = BackMessageType.Text; WSHeader = wsHeader; } internal CyberCommServerEventArgs(WebSocket webSocket, byte[] bytes, string ipAddress, NameValueCollection wsHeader) { CurrentWebSocket = webSocket; BinaryMessage = bytes; IpAddress = ipAddress; MessageType = BackMessageType.Binary; WSHeader = wsHeader; } internal CyberCommServerEventArgs(WebSocket webSocket, XFECyberCommException ex, string ipAddress, NameValueCollection wsHeader) { CurrentWebSocket = webSocket; Exception = ex; IpAddress = ipAddress; MessageType = BackMessageType.Error; WSHeader = wsHeader; } } class CyberCommClientEventArgsImpl : CyberCommClientEventArgs { internal CyberCommClientEventArgsImpl(ClientWebSocket clientWebSocket, string message) : base(clientWebSocket, message) { } internal CyberCommClientEventArgsImpl(ClientWebSocket clientWebSocket, byte[] bytes) : base(clientWebSocket, bytes) { } internal CyberCommClientEventArgsImpl(ClientWebSocket clientWebSocket, XFECyberCommException ex) : base(clientWebSocket, ex) { } } class CyberCommServerEventArgsImpl : CyberCommServerEventArgs { internal CyberCommServerEventArgsImpl(WebSocket webSocket, string message, string ipAddress, NameValueCollection wsHeader) : base(webSocket, message, ipAddress, wsHeader) { } internal CyberCommServerEventArgsImpl(WebSocket webSocket, byte[] bytes, string ipAddress, NameValueCollection wsHeader) : base(webSocket, bytes, ipAddress, wsHeader) { } internal CyberCommServerEventArgsImpl(WebSocket webSocket, XFECyberCommException ex, string ipAddress, NameValueCollection wsHeader) : base(webSocket, ex, ipAddress, wsHeader) { } } #endregion