首页 > 解决方案 > Task.WhenAny 的问题

问题描述

我正在使用 .NET 框架来创建一个服务器,它侦听 localhost 上的两个端口。这是一个简单的控制台应用程序。

当我继续连接到其中一个端口时它可以工作,但是在我第一个连接后,另一个没有响应。首先还活着。

这是我的代码:

    static void Main(string[] args)
    {
        IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
        List<TcpListener> listeners = new List<TcpListener>()
        {
            new TcpListener(hostIP, 6060),
            new TcpListener(hostIP, 6061)
        };
        foreach (TcpListener listener in listeners)
        {
            listener.Start();
        }
        try
        {
            while (true)
            {
                Socket socket = AcceptAnyConnection(listeners).Result;
                NetworkStream stream = new NetworkStream(socket);
                byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
                stream.Write(bytes, 0, bytes.Length);
                //stream.Close();
                socket.Close();
            }
        }
        finally
        {
            foreach (TcpListener listener in listeners)
            {
                listener.Stop();
            }
        }
    }

    private static async Task<Socket> AcceptAnyConnection(List<TcpListener> listeners)
    {
        List<Task<Socket>> tasks = new List<Task<Socket>>();
        foreach (TcpListener listener in listeners)
        {
            tasks.Add(AcceptConnection(listener));
        }
        Task<Socket> completedTask = await Task.WhenAny(tasks);
        return await completedTask;
    }
    private static async Task<Socket> AcceptConnection(TcpListener listener)
    {
        Socket socket = await listener.AcceptSocketAsync();
        return socket;
    }

如果我连接到另一个端口,则等待 Task.WhenAny() 阻塞。

我一定做错了什么,但我不确定是什么。

顺便说一句,我确实对 .NET Core 控制台应用程序进行了同样的尝试,并且效果很好。

谢谢

标签: c#.netserverasync-await

解决方案


我建议将您的代码重构为类似的内容,然后从那里获取。也就是说,为每个侦听器运行一个无限循环。这避免了确保您一次只AcceptTcpClientAsync为每个客户调用一次的问题。

(请注意,没有代码可以真正阻止听众。也完全未经测试 - 请仅将其用作指示采取的方法)

static void Main(string[] args)
{
    IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
    List<TcpListener> listeners = new List<TcpListener>()
    {
        new TcpListener(hostIP, 6060),
        new TcpListener(hostIP, 6061)
    };

    var listenerTasks = listeners.Select(x => RunTcpListener(x)).ToArray();
    Task.WaitAll(listenerTasks);
}

private static async Task RunTcpListener(TcpListener listener)
{
    listener.Start();

    try
    {
        while (true)
        {
            using (var client = await listener.AcceptTcpClientAsync())
            {
                var stream = client.GetStream();
                byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
                stream.Write(bytes, 0, bytes.Length);

                client.Close();
            }
        }
    }
    finally
    {
        listener.Stop();
    }
}

推荐阅读