异步 TCP 服务器持有套接字但停止侦听
Asycn TCP Server holds the socket but stops listening
我有以下异步 TCP 服务器,我用它来接受来自要上传文件的客户端的传入请求。大约 1-4 小时后,服务器将停止接受任何新连接。这一直让我感到困惑,因为我无法确定地重现错误。我程序中的其余线程继续正常运行。没有任何异常抛出。关于可能发生的事情有什么建议吗?
在服务器死机之前,我所看到的只是它设法完成了挂起的请求,然后停止了。我有一种预感,服务器正在经历频繁的网络断开连接。如何使这段代码对故障更健壮?我已经将 try-catch 添加到可能会失败的两段代码中,但我觉得我仍然遗漏了一些东西。
我设置了另一个线程来检查此服务器是否释放套接字,但即使在它停止处理客户端请求后套接字似乎仍在使用中。我使用 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);
}
}
你应该检查一下你是否仍然连接。
也许这有用:
How to test for a broken connection of TCPClient after being connected?
存在三个问题:
- 您一个接一个地处理连接。一个 faulty/hanging 连接支持整个服务器。只需删除
await t;
。您已经在 worker 函数中记录了所有错误,这很好。
- 使 HandleConnectionAsync return 非常快,以便可以快速恢复接受新连接。我会牺牲一点点效率,只说
Task.Run(() => HandleConnectionAsync(tcpClient))
以确保处理可以立即继续。现在所有文件打开的东西都是同步的,并阻碍了接受工作流程。
- 通过包装确定性地关闭
tcpClient
:using (tcpClient) ...
。这样可以防止僵尸客户端在出现错误时徘徊。
我有以下异步 TCP 服务器,我用它来接受来自要上传文件的客户端的传入请求。大约 1-4 小时后,服务器将停止接受任何新连接。这一直让我感到困惑,因为我无法确定地重现错误。我程序中的其余线程继续正常运行。没有任何异常抛出。关于可能发生的事情有什么建议吗?
在服务器死机之前,我所看到的只是它设法完成了挂起的请求,然后停止了。我有一种预感,服务器正在经历频繁的网络断开连接。如何使这段代码对故障更健壮?我已经将 try-catch 添加到可能会失败的两段代码中,但我觉得我仍然遗漏了一些东西。
我设置了另一个线程来检查此服务器是否释放套接字,但即使在它停止处理客户端请求后套接字似乎仍在使用中。我使用 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);
}
}
你应该检查一下你是否仍然连接。
也许这有用: How to test for a broken connection of TCPClient after being connected?
存在三个问题:
- 您一个接一个地处理连接。一个 faulty/hanging 连接支持整个服务器。只需删除
await t;
。您已经在 worker 函数中记录了所有错误,这很好。 - 使 HandleConnectionAsync return 非常快,以便可以快速恢复接受新连接。我会牺牲一点点效率,只说
Task.Run(() => HandleConnectionAsync(tcpClient))
以确保处理可以立即继续。现在所有文件打开的东西都是同步的,并阻碍了接受工作流程。 - 通过包装确定性地关闭
tcpClient
:using (tcpClient) ...
。这样可以防止僵尸客户端在出现错误时徘徊。