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

websocket-sharp OnMessage回调非主线程致WPF事件传递失败求助

问题分析与解决方案

核心问题出在WebSocketBehavior实例与单例实例不匹配:你的WebsocketServer类继承了WebSocketBehavior,但websocket-sharp会为每个客户端连接创建一个全新的WebSocketBehavior子类实例来处理该连接;而MainWindow订阅的是单例WebsocketServer.Instance的事件,实际触发事件的是每个连接对应的独立实例,两者完全不是同一个对象,所以事件永远不会被MainWindow接收到。

修正方案:拆分管理类与连接处理类

将服务器的全局管理(单例、启停)和单个连接的消息处理拆分,让所有连接的事件都通过单例管理类统一触发,确保MainWindow订阅的事件源和实际触发源一致。

1. 创建全局服务器管理类(单例)

public class WebsocketServerManager
{
    private static readonly Lazy<WebsocketServerManager> lazyInstance = new Lazy<WebsocketServerManager>(() => new WebsocketServerManager());
    public static WebsocketServerManager Instance => lazyInstance.Value;

    private const string HOST_IP_ADDRESS = "127.0.0.2";
    private const int PORT = 38001;

    private WebSocketServer _socket;

    // 供UI层订阅的统一事件
    public event EventHandler<EventArgs> RaiseOnScanDevice = (s, e) => { };

    private WebsocketServerManager()
    {
        Initialize();
    }

    public void Initialize()
    {
        _socket = new WebSocketServer(IPAddress.Parse(HOST_IP_ADDRESS), PORT);
        // 注册连接处理类,并传入当前单例实例
        _socket.AddWebSocketService<DeviceWebSocketBehavior>(() => new DeviceWebSocketBehavior(this));
        StartServer();
    }

    public void StartServer() => _socket.Start();
    public void StopServer() => _socket.Stop();

    // 供连接处理类调用,统一触发事件
    internal void TriggerScanDeviceEvent()
    {
        // 确保在WPF UI线程触发事件
        System.Windows.Application.Current.Dispatcher.Invoke(() =>
        {
            RaiseOnScanDevice?.Invoke(this, EventArgs.Empty);
        });
    }
}

2. 创建单个连接的消息处理类

public class DeviceWebSocketBehavior : WebSocketBehavior
{
    private readonly WebsocketServerManager _serverManager;
    private PacketHandler _packetHandler = new PacketHandler();

    public DeviceWebSocketBehavior(WebsocketServerManager serverManager)
    {
        _serverManager = serverManager;
    }

    protected override Task OnMessage(MessageEventArgs e)
    {
        using (var reader = new System.IO.StreamReader(e.Data))
        {
            string message = reader.ReadToEnd();
            PacketModel packet = _packetHandler.OpenPacket(message);
            HandleMessageFromClient(packet);
        }
        return base.OnMessage(e);
    }

    private void HandleMessageFromClient(PacketModel packet)
    {
        if (string.IsNullOrEmpty(packet.EventName))
            return;

        switch (packet.EventName)
        {
            case SocketEvent.Hello:
                Send("OK");
                break;
            case SocketEvent.ScanDevice:
                // 通过单例管理器触发全局事件
                _serverManager.TriggerScanDeviceEvent();
                break;
        }
    }
}

3. 修改MainWindow订阅逻辑

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        // 订阅单例管理器的事件
        WebsocketServerManager.Instance.RaiseOnScanDevice += SocketConnection_RaiseOnScanDevice;
    }

    private void SocketConnection_RaiseOnScanDevice(object sender, EventArgs e)
    {
        Console.WriteLine("SocketConnection_RaiseOnScanDevice");
    }
}

关键修正点说明

  • 拆分后,所有客户端连接的消息处理实例都会通过单例WebsocketServerManager触发事件,MainWindow订阅的是同一个事件源,确保事件能被正确接收。
  • 通过Dispatcher.Invoke强制事件在UI线程触发,彻底解决线程上下文不匹配的问题。

内容的提问来源于stack exchange,提问作者Duc Nguyen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:35:21