每个接受多个连接时如何监听多个TCP端口

How to listen to multiple TCP ports when each one accepts multiple connections

我需要使用 TcpListener 监听多个端口,我需要 TcpListener 接受多个连接并单独处理每个连接,这是我编写的代码,但如您所见,它只监听第一个端口然后转到 while(true) 并监听到达该端口的所有连接。知道我怎样才能为多个连接监听多个端口吗?

   private static async Task TcpServerAsync()
    {
        try
        {

            IPAddress ip;
            if (!IPAddress.TryParse(ConfigurationManager.AppSettings["ipAddress"], out ip))
            {
                Console.WriteLine("Failed to get IP address, service will listen for client activity on all network interfaces.");
                ip = IPAddress.Any;
            }


            foreach (Ports port in Ports.GetValues(typeof(Ports)))
            {

                Log.Info("Starting listener...");
                var tcpListener = new TcpListener(ip, (int)port);

                tcpListener.Start();
                Log.Info("Listening...");

                var startTimeSpan = TimeSpan.Zero;
                var periodTimeSpan = TimeSpan.FromSeconds(10000000);


                while (true)
                {
                    TcpClient client = await tcpListener.AcceptTcpClientAsync();
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionNam‌​e.KeepAlive, 1);
                    HandleByPortNumber(client, (int)port);
                }
            }
        }
        catch (Exception ex)
        {
            Log.Info("Error Happened : " + ex + ex.InnerException);
        }
}

   public static void HandleByPortNumber(TcpClient client , int portNumber)
    {
        switch (portNumber)
        {
            case (int)Ports.Teltonica:
                var cw = new Teltonika.TcpClientService(client);
                ThreadPool.UnsafeQueueUserWorkItem(x =>  ( (Teltonika.TcpClientService)x).Run(), cw);
                break;

            case (int)Ports.OBDTracker:
                break;
        }
    }

 public enum Ports
{
    Teltonica = 3000,
    OBDTracker = 3001
}

这是一个删除了额外功能(日志记录等)的实现。测试和工作。这里要解决的问题是如何从 Task 映射回它的侦听器和端口号。显然,我的端口号列表对您不起作用,但除此之外应该可以。您还希望将 Tuple<> 替换为自定义 class,以获得更好的可读性。

IDictionary<Task<TcpClient>, Tuple<int, TcpListener>> tcpListeners = new Dictionary<Task<TcpClient>, Tuple<int, TcpListener>>();

foreach (var port in Enumerable.Range(20000, 5))
{
    var tcpListener = new TcpListener(IPAddress.Any, port);

    tcpListener.Start();

    var task = tcpListener.AcceptTcpClientAsync();
    var tcpListenerPortPair = new Tuple<int, TcpListener>(port, tcpListener);

    tcpListeners.Add(task, tcpListenerPortPair);
}

Task<TcpClient> tcpClientTask;

while ((tcpClientTask = await Task.WhenAny(tcpListeners.Keys)) != null)
{
    var tcpListenerPortPair = tcpListeners[tcpClientTask];
    var port = tcpListenerPortPair.Item1;
    var tcpListener = tcpListenerPortPair.Item2;

    tcpListeners.Remove(tcpClientTask);

    // This needs to be async. What to do with its Task?
    // It cannot be awaited here.
    var handlerTask = HandleByPortNumber(tcpClientTask.Result, port);

    var task = tcpListener.AcceptTcpClientAsync();

    tcpListeners.Add(task, tcpListenerPortPair);
}