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,提问作者Калашников Ян
相关产品推荐
相关产品推荐

