如何在C#中取消任务之前在WebSocket上发送消息?

How to Send a Message on a WebSocket Before Task Cancellation in C#?

提问人:Captain C 提问时间:11/5/2023 最后编辑:Captain C 更新时间:11/6/2023 访问量:36

问:

我有一个处理 IP 摄像机流的异步方法 (IPCameraMethod)。它启动和取消通过 WebSocket 管理这些流的任务。这些任务在单独的类 IPCameraService 及其 Main 方法中启动。

当我尝试使用 CancellationToken 取消任务时,关联的 WebSocket 会立即关闭,从而阻止我发送应在 WebSocket 关闭之前执行的“Stop_Stream”命令。此“Stop_Stream”消息对于在服务器端正常关闭流至关重要。

这是我的代码的简化版本:

internal static Dictionary<int, Tuple<int, CancellationTokenSource, Task, CameraType>> tokenSources = new Dictionary<int, Tuple<int, CancellationTokenSource, Task, CameraType>>();

在 DeviceSettings 类中:

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; // Await the task's completion
            }

            catch (OperationCanceledException)
            {
                // Task was cancelled, expected behavior
            }
            tuple.Item2.Dispose();
            tokenSources.Remove(cameraIndex);
        }
        else
        {
            return; // If selected item is the same, we do not need to create a new task
        }
    }

    // Now that the old task has been cancelled and awaited, start the new task.
    var newCts = new CancellationTokenSource();
    Task newTask = null;
    if (Camera != null)
    {
        newTask = new TaskFactory().StartNew(() => Camera.IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url));
    }
    else
    {
        newTask = new TaskFactory().StartNew(() => (BaseViewModel as AddFaceViewModel).IPCameraService.Main(SourceImageControl, selectedItemIndex, newCts.Token, url));
    }

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

在 IPCameraService 类中:

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

    await StartSocket(cameraIndex, token);
    await StartStream(cameraIndex, cameraUrl, token);
    var stopStreamCompletion = new TaskCompletionSource<bool>();
    EventHandler(cameraUrl, cameraIndex, token);
    while (!token.IsCancellationRequested) // Added a token check to allow stopping the loop externally
    {
        var frame = await RunYolo(cameraIndex, token);
        if (frame != null)  
            await UpdateDisplay(frame, imageControl, token);
    }

    var Stop_Server = new
    {
        command = "Stop_Stream"
    };

    var ws = CameraWebsockets[cameraIndex];
    var Start_ServerJson = JsonConvert.SerializeObject(Stop_Server);
    var Start_ServerBytes = Encoding.UTF8.GetBytes(Start_ServerJson);
    await ws.SendAsync(new ArraySegment<byte>(Start_ServerBytes, 0, Start_ServerBytes.Length), WebSocketMessageType.Text, true, token);
    Debug.WriteLine("Websocket Cleared!");
}

问题出在 上,它旨在取消正在进行的任务并立即启动清理序列。我需要在进行此清理之前发送“Stop_Stream”命令,但是一旦请求取消,WebSocket就会关闭。tuple.Item2.Cancel();

如何重组取消和清理逻辑,以允许在关闭 WebSocket 之前发送“Stop_Stream”消息?

我尝试过:

  • 我试图捕捉OperationCanceledException,希望 WebSocket 仍将打开以发送消息,但它已经 到那时关闭。
  • 将 WebSocket 发送逻辑移动到 catch 块不起作用 或者,因为取消后无法访问 WebSocket。

问题:

  • 如何确保在 WebSocket 上发送“Stop_Stream”消息 在取消任务之前,实际导致 WebSocket 关闭?

其他上下文:

IPCameraMethod 和 Main 方法位于不同的类中,其中 IPCameraMethod 调用 Main 方法。 WebSocket 连接至关重要,在发送“Stop_Stream”命令之前应保持打开状态。 正在使用 C# .NET Framework 4.7.2。

C# 异步 websocket async-await 取消令牌

评论

1赞 Captain C 11/6/2023
您好@TheodorZoulias感谢您的回复。我在原始线程:)中添加了定义。希望你能帮到你。
0赞 Theodor Zoulias 11/6/2023
不幸的是,我不熟悉套接字编程,所以我帮不了你。但是,为了代码的其余部分的清晰度,添加该定义还是有用的。

答: 暂无答案