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

C#中如何在任务取消前通过WebSocket发送Stop_Stream指令

解决方案:确保取消任务时先发送"Stop_Stream"指令再关闭WebSocket

核心思路是让任务自行处理取消后的优雅清理流程,避免外部取消令牌直接中断WebSocket连接。以下是具体修改方案:

1. 重构IPCameraService.Main方法:将清理逻辑整合到取消处理流程中

修改Main方法,在捕获取消异常时优先完成"Stop_Stream"指令发送,再安全关闭WebSocket:

public async Task Main(System.Windows.Controls.Image imageControl, int cameraIndex, CancellationToken token, string cameraUrl)
{
    CameraURLs[cameraIndex] = cameraUrl;

    try
    {
        await StartSocket(cameraIndex, token);
        await StartStream(cameraIndex, cameraUrl, token);
        var stopStreamCompletion = new TaskCompletionSource<bool>();
        EventHandler(cameraUrl, cameraIndex, token);
        
        while (true)
        {
            // 每次循环前检查取消令牌,触发清理流程
            token.ThrowIfCancellationRequested();
            
            var frame = await RunYolo(cameraIndex, token);
            if (frame != null)  
                await UpdateDisplay(frame, imageControl, token);
        }
    }
    catch (OperationCanceledException)
    {
        // 执行优雅清理:先发送Stop_Stream指令
        var stopServerCommand = new { command = "Stop_Stream" };
        if (CameraWebsockets.TryGetValue(cameraIndex, out var ws) && ws.State == WebSocketState.Open)
        {
            var commandJson = JsonConvert.SerializeObject(stopServerCommand);
            var commandBytes = Encoding.UTF8.GetBytes(commandJson);
            
            // 使用CancellationToken.None确保指令发送不受原取消令牌影响
            await ws.SendAsync(
                new ArraySegment<byte>(commandBytes, 0, commandBytes.Length),
                WebSocketMessageType.Text,
                true,
                CancellationToken.None
            );
            Debug.WriteLine("Stop_Stream指令已发送");

            // 主动优雅关闭WebSocket
            await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "任务取消,优雅关闭", CancellationToken.None);
            CameraWebsockets.Remove(cameraIndex);
            Debug.WriteLine("WebSocket已优雅关闭");
        }
        // 重新抛出异常,让调用方感知任务已取消(可选)
        throw;
    }
}

2. 优化DeviceSettings.IPCameraMethod:确保等待任务完成清理

保留原有取消逻辑,但强化任务等待环节,确保旧任务完成清理后再启动新任务:

private async Task IPCameraMethod()
{
    if (string.IsNullOrWhiteSpace(textBoxUrl.Text) ||
        !int.TryParse(SourceComboBox.Name.Replace("comboBox", ""), out int cameraIndex) ||
        comboBoxSavedCameras.SelectedIndex < 0)
    {
        return;
    }

    string url = textBoxUrl.Text;
    int selectedItemIndex = comboBoxSavedCameras.SelectedIndex;

    if (tokenSources.TryGetValue(cameraIndex, out var tuple))
    {
        if (selectedItemIndex != tuple.Item1)
        {
            tuple.Item2.Cancel();

            try
            {
                await tuple.Item3; // 等待旧任务完成所有清理操作
            }
            catch (OperationCanceledException)
            {
                Debug.WriteLine("旧任务已完成取消清理");
            }
            finally
            {
                tuple.Item2.Dispose();
                tokenSources.Remove(cameraIndex);
            }
        }
        else
        {
            return; // 选中项未变化,无需操作
        }
    }

    // 启动新任务(用Task.Run替代StartNew,更适配异步场景)
    var newCts = new CancellationTokenSource();
    Task newTask = Camera != null 
        ? Task.Run(() => Camera.IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url))
        : Task.Run(() => (BaseViewModel as AddFaceViewModel).IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url));

    Debug.WriteLine("New Task Created!");
    tokenSources[cameraIndex] = Tuple.Create(selectedItemIndex, newCts, newTask, CameraType.IP);
}

关键注意事项

  • 避免令牌直接中断WebSocket:发送"Stop_Stream"时使用CancellationToken.None,确保指令不会因原令牌已取消而失败。
  • 检查WebSocket状态:发送指令前确认WebSocket处于Open状态,避免无效操作。
  • 线程安全:如果CameraWebsockets是多线程访问的集合,建议改用ConcurrentDictionary替代普通Dictionary,避免并发访问异常。
  • 取消逻辑统一:确保StartSocket、StartStream等方法内部不会在令牌取消时直接关闭WebSocket,将关闭逻辑统一到Main方法的清理流程中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 23:51:02