Reverse Proxy :👈 👉:Reverse Proxy vs API Gateway

Socket Exhaustion

What is Socket Exhaustion?

Socket Exhaustion occurs when an application creates too many network connections (sockets) and doesn't release or reuse them efficiently. Eventually, the operating system runs out of available sockets (or ephemeral ports), causing new HTTP requests to fail.

A very common cause in .NET is creating a new HttpClient object for every request.

Bad Example (Causes Socket Exhaustion)

public async Task<string> GetData()
{
    using (var client = new HttpClient())
    {
        return await client.GetStringAsync(
            "[https://api.example.com/data](https://api.example.com/data)");
    }
}

Looks harmless, but if this method executes thousands of times:

for(int i = 0; i < 10000; i++)
{
    await GetData();
}

many TCP connections are created.

Even after HttpClient is disposed, the underlying TCP connections may remain in the TIME_WAIT state for some time.

App Creates Client #1 Creates Client #2 Creates Client #3 Operating System

Many sockets remain in TIME_WAIT

Eventually:

System.Net.Http.HttpRequestException

or

Only one usage of each socket address
(network address/port) is normally permitted.

Why Does This Happen?

When a TCP connection closes:

Client -------- Server

   FIN ------>

   <------ ACK

the socket does not disappear immediately. The OS keeps it in:TIME_WAIT to ensure all packets are delivered properly. If thousands of connections are opened and closed rapidly:5000+ sockets in TIME_WAIT new connections cannot be created.

How to Prevent It

✅ Option 1: Reuse a Single HttpClient

public class ApiService
{
    private static readonly HttpClient _client =
        new HttpClient();
    public async Task<string> GetData()
    {
        return await _client.GetStringAsync(
            "[https://api.example.com/data](https://api.example.com/data)");
    }
}

Benefits:

  • Reuses connections
  • Uses connection pooling
  • Reduces resource usage

✅ Option 2: Use IHttpClientFactory (Recommended)

In ASP.NET Core, Microsoft recommends IHttpClientFactory.

Register

builder.Services.AddHttpClient();

Use

public class WeatherService
{
    private readonly HttpClient _client;
    public WeatherService(
        IHttpClientFactory factory)
    {
        _client = factory.CreateClient();
    }

    public async Task<string> GetWeather()
    {
        return await _client.GetStringAsync(
            "[https://api.weather.com](https://api.weather.com)");
    }
}

Why It Helps

IHttpClientFactory:

  • Reuses underlying handlers
  • Manages connection pools
  • Prevents socket exhaustion
  • Handles DNS changes better
  • Centralizes configuration

Named Client Example

builder.Services.AddHttpClient(
    "GitHub",
    client =>
    {
        client.BaseAddress =
            new Uri("[https://api.github.com](https://api.github.com)");
        client.DefaultRequestHeaders.Add(
            "User-Agent",
            "MyApp");
    });

Use:

public class GitHubService
{
    private readonly HttpClient _client;
    public GitHubService(
        IHttpClientFactory factory)
    {
        _client = factory.CreateClient(
            "GitHub");
    }
}

Real-World Scenario

Imagine an ASP.NET Core API receives:

1000 requests/minute

and for every request:

using var client = new HttpClient();

After a short period:

Request Create HttpClient Create Socket Dispose Client Socket enters TIME_WAIT

Thousands of sockets accumulate. Users then see:

  1. Connection refused
  2. Timeout
  3. No buffer space available
  4. SocketException

Modern Best Practice (.NET Core / .NET 8+)

Program.cs

builder.Services.AddHttpClient<IMyApiService,
    MyApiService>(client =>
{
    client.BaseAddress =
        new Uri("[https://api.example.com](https://api.example.com)");
    client.Timeout =
        TimeSpan.FromSeconds(30);
});

Service

public class MyApiService : IMyApiService
{
    private readonly HttpClient _httpClient;
    public MyApiService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
    public async Task<string> GetData()
    {
        return await _httpClient.GetStringAsync(
            "/users");
    }
}

This is the recommended production approach in modern ASP.NET Core applications.

Interview Answer (Short Version)

Socket Exhaustion is a condition where an application creates and disposes many network connections too quickly, causing available TCP sockets/ports to be exhausted. In .NET, it commonly happens when HttpClient is instantiated per request. The solution is to reuse HttpClient instances or use IHttpClientFactory, which manages connection pooling efficiently and prevents socket exhaustion.

Back to Index
Reverse Proxy :👈 👉:Reverse Proxy vs API Gateway