Unity WebGL使用NativeWebSocket通过WSS加密连接时,发送单条消息后连接中断且无法继续通信的问题
看起来你碰到了NativeWebSocket在Unity WebGL环境下WSS连接的典型坑——握手成功但发完一条消息就断连,还和ping机制有关。我结合你贴的客户端和NodeJS服务器代码,帮你梳理几个最可能的原因和解决办法:
1. 优先修复:Unity WebGL下必须调用DispatchMessageQueue(你的代码里有个致命宏)
你在Update方法里给websocket.DispatchMessageQueue()加了#if !UNITY_WEBGL || UNITY_EDITOR宏,这完全搞反了!WebGL环境下必须调用这个方法,因为WebGL的网络是异步的,所有的消息接收、Ping/Pong处理都依赖这个方法在主线程分发。这个宏会导致WebGL下根本不处理这些逻辑,客户端自然会认为连接“死了”,触发超时断开。
直接删掉这个宏,修改后的Update方法:
private async void Update() { if (!connected && websocket == null) { await connectServerAsync(); } else if (websocket != null) { // 所有平台(包括WebGL)都要调用这个,处理消息、Ping/Pong websocket.DispatchMessageQueue(); handleMessageSending(); } }
2. 处理Ping/Pong的双向响应(解决超时断连)
你怀疑是NativeWebSocket的Ping导致断连,核心原因是服务器没正确响应Ping,或者客户端没处理Pong。WSS连接下,如果客户端发了Ping但没收到Pong,NativeWebSocket会触发超时断开连接。
客户端修改(添加Ping配置和Pong监听)
在OnOpen回调里添加Ping间隔设置和Pong监听,确保客户端能正确处理服务器的响应:
websocket.OnOpen += () => { Debug.Log("Connection open!"); connected = true; // 设置Ping间隔(单位:毫秒,根据你的需求调整,比如2秒一次) websocket.PingInterval = 2000; // 监听Pong,确认服务器在线 websocket.OnPong += (bytes) => { Debug.Log("Received Pong from server!"); // 这里可以重置自定义超时计时器(如果需要的话) }; };
NodeJS服务器修改(正确响应Ping)
在服务器的connection事件里添加Ping监听,给客户端返回Pong:
wss.on('connection', function (ws) { console.log("client joined."); // 新增:响应客户端的Ping请求,避免客户端超时断连 ws.on('ping', function(data) { ws.pong(data, false, true); // 按规范返回Pong console.log("Sent Pong to client"); }); // 你的原有代码... const textInterval = setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send("hello world!"); } }, 50); ws.on('message', function (data) { // 你的原有代码... }); ws.on('close', function () { // 你的原有代码... }); });
3. 调整WebGL下的消息发送逻辑(避免异步阻塞)
你用IEnumerator包裹websocket.Send(),在WebGL环境下,Coroutine和Task的混合使用可能导致消息发送不及时,间接引发超时。建议把发送逻辑改成纯异步Task:
客户端修改SendMessage和handleMessageSending
// 把IEnumerator改成async Task private async Task SendMessage(ISerializable message) { if (websocket?.State != WebSocketState.Open) { Debug.LogWarning("Tried to send message but not connected!"); return; } Packet packet = new Packet(); packet.Write(message); Debug.Log($"Message Send: {message.GetType()}"); await websocket.Send(packet.GetBytes()); } // 把handleMessageSending改成async void private async void handleMessageSending() { while (networkMessageQueue.Count > 0) { ISerializable message = networkMessageQueue.Dequeue(); await SendMessage(message); // 可以加个微小延迟避免消息堆积,比如await Task.Delay(10); } }
4. 验证WSS证书的有效性
虽然你说证书应该没问题,但还是要确认这几点:
- 证书的通用名称(CN)或SAN扩展必须和你连接的服务器地址匹配(比如你用
localhost,证书里要包含localhost)。 - 在浏览器中手动访问
https://你的服务器地址:55555,确认浏览器能信任这个证书(如果是自签名证书,需要手动点击“高级”->“继续访问”来信任)。WebGL的连接依赖浏览器的证书信任体系,浏览器不认可的证书会导致WSS连接隐性失败。 - 检查NodeJS中加载PFX证书的密码是否正确,证书是否过期。
5. 额外建议:完善连接错误日志
你的connectServerAsync方法里没有捕获异常,很难排查连接失败的具体原因。可以加个try-catch捕获异常,打印详细错误:
private async Task connectServerAsync() { foreach (string adress in serverAddresses) { try { string prefix = secure ? "wss" : "ws"; websocket = new WebSocket($"{prefix}://{adress}:{port}"); Debug.Log($"Attempting to connect to: {adress}:{port}"); // 你的原有OnOpen/OnError/OnClose/OnMessage回调... await websocket.Connect(); return; } catch (System.Exception e) { Debug.LogError($"Failed to connect to {adress}:{port} - {e.Message}"); await Task.Delay(1000); // 失败后延迟1秒再试下一个地址,避免频繁重试 } } Debug.LogError("All server addresses failed to connect!"); }
你可以先优先修复第1点(DispatchMessageQueue的宏问题)和第2点(Ping/Pong响应),这两个是最可能导致你现在问题的原因。如果修改后还是有问题,可以把客户端和服务器的完整日志贴出来,咱们再进一步排查!




