Trouver le prochain port TCP dans .NET
-
02-07-2019 - |
Question
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 attribué de manière dynamique.
Je sais que TcpClient affectera un nouveau port côté client lorsque j'ouvre 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 pour pouvoir construire la chaîne ci-dessus. 0 ne fonctionne pas, car je dois passer cette chaîne à un autre processus pour pouvoir rappeler sur ce nouveau canal.
La solution
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;
}
Autres conseils
Utilisez un numéro de port de 0. La pile TCP allouera le prochain libre.
Ouvrez d'abord le port, puis donnez le numéro de port correct à l'autre processus.
Sinon, il est toujours possible qu'un autre processus ouvre le port en premier et vous en ayez toujours un autre.
C'est une solution comparable à la réponse acceptée de TheSeeker. Bien que je pense que c'est plus lisible:
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;
}
}
Si vous voulez juste donner un port de départ et le laisser vous rendre le prochain port TCP disponible, utilisez un code comme celui-ci:
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;
}
Si vous souhaitez obtenir un port libre dans une plage spécifique afin de l'utiliser comme port / point local:
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 the host
client.Connect(IPAddress.Parse(host), port);
client.Close();
}
catch (SocketException ex)
{
// Get the error message
string errorMessage = ex.Message;
DevUtils.LogErrorMessage(errorMessage);
}
}