.NET
TCP port
network programming
port availability
C# development

Find the next TCP port in .NET

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In .NET, the safest way to get an available TCP port is usually not to scan numbers yourself. Instead, bind a listener to port 0 and let the operating system pick a free port. If you truly need the next available port in a specific range, you can probe sequentially, but that comes with race conditions you should understand.

Let the Operating System Choose a Free Port

When you create a TcpListener with port 0, the operating system assigns an ephemeral port that is currently available.

csharp
1using System;
2using System.Net;
3using System.Net.Sockets;
4
5public static class Ports
6{
7    public static int GetFreeTcpPort()
8    {
9        TcpListener listener = new TcpListener(IPAddress.Loopback, 0);
10        listener.Start();
11
12        int port = ((IPEndPoint)listener.LocalEndpoint).Port;
13        listener.Stop();
14        return port;
15    }
16
17    public static void Main()
18    {
19        Console.WriteLine(GetFreeTcpPort());
20    }
21}

This is the simplest answer when your application just needs any free local port. It avoids hard-coded port numbers and reduces the chance of collisions during development or test runs.

Finding the Next Available Port in a Range

Sometimes you need a port near a preferred starting value, for example when integrating with a tool that expects a predictable range. In that case, try ports one by one until a bind succeeds.

csharp
1using System;
2using System.Net;
3using System.Net.Sockets;
4
5public static class PortScanner
6{
7    public static int FindAvailablePort(int startPort, int endPort)
8    {
9        for (int port = startPort; port <= endPort; port++)
10        {
11            try
12            {
13                TcpListener listener = new TcpListener(IPAddress.Loopback, port);
14                listener.Start();
15                listener.Stop();
16                return port;
17            }
18            catch (SocketException)
19            {
20            }
21        }
22
23        throw new InvalidOperationException("No free TCP port was found in the requested range.");
24    }
25
26    public static void Main()
27    {
28        Console.WriteLine(FindAvailablePort(5000, 5100));
29    }
30}

This works, but only as a best-effort check. Between the moment you stop the listener and the moment some other part of your application binds the same port, another process can take it.

Avoid the Check-Then-Bind Race

The most common design mistake is to ask for a free port, release it, and assume it will still be free later. That assumption is not reliable in concurrent systems.

If your code needs to own the port, keep the listener open and pass that listener, or the port number together with its open socket, to the rest of the application.

csharp
1using System;
2using System.Net;
3using System.Net.Sockets;
4
5public static class OwnedListener
6{
7    public static TcpListener StartOwnedListener()
8    {
9        TcpListener listener = new TcpListener(IPAddress.Loopback, 0);
10        listener.Start();
11        return listener;
12    }
13
14    public static void Main()
15    {
16        TcpListener listener = StartOwnedListener();
17        int port = ((IPEndPoint)listener.LocalEndpoint).Port;
18
19        Console.WriteLine($"Listening on {port}");
20        listener.Stop();
21    }
22}

That pattern is much safer for tests, temporary servers, and local tooling.

When to Use Loopback vs Any

Use IPAddress.Loopback when the port only needs to be reachable from the local machine. This is usually the correct choice for development tools and test servers.

Use IPAddress.Any only when you intentionally want to accept connections from other machines. Binding broadly can expose a service you only meant to run locally.

Common Pitfalls

  • Scanning for a port and then starting the real server later. Another process may take the port in the gap.
  • Assuming a port is globally free because it is free on one local address.
  • Binding to low-numbered ports without considering operating system restrictions or service conflicts.
  • Using a fixed port in test suites that run in parallel.
  • Listening on IPAddress.Any when local-only access was intended.

Summary

  • In most cases, bind to port 0 and let the operating system pick a free TCP port.
  • If you must search a range, probe by attempting a real bind with TcpListener.
  • A free-port check is not ownership; race conditions still exist after you release the listener.
  • Keep the listener open if your code truly needs to reserve the port.
  • Prefer IPAddress.Loopback for local development and test scenarios.

Course illustration
Course illustration

All Rights Reserved.