Sign-up for my latest app's private beta at consolewriteline.com!

« Announcing: Flare 1.0 | Main | Announcing Doctype - a Q&A site for web designers »

Detecting the next available, free TCP port

.NET 3.5, C#

I recently had a need to find an available port for selenium, starting at the default of 4444. The code below checks to see if the port you're about to use is available, incrementing your port number to find the next free port if your first choice is in use.

This very simple method uses a global mutex to avoid a race condition when releasing a port.

Adapting it to use UDP is beyond what I need, but it'll be very easy to do - just replace ipGlobalProperties.GetActiveTcpListeners() with ipGlobalProperties.GetActiveUdpListeners();

/// <summary>
/// Provides static methods for operations 
/// commonly required when working with TCP ports
/// </summary>
public static class TcpPort
{
    private const string PortReleaseGuid = 
        "8875BD8E-4D5B-11DE-B2F4-691756D89593";

    /// <summary>
    /// Check if startPort is available, incrementing and
    /// checking again if it's in use until a free port is found
    /// </summary>
    /// <param name="startPort">The first port to check</param>
    /// <returns>The first available port</returns>
    public static int FindNextAvailablePort(int startPort)
    {
        int port = startPort;
        bool isAvailable = true;

        var mutex = new Mutex(false, 
            string.Concat("Global/", PortReleaseGuid));
        mutex.WaitOne();
        try
        {
            IPGlobalProperties ipGlobalProperties = 
                IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] endPoints = 
                ipGlobalProperties.GetActiveTcpListeners();

            do
            {
                if (!isAvailable)
                {
                    port++;
                    isAvailable = true;
                }

                foreach (IPEndPoint endPoint in endPoints)
                {
                    if (endPoint.Port != port) continue;
                    isAvailable = false;
                    break;
                }

            } while (!isAvailable && port < IPEndPoint.MaxPort);

            if (!isAvailable)
                throw new NoAvailablePortsInRangeException();

            return port;
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
}

For usage examples, please see my integration tests:

[TestFixture]
public class TcpPortFixture
{
    [Test]
    public void FindNextAvailablePort()
    {
        Assert.That(TcpPort.FindNextAvailablePort(4444), 
            Is.EqualTo(4444));
    }

    [Test]
    public void FindNextAvailablePortInUse()
    {
        var tcpListener = 
            new TcpListener(IPAddress.Parse("127.0.0.1"), 4444);
        try
        {
            tcpListener.Start();
            Assert.That(TcpPort.FindNextAvailablePort(4444), 
                Is.EqualTo(4445));
        }
        finally
        {
            tcpListener.Stop();
        }
    }
}

Post a comment


Contact Me

If you'd like to get in touch, contact me on +447944 353544 or matt@mattbrindley.com

products

Litmus

Litmus makes compatibility testing easier for web pages and email newsletters.

ThinkFold

Online outlining, for groups. Collaborate in realtime with colleagues!

Delicious Presentation Creator

20 slides from your Delicious feed, 20 seconds each.

Flare

A site-specific browser for 37Signals' Campfire chat app, bring Campfire to your desktop.

CSSVista

Edit your CSS code live in both Internet Explorer and Firefox simultaneously.