异步TCP服务器保持套接字但停止侦听

时间:2015-04-02 18:38:48

标签: c# .net asynchronous tcp async-await

我有以下异步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);
        }
    }

2 个答案:

答案 0 :(得分:5)

有三个问题:

  1. 您逐个处理连接。一个故障/挂起连接会占用整个服务器。只需删除await t;即可。您已经记录了worker函数中的所有错误。
  2. 使HandleConnectionAsync返回非常快,以便可以快速恢复接受新连接。我牺牲了很少的效率,只是说Task.Run(() => HandleConnectionAsync(tcpClient))以确保处理可以立即继续。现在所有文件打开的东西都是同步的,并且阻止了接受工作流程。
  3. 通过打包确定关闭tcpClientusing (tcpClient) ...。这可以防止僵尸客户端在出现错误时闲逛。

答案 1 :(得分:-1)

如果您仍然连接,则应检查。

也许这很有用: How to test for a broken connection of TCPClient after being connected?