#if UNITY_WEBGL using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Runtime.InteropServices.ComTypes; using BestHTTP.WebSocket; using GFGGame; namespace ET { public class WChannel : AChannel { private readonly WService Service; private WebSocket webSocket; private Queue waitSend = new Queue(); //address=http://webgltest.goufuguiwxw.com/ws public WChannel(long id, IPEndPoint ipEndPoint, WService service, string address) { this.Service = service; this.ChannelType = ChannelType.Connect; this.Id = id; string wsStr; bool isHttps = LauncherConfig.isHttps; // 检查address是否是URL格式 if (!string.IsNullOrEmpty(address) && (address.StartsWith("http://") || address.StartsWith("https://"))) { // 如果是URL格式,转换为WebSocket协议 if (address.StartsWith("https://")) { wsStr = address.Replace("https://", "wss://"); isHttps = true; } else { wsStr = address.Replace("http://", "ws://"); } } else if (ipEndPoint != null) { // 如果不是URL格式但有IPEndPoint,使用IP+端口方式 wsStr = $"ws://{ipEndPoint}"; } else if (!string.IsNullOrEmpty(address)) { // 如果没有IPEndPoint但有address,直接使用address作为WebSocket地址 // 支持IP:端口格式 wsStr = address.StartsWith("ws://") || address.StartsWith("wss://") ? address : $"ws://{address}"; } else { // 无法构造WebSocket地址 Log.Error($"WChannel: Invalid address and ipEndPoint are both null"); throw new ArgumentException("Invalid address and ipEndPoint are both null"); } Log.Debug($"wc address:{address}"); Log.Debug($"wc wsStr:{wsStr}"); WebSocket ws = new WebSocket(new Uri(wsStr)); if (isHttps || ipEndPoint == null) { this.RemoteAddress = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); } else { this.RemoteAddress = ipEndPoint; } // Subscribe to the WS events ws.OnOpen += OnOpen; ws.OnClosed += OnClosed; ws.OnError += OnError; ws.OnBinary += OnRead; // Start connecting to the server ws.Open(); } public override void Dispose() { if (this.IsDisposed) { return; } this.Id = 0; this.webSocket?.Close(); this.webSocket = null; } public void Send(MemoryStream memoryBuffer) { switch (this.Service.ServiceType) { case ServiceType.Inner: break; case ServiceType.Outer: memoryBuffer.Seek(Packet.ActorIdLength, SeekOrigin.Begin); ; break; } if (this.webSocket == null) { this.waitSend.Enqueue(memoryBuffer); return; } SendOne(memoryBuffer); } private void SendOne(MemoryStream memoryBuffer) { this.webSocket.Send(memoryBuffer.GetBuffer(), (ulong)memoryBuffer.Position, (ulong)(memoryBuffer.Length - memoryBuffer.Position)); } private void OnOpen(WebSocket ws) { if (ws == null) { this.OnError(ErrorCore.ERR_WebsocketConnectError); return; } if (this.IsDisposed) { return; } this.webSocket = ws; while (this.waitSend.Count > 0) { MemoryStream memoryBuffer = this.waitSend.Dequeue(); this.SendOne(memoryBuffer); } } /// /// Called when we received a text message from the server /// private void OnRead(WebSocket ws, byte[] data) { if (this.IsDisposed) { return; } MemoryStream memoryBuffer = this.Service.Fetch(); memoryBuffer.Write(data, 0, data.Length); // 写入整个 data memoryBuffer.Seek(2, SeekOrigin.Begin); this.Service.ReadCallback(this.Id, memoryBuffer); } /// /// Called when the web socket closed /// private void OnClosed(WebSocket ws, UInt16 code, string message) { if (this.IsDisposed) { return; } Log.Error($"wchannel closed: {code} {message}"); this.OnError(0); } /// /// Called when an error occured on client side /// private void OnError(WebSocket ws, string error) { if (this.IsDisposed) { return; } //Log.Error($"WChannel error: {this.Id} {ws.GetHashCode()} {error}"); this.OnError(ErrorCore.ERR_WebsocketError); } private void OnError(int error) { Log.Info($"WChannel error: {this.Id} {error}"); long channelId = this.Id; this.Service.Remove(channelId); this.Service.ErrorCallback(channelId, error); } } } #endif