Home Articles

在.Net中查找下一个TCP端口

Asked
Viewed 2 times
51

我想为WCF服务调用创建一个新的net.tcp:// localhost:x / Service endpoints ,并使用动态分配的新的open tcp端口 .

我知道当我打开与给定服务器的连接时,TcpClient将分配一个新的客户端端口 .

有没有一种简单的方法可以在.Net中找到下一个打开的TCP端口?

我需要实际的数字,以便我可以构建上面的字符串,0不起作用,因为我需要将该字符串传递给另一个进程,以便我可以回调该新的通道 .

6 Answers

  • 107

    使用端口号0. TCP堆栈将分配下一个空闲的堆栈 .

  • 14

    这是我在寻找的东西:

    static int FreeTcpPort()
    {
      TcpListener l = new TcpListener(IPAddress.Loopback, 0);
      l.Start();
      int port = ((IPEndPoint)l.LocalEndpoint).Port;
      l.Stop();
      return port;
    }
    
  • 8

    如果您想获得特定范围内的空闲端口,以便将其用作本地端口/ endpoints :

    private int GetFreePortInRange(int PortStartIndex, int PortEndIndex)
        {
            DevUtils.LogDebugMessage(string.Format("GetFreePortInRange, PortStartIndex: {0} PortEndIndex: {1}", PortStartIndex, PortEndIndex));
            try
            {
                IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
    
                IPEndPoint[] tcpEndPoints = ipGlobalProperties.GetActiveTcpListeners();
                List<int> usedServerTCpPorts = tcpEndPoints.Select(p => p.Port).ToList<int>();
    
                IPEndPoint[] udpEndPoints = ipGlobalProperties.GetActiveUdpListeners();
                List<int> usedServerUdpPorts = udpEndPoints.Select(p => p.Port).ToList<int>();
    
                TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
                List<int> usedPorts = tcpConnInfoArray.Where(p=> p.State != TcpState.Closed).Select(p => p.LocalEndPoint.Port).ToList<int>();
    
                usedPorts.AddRange(usedServerTCpPorts.ToArray());
                usedPorts.AddRange(usedServerUdpPorts.ToArray());
    
                int unusedPort = 0;
    
                for (int port = PortStartIndex; port < PortEndIndex; port++)
                {
                    if (!usedPorts.Contains(port))
                    {
                        unusedPort = port;
                        break;
                    }
                }
                DevUtils.LogDebugMessage(string.Format("Local unused Port:{0}", unusedPort.ToString()));
    
                if (unusedPort == 0)
                {
                    DevUtils.LogErrorMessage("Out of ports");
                    throw new ApplicationException("GetFreePortInRange, Out of ports");
                }
    
                return unusedPort;
            }
            catch (Exception ex)
            {
    
                string errorMessage = ex.Message;
                DevUtils.LogErrorMessage(errorMessage);
                throw;
            }
        }
    
    
    
    private int GetLocalFreePort()
        {
            int hemoStartLocalPort = int.Parse(DBConfig.GetField("Site.Config.hemoStartLocalPort"));
            int hemoEndLocalPort = int.Parse(DBConfig.GetField("Site.Config.hemoEndLocalPort"));
            int localPort = GetFreePortInRange(hemoStartLocalPort, hemoEndLocalPort);
            DevUtils.LogDebugMessage(string.Format("Local Free Port:{0}", localPort.ToString()));
            return localPort;
        }
    
    
    
    
    
    public void Connect(string host, int port)
        {
            try
            {
                //Create socket
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
    
                var localPort = GetLocalFreePort();
                //Create an endpoint for the specified IP on any port
                IPEndPoint bindEndPoint = new IPEndPoint(IPAddress.Any, localPort);
    
                //Bind the socket to the endpoint
                socket.Bind(bindEndPoint);
    
                //Connect to host
                socket.Connect(IPAddress.Parse(host), port);                
    
                socket.Dispose();
            }
            catch (SocketException ex)
            {
                //Get the error message
                string errorMessage = ex.Message;
                DevUtils.LogErrorMessage(errorMessage);
            }
        }
    
    
        public void Connect2(string host, int port)
        {
            try
            {
                //Create socket
    
                var localPort = GetLocalFreePort();
                //Create an endpoint for the specified IP on any port
                IPEndPoint bindEndPoint = new IPEndPoint(IPAddress.Any, localPort);
    
                var client = new TcpClient(bindEndPoint);
                //client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //will release port when done   
    
                //Connect to host
                client.Connect(IPAddress.Parse(host), port);                
    
                client.Close();             
            }
            catch (SocketException ex)
            {
                //Get the error message
                string errorMessage = ex.Message;
                DevUtils.LogErrorMessage(errorMessage);
            }
        }
    
  • 4

    首先打开端口,然后将正确的端口号提供给另一个进程 .

    否则,某些其他进程仍然可能首先打开端口,但您仍然有另一个进程 .

  • 4

    这是一个与TheSeeker接受的答案相当的解决方案 . 虽然我觉得它更具可读性:

    using System;
    using System.Net;
    using System.Net.Sockets;
    
        private static readonly IPEndPoint DefaultLoopbackEndpoint = new IPEndPoint(IPAddress.Loopback, port: 0);
    
        public static int GetAvailablePort()
        {
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                socket.Bind(DefaultLoopbackEndpoint);
                return ((IPEndPoint)socket.LocalEndPoint).Port;
            }
        }
    
  • 1

    如果您只想提供一个起始端口,并让它返回给您可用的下一个tcp端口,请使用如下代码:

    public static int GetAvailablePort(int startingPort)
    {
        var portArray = new List<int>();
    
        var properties = IPGlobalProperties.GetIPGlobalProperties();
    
        // Ignore active connections
        var connections = properties.GetActiveTcpConnections();
        portArray.AddRange(from n in connections
                            where n.LocalEndPoint.Port >= startingPort
                            select n.LocalEndPoint.Port);
    
        // Ignore active tcp listners
        var endPoints = properties.GetActiveTcpListeners();
        portArray.AddRange(from n in endPoints
                            where n.Port >= startingPort
                            select n.Port);
    
        // Ignore active udp listeners
        endPoints = properties.GetActiveUdpListeners();
        portArray.AddRange(from n in endPoints
                            where n.Port >= startingPort
                            select n.Port);
    
        portArray.Sort();
    
        for (var i = startingPort; i < UInt16.MaxValue; i++)
            if (!portArray.Contains(i))
                return i;
    
        return 0;
    }
    

Related