You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity WebGL使用NativeWebSocket通过WSS加密连接时,发送单条消息后连接中断且无法继续通信的问题

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响应),这两个是最可能导致你现在问题的原因。如果修改后还是有问题,可以把客户端和服务器的完整日志贴出来,咱们再进一步排查!

火山引擎 最新活动