TcpListener will find a random un-used port to listen on if you bind to port 0.
public static int GetRandomUnusedPort()
{
var listener = new TcpListener(IPAddress.Any, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
How about something like this:
static List<int> usedPorts = new List<int>();
static Random r = new Random();
public HttpListener CreateNewListener()
{
HttpListener mListener;
int newPort = -1;
while (true)
{
mListener = new HttpListener();
newPort = r.Next(49152, 65535); // IANA suggests the range 49152 to 65535 for dynamic or private ports.
if (usedPorts.Contains(newPort))
{
continue;
}
mListener.Prefixes.Add(string.Format("http://*:{0}/", newPort));
try
{
mListener.Start();
}
catch
{
continue;
}
usedPorts.Add(newPort);
break;
}
return mListener;
}
I'm not sure how you would find all of the ports that are in use on that machine, but you should get an exception if you try to listen on a port that is already being used, in which case the method will simply pick another port.
Here's an answer, derived from Snooganz's answer. It avoids the race condition between testing for availability, and later binding.
public static bool TryBindListenerOnFreePort(out HttpListener httpListener, out int port)
{
// IANA suggested range for dynamic or private ports
const int MinPort = 49215;
const int MaxPort = 65535;
for (port = MinPort; port < MaxPort; port++)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add($"http://localhost:{port}/");
try
{
httpListener.Start();
return true;
}
catch
{
// nothing to do here -- the listener disposes itself when Start throws
}
}
port = 0;
httpListener = null;
return false;
}
On my machine this method takes 15ms on average, which is acceptable for my use case. Hope this helps someone else.
Unfortunately, this isn't possible. As Richard Dingwall already suggested, you could create a TCP listener and use that port. This approach has two possible problems:
Since you are using an HttpListener (and therefore TCP connections) you can get a list of active TCP listeners using GetActiveTcpListeners
method of the IPGlobalProperties
object and inspect their Port
property.
The possible solution may look like this:
private static bool TryGetUnusedPort(int startingPort, ref int port)
{
var listeners = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners();
for (var i = startingPort; i <= 65535; i++)
{
if (listeners.Any(x => x.Port == i)) continue;
port = i;
return true;
}
return false;
}
This code will find first unused port beginning from the startingPort
port number and return true
. In case all ports are already occupied (which is very unlikely) the method returns false
.
Also keep in mind the possibility of a race condition that may happen when some other process takes the found port before you do.
I'd recommend trying Grapevine. It allows you embed a REST/HTTP server in your application. It includes a RestCluster
class that will allow you to manage all of your RestServer
instances in a single place.
Set each instance to use a random, open port number like this:
using (var server = new RestServer())
{
// Grab the next open port (starts at 1)
server.Port = PortFinder.FindNextLocalOpenPort();
// Grab the next open port after 2000 (inclusive)
server.Port = PortFinder.FindNextLocalOpenPort(2000);
// Grab the next open port between 2000 and 5000 (inclusive)
server.Port = PortFinder.FindNextLocalOpenPort(200, 5000);
...
}
Getting started guide: https://sukona.github.io/Grapevine/en/getting-started.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With