Reputation: 116860
I have the following async TCP server that I use to accept incoming requests from clients that want to upload files. After say about 1-4 hours, the server simply stops accepting any new connections. This has been baffling me because I am unable to reproduce the error deterministically. The rest of the threads in my program continue to function properly. There are no exceptions thrown whatsoever. Any suggestions on what could be happening?
Before the server goes dead, all I do see is that it manages to finish the pending requests and then stops. I have a hunch that the server is experiencing frequent network disconnects. How do I make this piece of code more robust to failures? I've added try-catch to both pieces of code that might fail but I feel I'm still missing something.
I setup another thread to check if this server releases the socket but it seems like the socket is in use even after it stops processing client requests. I verified this using netstat -a
internal class TCPServer
{
private readonly int _listeningPort;
private TcpListener listener;
public TCPServer(int port)
{
_listeningPort = port;
listener = new TcpListener(IPAddress.Any, _listeningPort);
listener.Start(int.MaxValue);
}
public async void Start()
{
while (true)
{
Log.Verbose("Waiting for connections...");
try
{
var tcpClient = await listener.AcceptTcpClientAsync();
Task t = HandleConnectionAsync(tcpClient);
await t;
}
catch (Exception exp)
{
Log.Fatal(exp.ToString());
}
}
}
private async Task HandleConnectionAsync(TcpClient tcpClient)
{
try
{
string outputFile = ""; // get a random string
using (var stream = tcpClient.GetStream())
using (var output = File.Create(outputFile))
{
//...
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// ...
await output.WriteAsync(buffer, 0, bytesRead);
}
}
tcpClient.Close();
}
catch (Exception exp)
{
Log(exp.Message);
}
}
Upvotes: 4
Views: 1479
Reputation: 171178
There are three problems:
await t;
. You are already logging all errors in the worker function which is good.Task.Run(() => HandleConnectionAsync(tcpClient))
to be sure that processing can continue immediately. Right now all the file opening stuff is synchronous and holding up the accept workflow.tcpClient
by wrapping it: using (tcpClient) ...
. That prevents zombie clients from hanging around in case of an error.Upvotes: 6
Reputation: 130
You should check, if you are still connected.
Maybe this is useful: How to test for a broken connection of TCPClient after being connected?
Upvotes: -1