Task.WhenAny遇到问题

时间:2019-05-30 12:32:56

标签: c# .net server async-await

我正在使用.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控制台应用程序进行了尝试,并且效果很好。

谢谢

2 个答案:

答案 0 :(得分:0)

我建议将您的代码重构为类似的东西,然后从那里获取。也就是说,为每个侦听器运行一个无限循环。这样可以避免为每个客户一次只呼叫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();
    }
}

答案 1 :(得分:0)

这是我的代码,在我遵循canton7的建议后,将任务列表移到循环外,并“随我们所愿”移动添加和删除任务。也许我将不得不对其进行清理,但是这个想法可行:

    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)
        };
        ProcessConnections(listeners).Wait();
    }

    private async static Task SendData(Socket socket)
    {
        NetworkStream stream = new NetworkStream(socket);
        byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
        await stream.WriteAsync(bytes, 0, bytes.Length);
        socket.Close();
    }

    private static async Task ProcessConnections(List<TcpListener> listeners)
    {
        foreach (TcpListener listener in listeners)
        {
            listener.Start();
        }
        try
        { 
            List<Task<Socket>> tasks = new List<Task<Socket>>();
            foreach (TcpListener listener in listeners)
            {
                tasks.Add(AcceptConnection(listener));
            }
            while (true)
            {
                int i = Task.WaitAny(tasks.ToArray());
                Socket socket = await tasks[i];
                await SendData(socket);
                tasks.RemoveAt(i);
                tasks.Insert(i, AcceptConnection(listeners[i]));
            }
        }
        finally
        {
            foreach (TcpListener listener in listeners)
            {
                listener.Stop();
            }
        }
    }
    private static async Task<Socket> AcceptConnection(TcpListener listener)
    {
        Socket socket = await listener.AcceptSocketAsync();
        return socket;
    }