using Cysharp.Threading.Tasks; using NativeWebSocket; using System; using System.Collections.Generic; using System.Text; using UnityEngine; /// /// WebSocket 网络服务 - 用于小游戏平台 /// public class WebSocketNetworkService : INetworkService { private WebSocket webSocket; private NetworkState _state = NetworkState.Disconnected; private string currentUrl; // 统计信息(与 ClientSocket 对齐) private long getBytesTotal = 0; // 接收的数据总量 private long sendBytesTotal = 0; // 发送的数据总量 private DateTime m_LastPackageTime = DateTime.MinValue; /// /// 最后收包时间(实现接口) /// public DateTime LastPackageTime { get { return m_LastPackageTime; } } // 发送队列(与 ClientSocket 对齐) private Queue sendQueue = new Queue(); private bool isSending = false; // 编解码器(与 ClientSocket 对齐) private GameNetEncode encoder = new GameNetEncode(); // 服务器类型(与 ClientSocket 对齐) private ServerType socketType = ServerType.Main; /// /// 构造函数(与 ClientSocket 对齐) /// public WebSocketNetworkService(ServerType type) { this.socketType = type; } public NetworkState State { get => _state; private set { if (_state != value) { _state = value; OnStateChanged?.Invoke(value); } } } public bool IsConnected => State == NetworkState.Connected; public event Action OnStateChanged; /// /// 连接到 WebSocket 服务器 /// public async UniTask ConnectAsync(string url) { if (IsConnected) { Debug.LogWarning($"[WebSocket] 已经连接到 {currentUrl}"); return true; } try { State = NetworkState.Connecting; currentUrl = url; Debug.Log($"[WebSocket] 开始连接: {url}"); // 创建 WebSocket 连接(不传 headers,使用默认行为) webSocket = new WebSocket(url); // 注册事件监听 webSocket.OnOpen += OnWebSocketOpen; webSocket.OnMessage += OnWebSocketMessage; webSocket.OnError += OnWebSocketError; webSocket.OnClose += OnWebSocketClose; // 开始连接 Debug.Log($"[WebSocket] 调用 Connect()..."); // 启动连接任务(不等待它完成,因为它会一直运行到连接关闭) var connectTask = webSocket.Connect(); // 等待 OnOpen 触发(最多5秒) var timeout = DateTime.Now.AddSeconds(5); while (State != NetworkState.Connected && DateTime.Now < timeout) { await UniTask.Yield(); } Debug.Log($"[WebSocket] 等待结束,当前状态: {State}, WebSocket.State: {webSocket.State}"); if (IsConnected) { Debug.Log("[WebSocket] ✓ 连接成功"); return true; } else { Debug.LogError($"[WebSocket] ✗ 连接超时或失败,State={State}, WebSocket.State={webSocket?.State}"); return false; } } catch (Exception ex) { Debug.LogError($"[WebSocket] 连接异常: {ex.Message}\n{ex.StackTrace}"); return false; } } /// /// 断开连接(异步) /// public async UniTask DisconnectAsync() { Debug.LogWarning($"[WebSocket] DisconnectAsync 被调用! State={State}"); Debug.LogWarning($"[WebSocket] 调用堆栈:\n{System.Environment.StackTrace}"); if (webSocket != null) { // 清空发送队列 lock (sendQueue) { sendQueue.Clear(); isSending = false; } await webSocket.Close(); webSocket = null; } State = NetworkState.Disconnected; } /// /// 断开连接(同步,适配 ClientSocket.CloseConnect) /// public void Disconnect() { Debug.LogWarning($"[WebSocket] Disconnect 被调用! State={State}"); Debug.LogWarning($"[WebSocket] 调用堆栈:\n{System.Environment.StackTrace}"); DisconnectAsync().Forget(); } /// /// 发送协议包(与 ClientSocket.SendInfo 完全对齐) /// public void SendInfo(GameNetPackBasic protocol) { if (!IsConnected) { Debug.LogError("[WebSocket] 未连接,无法发送协议包"); return; } if (protocol == null) { Debug.LogError("[WebSocket] 要发的信息对象为空"); return; } try { // 1. 准备协议数据 if (protocol.combineBytes == null) { protocol.WriteToBytes(); } // 2. 组合数据(与 ClientSocket.SendInfo 一致) protocol.CombineDatas(encoder); #if UNITY_EDITOR // 3. 记录包信息到 NetPackageWindow(与 ClientSocket 对齐) NetPkgCtl.RecordPackage(socketType, protocol.vInfoCont, NetPackagetType.Client, protocol.ToString(), FieldPrint.PrintFields(protocol), FieldPrint.PrintFieldsExpand(protocol, true)); #endif byte[] data = protocol.dataBytes; // 4. 加密 byte[] encryptedData = encoder.BaseXorAdd(data); // 5. 添加包头(6字节:0xFF 0xCC + 4字节长度小端序,与 ClientSocket 一致) int bodyLength = encryptedData.Length; byte[] sendData = new byte[bodyLength + 6]; sendData[0] = 0xFF; // 与 ClientSocket 一致 sendData[1] = 0xCC; // 与 ClientSocket 一致 // 使用 BitConverter 小端序(与 ClientSocket 一致) byte[] lengthBytes = BitConverter.GetBytes(bodyLength); Array.Copy(lengthBytes, 0, sendData, 2, 4); Array.Copy(encryptedData, 0, sendData, 6, bodyLength); // 6. 更新统计(与 ClientSocket 对齐) sendBytesTotal += sendData.Length; // 7. 发送(异步) SendAsync(sendData).Forget(); } catch (Exception ex) { Debug.LogError($"[WebSocket] 发送协议包异常: {ex.Message}\n{ex.StackTrace}"); } } /// /// 发送二进制数据(同步重载,适配 ClientSocket.SendInfo) /// public void SendInfo(byte[] data) { SendAsync(data).Forget(); } /// /// 发送二进制数据(带队列机制,与 ClientSocket 对齐) /// public async UniTask SendAsync(byte[] data) { if (!IsConnected) { Debug.LogError("[WebSocket] 未连接,无法发送数据"); return; } if (data == null || data.Length == 0) { Debug.LogError("[WebSocket] 发送数据为空"); return; } // 检查消息大小(最大 64KB) if (data.Length > 65536) { Debug.LogError($"[WebSocket] 消息过大: {data.Length} bytes(最大 64KB)"); return; } // 队列机制:如果正在发送,加入队列 lock (sendQueue) { if (isSending) { sendQueue.Enqueue(data); Debug.Log($"[WebSocket] 数据加入发送队列,队列长度: {sendQueue.Count}"); return; } else { isSending = true; } } // 发送数据 await SendBytesInternal(data); } /// /// 内部发送方法(处理队列) /// private async UniTask SendBytesInternal(byte[] data) { try { await webSocket.Send(data); sendBytesTotal += data.Length; Debug.Log($"[WebSocket] 发送成功: {data.Length} bytes,总发送: {sendBytesTotal} bytes"); // 处理队列中的下一个消息 byte[] nextData = null; lock (sendQueue) { if (sendQueue.Count > 0) { nextData = sendQueue.Dequeue(); } else { isSending = false; } } if (nextData != null) { await SendBytesInternal(nextData); } } catch (Exception ex) { Debug.LogError($"[WebSocket] 发送失败: {ex.Message}"); lock (sendQueue) { isSending = false; } } } /// /// WebSocket 连接成功回调 /// private void OnWebSocketOpen() { Debug.Log($"[WebSocket] ✓✓✓ OnOpen 事件触发 - 连接成功: {currentUrl}"); Debug.Log($"[WebSocket] WebSocket.State: {webSocket?.State}"); State = NetworkState.Connected; Debug.Log($"[WebSocket] 当前状态已更新为: {State}"); } /// /// WebSocket 消息接收回调(与 ClientSocket.ReadInfo 对齐) /// private void OnWebSocketMessage(byte[] data) { // 完整的包处理流程(与 ClientSocket.ReadInfo 对齐) try { if (data == null || data.Length < 6) { Debug.LogError($"[WebSocket] 收到无效数据包: {data?.Length ?? 0} bytes"); return; } // 更新统计信息 getBytesTotal += data.Length; Debug.Log($"[WebSocket] 收到原始消息: {data.Length} bytes"); // 检查包头(0xFF 0xCC,与 ClientSocket 一致) if (data[0] != 0xFF || data[1] != 0xCC) { Debug.LogError($"[WebSocket] 包头错误: 0x{data[0]:X2} 0x{data[1]:X2},期望 0xFF 0xCC"); return; } // 读取包体长度(小端序,与 ClientSocket 一致) int bodyLength = BitConverter.ToInt32(data, 2); if (data.Length < bodyLength + 6) { Debug.LogError($"[WebSocket] 包长度不匹配: 声明 {bodyLength + 6}, 实际 {data.Length}"); return; } // 提取加密的包体(跳过6字节包头) byte[] encryptedBody = new byte[bodyLength]; Array.Copy(data, 6, encryptedBody, 0, bodyLength); // 解密包体(与 ClientSocket.ReadInfo 一致) byte[] decryptedData = encoder.BaseXorSub(encryptedBody); // 解析 CMD(前2字节) byte[] cmdBytes = new byte[2]; Array.Copy(decryptedData, 0, cmdBytes, 0, 2); var cmd = (ushort)((ushort)(cmdBytes[0] << 8) + cmdBytes[1]); Debug.Log($"[WebSocket] 解密成功,CMD=0x{cmd:X4}"); bool isRegist = false; // 转换协议包(与 ClientSocket.ReadInfo 一致) if (PackageRegedit.Contain(cmd)) { GameNetPackBasic pack = PackageRegedit.TransPack(socketType, cmd, decryptedData); if (pack != null) { Debug.Log($"[WebSocket] 收到协议: {pack.GetType().Name}"); m_LastPackageTime = DateTime.Now; // 直接推送到 GameNetSystem(与 ClientSocket 一致) GameNetSystem.Instance.PushPackage(pack, socketType); isRegist = true; } } // 未注册封包处理(与 ClientSocket 一致) if (!isRegist) { #if UNITY_EDITOR PackageRegedit.TransPack(socketType, cmd, decryptedData); #endif } } catch (Exception ex) { Debug.LogError($"[WebSocket] 消息处理异常: {ex.Message}\n{ex.StackTrace}"); } } /// /// WebSocket 错误回调 /// private void OnWebSocketError(string error) { Debug.LogError($"[WebSocket] ✗ OnError 事件触发: {error}"); Debug.LogError($"[WebSocket] 当前状态: {State}, WebSocket.State: {webSocket?.State}"); } /// /// WebSocket 关闭回调(不自动重连,与 ClientSocket 一致) /// private void OnWebSocketClose(WebSocketCloseCode code) { Debug.LogError($"[WebSocket] ⊗ OnClose 事件触发!"); Debug.LogError($"[WebSocket] 关闭代码: {code} ({(int)code})"); Debug.LogError($"[WebSocket] 之前状态: {State}\n"); // 判断是谁关闭的 if (code == WebSocketCloseCode.Normal) { Debug.LogWarning("[WebSocket] → 正常关闭(客户端主动)"); } else if (code == WebSocketCloseCode.Abnormal) { Debug.LogError("[WebSocket] → 异常关闭(连接丢失或服务器断开)"); } else { Debug.LogError($"[WebSocket] → 其他原因关闭: {code}"); } State = NetworkState.Disconnected; // 注意:不自动重连,与 ClientSocket 一致,由 GameNetSystem 控制重连逻辑 Debug.Log("[WebSocket] 连接已断开,等待 GameNetSystem 处理"); } /// /// 获取接收统计信息 /// public long GetBytesTotal() => getBytesTotal; /// /// 获取发送统计信息 /// public long GetSendBytesTotal() => sendBytesTotal; /// /// 获取发送队列长度 /// public int GetSendQueueCount() { lock (sendQueue) { return sendQueue.Count; } } /// /// 每帧处理 WebSocket 消息(必须在 MonoBehaviour 的 Update 中调用) /// public void Update() { #if !UNITY_WEBGL || UNITY_EDITOR webSocket?.DispatchMessageQueue(); #endif } }