2008-09-26 13 views
44

Je souhaite créer un nouveau point de terminaison net.tcp: // localhost: x/Service pour un appel de service WCF, avec un nouveau port tcp ouvert dynamiquement assigné.Trouver le port TCP suivant dans .Net

Je sais que TcpClient affectera un nouveau port côté client lorsque j'ouvrirai une connexion à un serveur donné.

Existe-t-il un moyen simple de trouver le prochain port TCP ouvert dans .Net?

J'ai besoin du nombre réel, de sorte que je puisse construire la chaîne ci-dessus, 0 ne fonctionne pas, puisque je dois passer cette chaîne à un autre processus, de sorte que je peux rappeler sur ce nouveau canal.

+1

http://stackoverflow.com/questions/3563393/how-can-i-get-the-port-that-a-wcf-service-is-listening-on – keza

Répondre

91

Voici ce que je cherchais:

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

Et que se passe-t-il si un autre processus ouvre ce port avant de le rouvrir ...? –

+5

Ensuite, vous obtiendrez une erreur bien sûr, mais ce n'était pas un problème pour mon contexte. – TheSeeker

+8

J'ai utilisé avec succès cette technique pour obtenir un port gratuit. Moi aussi j'étais préoccupé par les conditions de course, avec d'autres processus qui se faufilaient dans le port récemment détecté comme étant libre. J'ai donc écrit un test avec un 'Sleep (100) forcé entre' var port = FreeTcpPort() 'et en démarrant un HttpListener sur le port libre. J'ai ensuite exécuté 8 processus identiques en martelant cela en boucle. Je ne pourrais jamais atteindre la condition de course. Mon témoignage anecdotique (Win 7) est que le système d'exploitation semble parcourir la gamme des ports éphémères (quelques milliers) avant de revenir. Donc, l'extrait ci-dessus devrait être très bien. –

14

Utilisez un numéro de port de 0. La pile TCP allouera la prochaine libre.

+3

Cela ne fonctionne pas, puisque j'ai besoin de ce # réel, pas seulement 0. J'ai besoin de la nombre pour construire une chaîne. – TheSeeker

+0

Celui-ci m'a aidé. Cela fonctionne réellement, si vous notifiez à l'autre côté quel est le port que vous écoutez. – user35443

+0

ServiceHost host = nouveau ServiceHost (typeof (MyService), nouvel Uri ("net.tcp: // localhost: 0/Service")); Ca ne va pas marcher? – jcmcbeth

8

Commencez par ouvrir le port, puis attribuez le numéro de port approprié à l'autre processus.

Sinon, il est toujours possible que d'autres processus ouvrent le port en premier et que vous en ayez encore un autre.

+1

Avez-vous un exemple de code pour obtenir un tel port TCP aussi facile que possible? – TheSeeker

+0

C'est la façon de le faire. Faut être prudent, pourrait être une condition de concurrence si plus d'un processus ouvre le même port. –

1

Si vous souhaitez obtenir un port libre dans un envue de gamme spécifique pour l'utiliser comme port local/Point final:

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); 
     } 
    } 
2

Si vous voulez juste donner un port de départ, et laissez-le vous renvoyer le prochain port de tcp disponible, utilisez le code comme ceci:

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; 
} 
+0

Travaillez parfaitement! – Bestter