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

WebSocket.onopen回调内调用send()始终失败问题排查求助

WebSocketSharp服务端收不到onopen回调内发送消息的解决方案

问题根因

这个问题是WebSocketSharp库的历史遗留时序缺陷导致的:浏览器端触发onopen回调时,WebSocket的TCP连接和握手流程已经完成,客户端状态正常切换为OPEN,但WebSocketSharp服务端还未完成对应会话的接收流初始化操作。此时客户端发送的数据包要么被未就绪的服务端流丢弃,要么被识别为不完整的帧,触发你遇到的The header of a frame cannot be read from the stream异常。
手动加延时、点击按钮发送能正常工作,本质都是等服务端完成了流初始化的操作,窗口时间过了之后自然收发正常。

解决方案

方案1:双向握手确认(最稳定,无兼容问题)

在服务端完成会话初始化后,先向客户端推送一条就绪信号,客户端收到信号后再发送首条业务消息,完全规避时序问题:

  1. 服务端修改TestWS类,重写OnOpen方法:
public class TestWS : WebSocketBehavior {
    protected override void OnOpen()
    {
        // 向客户端发送就绪确认信号,信号内容可以自定义
        Send("__SERVER_INIT_COMPLETE__");
    }

    protected override void OnMessage (MessageEventArgs e) {
        System.Diagnostics.Debug.WriteLine($"Client message: {e.Data}");
        Send($"String length: {e.Data.Length} [msg received: {e.Data}]");
    }
}
  1. 客户端修改逻辑,收到就绪信号后再发送首条消息:
const webSocket = new WebSocket("ws://localhost:51036/test");

webSocket.onopen = e => {
    console.log("Socket connection opened!");
}

webSocket.onmessage = e => {
    // 匹配服务端发来的就绪信号
    if (e.data === "__SERVER_INIT_COMPLETE__") {
        // 此时服务端流已经就绪,可以正常发送消息
        webSocket.send("hello :D");
        return;
    }
    // 其他业务消息的处理逻辑
}

方案2:延时发送(临时调试用,不建议生产环境)

如果只是本地测试不想改太多逻辑,可以沿用你测试的setTimeout方案,但注意延时时长不固定,性能较差的设备可能需要调大延时数值,存在偶发失败概率:

webSocket.onopen = e => {
    setTimeout(() => {
        webSocket.send("hello :D");
    }, 200);
    console.log("Socket connection opened!");
}

方案3:更换服务端实现

WebSocketSharp已经多年没有更新稳定版本,存在不少遗留bug。如果是正式项目,可以换成ASP.NET Core内置的WebSocket中间件,原生实现没有这类时序问题,维护性和稳定性都更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:39:02