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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:50:31