理解正确的 http keep-alive 实现

understanding correct http keep-alive implementation

我需要尝试修复 Mono 中的错误。多年来,该错误已被报告,人们试图找出解决方案。在我的情况下,只要有一些延迟,它就很容易重现。我也许能够解决问题,但首先我必须了解什么是正确的行为。

我们有一个服务器通过保持活动连接来处理 http 请求。连接被配置为在服务器关闭连接之前有超时和服务请求限制。

一个简单的测试使用 .NET/Mono HttpClient::GetASync(uri) 方法定期发出请求。

    while (true)
    {
        try
        {
            var httpResponse = await httpClient.GetAsync("https://192.168.1.22/api/v1/system/status/", cancellationToken);
            if (httpResponse.IsSuccessStatusCode)
            {
                Console.Write(".");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("HttpClientGetStatus- Exception - " + ex.GetType() + " " + ex.Message);
        }
       Thread.Sleep(this.StatusFreq * 1000);
    }

在 Microsoft .NET 上,它工作正常。在 Mono 上,无论 Windows/Linux/OSX,时间设置是否达到服务器限制,此测试都会抛出异常。 Mono 实现归结为 WebConnection::ReadDone,它调用 Stream::ReadDone。 Stream::ReadDone 显然理解服务器发送的 FIN 数据包意味着流已关闭并且 returns 0 是应该的。 WebConnection::ReadDone 将此解释为错误并立即抛出异常。

正确的行为是什么?为什么 .NET 也不例外?

谢谢

我在这里通过 Mono 代码进行了大量挖掘。 Mono 中显然存在错误。我修复了它,并将在接下来的几天内提交补丁。 RFC2616 第 8.1 节涉及持久连接。 8.1.4 "Practical Considerations" 节与我们的错误相关。

引用:

客户端、服务器或代理可以随时关闭传输连接。 ...客户端、服务器和代理必须能够从异步关闭事件中恢复。只要请求序列是幂等的(参见第 9.1.2 节),客户端软件应该重新打开传输连接并重新传输中止的请求序列而无需用户交互(参见第 9.1.2 节)...

我的补丁根据 RFC

检查连接是否保持活动状态并尝试恢复