我想为WCF服务调用创建一个新的net.tcp://localhost:x/Service端点,并动态分配一个新的开放TCP端口。
我知道当我连接到给定的服务器时,TcpClient会分配一个新的客户端端口。
有没有一种简单的方法在.NET中找到下一个空闲的TCP端口?
我需要实际的数字,以便我可以构建上面的字符串。0不起作用,因为我需要将该字符串传递给另一个进程,以便我可以在该新通道上回调。
我想为WCF服务调用创建一个新的net.tcp://localhost:x/Service端点,并动态分配一个新的开放TCP端口。
我知道当我连接到给定的服务器时,TcpClient会分配一个新的客户端端口。
有没有一种简单的方法在.NET中找到下一个空闲的TCP端口?
我需要实际的数字,以便我可以构建上面的字符串。0不起作用,因为我需要将该字符串传递给另一个进程,以便我可以在该新通道上回调。
这就是我在寻找的内容:
static int FreeTcpPort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
FreeTcpPort()
获取空闲端口和在该端口上启动HttpListener之间,我加入了一个Sleep(100)
的强制等待,并编写了一个测试。我随后运行了8个相同的进程,对其进行循环测试。但我从未遇到过竞争条件。根据我的经验(Win 7),操作系统显然会在整个短暂端口范围内循环(几千个)之后再次回到起点。因此,上述代码应该是没有问题的。 - Doug SchmidtTcpListener myActualServer = new TcpListener(ipAddress, 0); myActualServer.Start(); return ((IPEndPoint)myActualServer.LocalEndpoint).Port;
或者重要的是在真正启动监听器之前让OP获得端口号? - JakeStrang使用端口号0,TCP协议栈会分配下一个可用的端口。
endpoint.ListenUriMode
设置为 Unique
。 - Yegor这个解决方案与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;
}
}
... SocketType.Dgram, ProtocolType.Udp...
- BatteryAcid我从 Selenium.WebDriver DLL 中找到了下面的代码:
命名空间:OpenQA.Selenium.Internal
类:PortUtility
public static int FindFreePort()
{
int port = 0;
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 0);
socket.Bind(localEP);
localEP = (IPEndPoint)socket.LocalEndPoint;
port = localEP.Port;
}
finally
{
socket.Close();
}
return port;
}
如果您只想提供一个起始端口,并让它返回下一个可用的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;
}
首先打开端口,然后将正确的端口号提供给其他进程。
否则,仍有可能出现其他进程先打开端口而您使用不同的端口号的情况。
如果您想在给定范围内找到下一个可用的TCP端口,以下是更简洁的实现方式:
private int GetNextUnusedPort(int min, int max)
{
if (max < min)
throw new ArgumentException("Max cannot be less than min.");
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
var usedPorts =
ipProperties.GetActiveTcpConnections()
.Where(connection => connection.State != TcpState.Closed)
.Select(connection => connection.LocalEndPoint)
.Concat(ipProperties.GetActiveTcpListeners())
.Concat(ipProperties.GetActiveUdpListeners())
.Select(endpoint => endpoint.Port)
.ToArray();
var firstUnused =
Enumerable.Range(min, max - min)
.Where(port => !usedPorts.Contains(port))
.Select(port => new int?(port))
.FirstOrDefault();
if (!firstUnused.HasValue)
throw new Exception($"All local TCP ports between {min} and {max} are currently in use.");
return firstUnused.Value;
}
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);
}
}