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

Blazor Server应用触发WebSocket 1006错误冻结,求根因排查与修复

Blazor Server应用WebSocket 1006错误排查与修复

问题说明

Blazor Server端应用执行特定代码时出现屏幕冻结,Chrome和Firefox浏览器均触发错误:WebSocket closed with status code: 1006 (no reason given)。具体场景:

  • 页面首次打开后,第一次调用ReadVariables方法(once=true):执行AGL4.NCK_Symbolic_LoadGUD和AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem,输出正常。
  • 第二次调用该方法(once=false):仅执行AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem,使用首次保存的root_handle_2,在标记abc的代码行触发屏幕冻结,服务端无任何报错。

相关代码

public AGL4.NckNodeHandle root_handle_2 ;
public bool once = true;

public void ReadVariables(int p_conn_nr)        
{            
    int res = AGL4.AGL40_SUCCESS;
    if (once == true)
    {
        AGL4.NckNodeHandle root_handle = new AGL4.NckNodeHandle();
        res = AGL4.NCK_Symbolic_LoadGUD(p_conn_nr, ref root_handle);
        root_handle_2 = root_handle;
        once = false;   
    }          

    int variables_count = TagService.GUD_VAR_names.Count;
    //准备待读取的变量列表
    AGL4.NckDataRW[] data_rws = new AGL4.NckDataRW[variables_count];
    using (StreamWriter sw = File.AppendText(error_path))

    for (int i = 0; i < variables_count; ++i)
    {
        data_rws[i] = new AGL4.NckDataRW();                
        string variable = TagService.GUD_VAR_names[i];
        int error_position = 0;
        // abc: 第二次执行时此处触发冻结与WebSocket错误
        res = AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem(root_handle_2, variable, ref data_rws[i], ref error_position); 
    }
}

排查方向

  • AGL4库线程安全性检查:Blazor Server组件方法默认在UI线程执行,若AGL4的非托管函数不是线程安全的,重复调用可能引发死锁或资源冲突。
  • root_handle_2有效性验证:第二次调用时,root_handle_2是否已被AGL4库自动释放或失效?需确认NCK_Symbolic_LoadGUD返回的句柄生命周期规则,是否存在超时回收机制。
  • 同步阻塞问题排查:如果NCK_Symbolic_GetNCKDataRWByBTSSItem是同步阻塞调用且耗时过长,会卡住Blazor的SignalR UI线程,触发WebSocket断开(Blazor Server对UI线程阻塞有超时限制)。
  • 添加详细日志:在GetNCKDataRWByBTSSItem调用前后记录日志,包括当前变量名、句柄状态(若可获取),定位是否在处理某个特定变量时卡住。
  • 资源泄漏检查:第一次调用创建的资源是否未正确释放,导致第二次调用时资源不足或句柄异常。

修复建议

  1. 异步化调用避免UI阻塞
    将ReadVariables改为异步方法,把AGL4的调用放到后台线程执行,防止阻塞UI线程引发WebSocket断开:
public async Task ReadVariables(int p_conn_nr)        
{            
    int res = AGL4.AGL40_SUCCESS;
    if (once == true)
    {
        await Task.Run(() => {
            AGL4.NckNodeHandle root_handle = new AGL4.NckNodeHandle();
            res = AGL4.NCK_Symbolic_LoadGUD(p_conn_nr, ref root_handle);
            root_handle_2 = root_handle;
            once = false;   
        });
    }          

    int variables_count = TagService.GUD_VAR_names.Count;
    AGL4.NckDataRW[] data_rws = new AGL4.NckDataRW[variables_count];

    await Task.Run(() => {
        for (int i = 0; i < variables_count; ++i)
        {
            data_rws[i] = new AGL4.NckDataRW();                
            string variable = TagService.GUD_VAR_names[i];
            int error_position = 0;
            res = AGL4.NCK_Symbolic_GetNCKDataRWByBTSSItem(root_handle_2, variable, ref data_rws[i], ref error_position);
            
            // 添加错误检查,避免循环卡住
            if (res != AGL4.AGL40_SUCCESS)
            {
                // 记录错误并中断循环
                break;
            }
        }
    });

    // 若需更新UI,通过InvokeAsync切换回UI线程
    await InvokeAsync(() => {
        // 更新UI逻辑
    });
}
  1. 句柄有效性校验
    在第二次调用GetNCKDataRWByBTSSItem前,使用AGL4库提供的句柄验证函数(若存在)检查root_handle_2是否有效,若无效则重新执行NCK_Symbolic_LoadGUD加载句柄。

  2. 添加错误处理与日志
    在循环中检查res返回值,记录每次调用的错误信息,快速定位异常变量或调用失败原因。

  3. 确保线程安全
    若AGL4库不是线程安全的,需使用lock同步所有AGL4函数调用,或确保所有调用在同一个线程上下文执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:35:44