20 秒后超时的 TcpClient SocketException 无论如何

TcpClient SocketException with timeout after 20s no matter what

我想用 TcpClient 等待客户端的缓慢响应,但无论我如何配置它,都会在大约 20 秒后超时。这是我的尝试:

using (var client = new TcpClient { ReceiveTimeout = 9999999, SendTimeout = 9999999 })
{
    await client.ConnectAsync(ip, port);
    using (var stream = client.GetStream())
    {
        // Some quick read/writes happen here via the stream with stream.Write() and stream.Read(), successfully.

        // Now the remote host is calculating something long and will reply if finished. This throws the below exception however instead of waiting for >20s.
        var bytesRead = await stream.ReadAsync(new byte[8], 0, 8);
    }
}

例外是 IOException:

Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

...里面有一个SocketException

A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

SocketErrorCodeTimedOut.

20 年代 seems to be an OS default on Windows 但是否可以通过与 TcpClient 交互从托管代码覆盖它?或者我怎么才能等待响应呢?

我也试过老式的 BeginRead-EndRead 方式,同样的事情发生在 EndRead 上。该问题也不是由 Windows 防火墙或 Defender 引起的。

I'd like to wait for a slow response from a client

请务必注意,失败的是 连接。连接超时仅用于建立连接,连接应该总是非常快的。事实上,OS 将代表 应用程序接受连接 ,因此您实际上只是在谈论数据包往返。 21秒应该足够了。

建立连接后,您可以删除ReceiveTimeout/SendTimeout并使用异步读取永远等待。

事实证明,远程主机没有及时响应,因此出现了问题。让我详细说明一下,虽然这将是一个非常针对我的情况的解决方案,但也许它对其他人也有用。

真正的问题不是超时本身,如异常所示,而是后续 Read() 调用中抛出的异常显示:"An existing connection was forcibly closed by the remote host"

远程主机并非有意关闭连接。相反,发生的情况是,当它响应缓慢时,它实际上非常忙,以至于它也没有处理任何 TCP 流量。虽然本地主机在等待响应时没有明确发送任何内容,但这仍然是一个问题:本地主机尝试为远程主机的先前传输发送 ACK。由于这些无法传送,本地主机确定远程主机 "forcibly closed" 连接。

我通过 Wireshark 查看流量得到了线索(尝试查看表面之下的内容而不是四处猜测总是好的):很明显,当远程主机忙碌时,它显示完全的无线电静默。同时 Wireshark 显示了本地主机进行的重传尝试,表明这是问题所在。

因此该解决方案也无法在本地主机上实施,需要更改远程主机的行为。