| 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 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.
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 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 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:
Thousands of sockets accumulate. Users then see:
- Connection refused
- Timeout
- No buffer space available
- SocketException
Modern Best Practice (.NET Core / .NET 8+)
Program.cs
builder.Services.AddHttpClient
Service
public class MyApiService : IMyApiService
{
private readonly HttpClient _httpClient;
public MyApiService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task 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
HttpClientis instantiated per request. The solution is to reuseHttpClientinstances or useIHttpClientFactory, which manages connection pooling efficiently and prevents socket exhaustion.
| Reverse Proxy :👈 | 👉:Reverse Proxy vs API Gateway |