c# - 如何使用 Task.WhenAny 和 ReadLineAsync 从任何 TcpClient 获取数据

标签 c# wpf asynchronous task-parallel-library

通过所有异步/等待(来自线程池),我遇到了一个有趣的挑战。

我有一个在 WPF 应用程序中运行的 TCP 服务器,该应用程序接受客户端并将它们存储在 List<> 中像这样:

private List<Client> clients = new List<Client>();
while (running && clientCount <= maxClients)
{
    Client client = new Client(await server.AcceptTcpClientAsync());
    await client.WriteLineAsync("Connected to the Server!");
    clients.Add(client);
    clientCount++;
}

所以我想做的是遍历我的客户列表,如果收到任何数据,我想将其附加到文本框。我意识到这可能不是实现此目标的最佳方式,并且我乐于接受建议,但这就是我目前的结构。

一个按钮开始循环,不断调用等待AllReadLineAsync()

private async void btnStartReadLoopClick(object sender, RoutedEventArgs e)
{
    btnStartReadLoop.IsEnabled = false;
    while(server.clientCount > 0)
    {
        string text = await server.AllReadLineAsync();
        txtOutputLog.AppendText("[client] " + text + "\n");
    }
}

这是什么函数:

public async Task<string> AllReadLineAsync()
{
    var tasklist = new List<Task<string>>();

    foreach (var client in clients)
        tasklist.Add(client.ReadLineAsync());

    while (tasklist.Count > 0)
    {
        Task<string> finishedTask = await Task.WhenAny(tasklist);
        if (finishedTask.Status == TaskStatus.RanToCompletion)
            return await finishedTask;

        tasklist.Remove(finishedTask);
    }

    return "Error: No task finished";
}

此函数遍历客户端列表并创建一个 List<Tast<string>>所有的 ReadLineAsync()任务。

在任何给定时间,我可能只有 1 或 2 个客户端实际发送数据,所以我不能 WhenAll()我试过了WhenAny()WaitAny()没有成功。

future google 员工注意事项: WaitAny()就像Wait()并且正在阻塞。不要在 UI 线程上执行此操作。而是使用 WhenAny()并等待它。

所以我当前的实现是可行的,但我无法弄清楚如果其他客户端不发送数据,消息将从 1 个客户端累积的错误。

TL;DR: 我在使用 WhenAny() 吗?正确还是有更好的方法让我等待 ReadLineAsync 并将结果传递给文本框?

编辑:这是我看到的行为 我按以下顺序输入:左、右、左 2、右 2、左 3、右 3 似乎有些消息被丢弃了?

enter image description here

编辑 2: 我在 MSDN 博客上找到了我复制的代码片段的来源:https://blogs.msdn.microsoft.com/pfxteam/2012/08/02/processing-tasks-as-they-complete/

此代码片段专门用于遍历任务列表以确保它们全部完成。我不关心任务是否重复,所以我需要修改代码以始终检查整个任务列表而不是删除任何任务。

最佳答案

it appears as if some messages are being dropped?

是的。因为异步工作在您调用它们的方法(例如,ReadLineAsync)时开始。当其中一个任务完成时 (Task.WhenAny),您的代码将放弃其他任务。但它们会继续运行 - 它们仍在从套接字中读取数据,并且它们读取的任何内容都将被丢弃。

据我所知,当您再次开始从同一个套接字开始读取时,行为是未定义的 - 它可能会读取下一个内容,或者可能会排队。我知道您不应该同时从一个套接字(或任何流)发出多个读取。

套接字不是async 的完美匹配,因为它们可以随时发送数据。您应该改用 Rx 或事件。使 async 工作是可能的,但它非常复杂。

关于c# - 如何使用 Task.WhenAny 和 ReadLineAsync 从任何 TcpClient 获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42116277/

相关文章:

c# - 从头开始显示 TextBox 的选定文本

java - Android Retrofit Post 请求的服务器超时

Java - 从文件读取字节时对其进行处理

c# - 在 ASP.NET Core 中使用 WebGrid

c# - SerialPort.GetPortNames 多次返回同一个端口

c# - 如何在 C#/Vista 中将鼠标事件传递给我背后的应用程序?

java - 不完整的文件复制 Java NIO

C#:将 DataTable 传递给 SQL Server 非常慢

c# - 如何从类中引发和捕获鼠标事件(不从控件继承)?

wpf - 在 MVVM 中的查看模式和编辑模式之间切换?