【问题标题】:Asycn TCP Server holds the socket but stops listening异步 TCP 服务器持有套接字但停止侦听
【发布时间】:2015-06-07 19:56:14
【问题描述】:

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

【问题讨论】:

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


【解决方案1】:

存在三个问题:

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

【讨论】:

  • +1 这些都是绝妙的观察。回想起来,这似乎是一个愚蠢的错误。非常感谢您的澄清。服务器在过去三天内没有崩溃过一次 :) 我会继续监控。最后一个问题:我是否使用工作任务中的 await 操作正确地进行网络读取和文件写入?对我来说,它看起来是正确的,但我只是想通过第二双眼睛来确认。另外,您能否添加一些关于为什么等待首先导致问题的信息?
  • @Legend 读写正确。您可以(启发式地)通过 await 代码看起来就像同步代码但在其上机械地加上 await 的事实来判断这一点。如果您不做任何时髦的事情,那么使用 await 使代码异步很容易。我会用一个问题来回答最后一个问题:在你看来,await t; 做了什么?
  • 谢谢!我的理解是它会让线程等待Task t 完成,所以它会在接受另一个连接之前等待?
  • 这几乎是正确的。只是这与线程无关,因为等待的目的是释放线程而不是让它们等待/阻塞。但是,是的,这就是为什么它不会立即处理下一个连接。
  • 明白。感谢您澄清这一点!
【解决方案2】:

你应该检查一下,如果你仍然连接。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多