You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity使用WebSocketSharp时OnMessage内改色方法不生效原因排查

问题根本原因

WebSocketSharp 的 OnMessage 回调运行在独立的后台网络线程,而非 Unity 主线程。Unity 几乎所有引擎核心 API(包括访问、修改 Renderer 组件材质属性的操作)仅允许在主线程调用,非主线程调用这类 API 会被引擎的线程安全校验静默拦截,通常不会抛出显性报错,也不会实际执行修改逻辑——这就是回调触发了但改色失败,而 Update 里按键调用同个方法能正常生效的核心原因。

修复方案

核心原则是:网络回调线程只做数据接收、存储,所有涉及 Unity API 的操作全部排队到主线程执行。

  • 新增线程安全的任务队列,用来暂存跨线程过来、需要主线程执行的操作
  • 修改 OnMessage 回调逻辑,不再直接调用 ChangeColor,而是把改色操作入队
  • 在 Update(主线程生命周期)里依次消费队列里的任务,执行改色逻辑

修正后的完整代码参考:

using System;
using System.Collections.Concurrent;
using UnityEngine;
using WebSocketSharp;

public class WsColorChanger : MonoBehaviour
{
    WebSocket ws;
    private Renderer objectRenderer;
    private Color matColor;
    private string reciveData;
    // 线程安全队列,存储待主线程执行的任务
    private readonly ConcurrentQueue<Action> _mainThreadTaskQueue = new ConcurrentQueue<Action>();

    private void Start()
    {
        objectRenderer = GetComponent<Renderer>();

        ws = new WebSocket("ws://127.0.0.1:8080");
        ws.Connect();
        ws.OnMessage += (sender, e) =>
        {
            reciveData = e.Data;
            // 非主线程仅入队任务,不直接调用Unity相关API
            _mainThreadTaskQueue.Enqueue(() =>
            {
                ChangeColor(e.Data);
            });
        };
    }

    void Update()
    {
        if (ws == null)
            return;
        
        // 主线程依次执行所有排队的任务
        while (_mainThreadTaskQueue.TryDequeue(out var task))
        {
            task.Invoke();
        }
    }

    public void ChangeColor(string data)
    {
        string[] colors = data.Split(',');
        matColor = new Color()
        {
            r = float.Parse(colors[0]) / 255.0f,
            g = float.Parse(colors[1]) / 255.0f,
            b = float.Parse(colors[2]) / 255.0f,
            a = float.Parse(colors[3]) / 255.0f
        };
        objectRenderer.material.color = matColor;
    }

    private void OnDestroy()
    {
        // 退出时记得关闭WebSocket连接,避免内存泄漏
        ws?.Close();
        ws = null;
    }
}

注意:不要用普通的List、Queue做跨线程任务存储,这类集合不是线程安全的,多线程读写时会出现数据错乱、集合修改异常等问题。

内容的提问来源于stack exchange,提问作者Калашников Ян

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:30:39