C#中如何实现主线程与WebSocket线程的双向数据传递?
实现Unity主线程到WebSocket线程的反向数据传递
要实现从Unity主线程(WS_Client)向WebSocket服务线程(MyWebSocketServer)传递实时更新的变量,核心是解决跨线程安全访问的问题,同时让WebSocket服务能够安全获取主线程的实时数据。以下是具体实现方案:
1. 主线程变量的线程安全封装
首先在WS_Client中对需要共享的局部变量添加线程安全的读写控制,避免多线程竞争导致的数据错误:
public class WS_Client : MonoBehaviour { public static GameObject _cube; private Action<Vector3> callback; [SerializeField] float speed = 50.0f; // 用锁对象保护_orientation的读写操作 private Vector3 _orientation; private readonly object _orientationLock = new object(); void Start() { _cube = GameObject.Find("MyCube"); if (_cube == null) { Debug.Log("couldnt find MyCube at first"); } WebSocketServer wssv = new WebSocketServer(8080); Action<Vector3> callback = HandleOrientationUpdate; // 创建WebSocket服务时传入当前WS_Client实例 MyWebSocketServer wsService = new MyWebSocketServer(callback, this); wssv.AddWebSocketService<MyWebSocketServer>("/MyWebSocket", () => wsService); wssv.Start(); } // 线程安全的获取当前方向方法 public Vector3 GetCurrentOrientation() { lock (_orientationLock) { return _orientation; } } private void Update() { // 线程安全读取_orientation Vector3 currentOrientation; lock (_orientationLock) { currentOrientation = _orientation; } _cube.transform.rotation = Quaternion.Euler(currentOrientation); } private void HandleOrientationUpdate(Vector3 orientation) { Debug.Log("tries to rotate mycube"); Debug.Log(orientation); try { // 线程安全写入_orientation lock (_orientationLock) { _orientation = orientation; } Debug.Log("translates the orientation"); } catch (Exception ex) { Debug.LogError("An error occurred: " + ex.Message); } } // 其他构造函数和方法保持不变 }
2. 修改WebSocket服务,添加主线程实例引用
让MyWebSocketServer持有WS_Client的实例引用,当收到客户端请求时,安全调用线程安全方法获取实时数据并发送:
public class MyWebSocketServer : WebSocketBehavior { private Action<Vector3> callback; private WS_Client _wsClient; // 持有主线程WS_Client实例 // 构造函数新增WS_Client参数 public MyWebSocketServer(Action<Vector3> callback, WS_Client wsClient) { this.callback = callback; this._wsClient = wsClient; } protected override void OnMessage(MessageEventArgs e) { // 处理"请求方向数据"的指令(可根据业务自定义指令格式) if (e.Data.Trim().Equals("request_orientation", StringComparison.OrdinalIgnoreCase)) { try { // 线程安全获取主线程的实时方向数据 Vector3 currentOrientation = _wsClient.GetCurrentOrientation(); // 将Vector3转为字符串格式发送 string response = $"{currentOrientation.x:F2} {currentOrientation.y:F2} {currentOrientation.z:F2}"; Send(response); Debug.Log("Sent current orientation: " + response); return; } catch (Exception ex) { Debug.LogError("Failed to send orientation: " + ex.Message); } } // 原有方向更新处理逻辑保持不变 string data = e.Data; string[] components = data.Split(' '); Debug.Log("splits components"); float x = float.Parse(components[0]); float y = float.Parse(components[1]); float z = float.Parse(components[2]); Debug.Log("parses components"); Vector3 orientation = new Vector3(x, y, z); try { // 注意:WebSocket线程无法直接调用Unity API,若需操作Unity对象需切换到主线程 callback?.Invoke(orientation); Debug.Log("invokes action"); } catch (Exception ex) { Debug.LogError("An error occurred: " + ex.Message); } } // OnOpen、OnClose方法保持不变 }
3. 关键注意事项
- 线程安全:所有共享变量的读写必须通过
lock同步,避免多线程竞争导致的数据损坏。 - Unity API限制:WebSocketSharp的
OnMessage方法在后台线程执行,直接调用Unity API(如修改transform)会报错。若需在回调中操作Unity对象,可通过创建任务队列,在WS_Client的Update方法中处理队列任务。 - 通信协议:示例用
request_orientation作为请求指令,你可根据业务需求定义更规范的协议(如JSON格式)。
内容的提问来源于stack exchange,提问作者Ivan Viti
相关产品推荐
相关产品推荐

