Windows 套接字 #10060 错误(WSAETIMEDOUT - 尝试连接超时但未建立连接)是否是一个编程错误?

Can Windows Socket #10060 error (WSAETIMEDOUT - An attempt to connect timed out without establishing a connection) be a programming error at all?

我有 Delphi 使用 Indy HTTP 组件(使用 Windows 套接字)的应用程序。在执行 Indy 程序时,我有时会收到#10060 套接字错误(WSAETIMEDOUT - 尝试连接超时而未建立连接):

CheckForSocketError(IdWinsock2.Connect(ASocket, @LAddr, SizeOf(LAddr)));
...
connect : TconnectProc;
...
TconnectProc = function ( const s: TSocket; const name: PSockAddr; const namelen: Integer): Integer; stdcall;

实际上所有这些只是环绕 Windows 连接函数 https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect,它给出错误和消息 WSAETIMEDOUT。所以 - 我的问题是 - 这可能是编程错误吗?即使我在另一台计算机上有服务器 运行,甚至该服务器在服务请求时遇到问题,即使在这种情况下,低级连接也应该正常执行,如果服务器无法服务 GET/POST 请求,那么,当然,错误应该是,但这些错误应该 spring 仅在执行其他 Socket 函数期间不在 connect 函数中,不是吗?

我正在尝试解决我的问题https://serverfault.com/questions/973648/is-it-possible-that-unencrypted-traffic-can-cause-windows-socket-10057-10060?noredirect=1#comment1266907_973648,现在我正在寻找我的代码中发生了什么。

我的服务器端代码非常简单 - 它只是实现了 TIdHttpServer 组件(我在这里只提供事件名称):

MyForm.IdHTTPServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);

那么 - 我的实施可以解决什么问题,什么可以导致 connect 出现 WSAETIMEDOUT?是的,我的程序有时会很长,但多年来它成功地返回了答案并且没有通信错误。而且我想,那个连接函数甚至可以不依赖(不 use/raise)OnCommandGet 事件,所以,我无法控制服务器端如何处理来自客户端的套接字连接函数?

这可能与 TCP(而非 HTTP)keepalive 连接,也许一些 Windows 更新减少了客户端的 Windows TCP keepalive 客户端设置,现在这表明这样的错误。

Indy TCP 客户端,如 TIdHTTP,有一个 public ConnectTimeout 属性,默认设置为 0(无限)。如果没有指定超时,如果在主 UI 线程中调用客户端的 TIdTCPClient.Connect() 方法并且 TIdAntiFreeze 处于活动状态,则使用 hard-coded 2 分钟超时,否则不会超时用过。

如果使用超时,Indy 会在工作线程中调用 Winsock 的 connect() 函数并等待该线程终止。如果 Indy 的超时结束,则关闭套接字以中止 connect(),然后将 EIdConnectTimeout 引发给调用者。如果 connect() 在 Indy 的超时结束之前退出,则仅当 connect() 失败时才会向调用者引发异常。

如果不使用超时,Indy 直接调用Winsock 的connect(),等待它自行退出,只有在失败时才会抛出异常。

因此,当 Indy 调用 Winsock 的 connect() 函数时,您可以从 Indy 获得 WSATIMEDOUT 错误的唯一方法是,如果 Winsock 本身在 Indy 自己的超时结束之前在内部超时。这并不一定表示您的代码中存在问题。这只是意味着您尝试连接的 Host 在那一刻根本无法访问。如果服务器可访问,但无法接受您的连接,您将收到不同的错误,例如 WSAECONNREFUSED.

如果您的服务器位于防火墙或路由器之后,请确保它没有阻止连接到达您的服务器。尝试 运行 服务器计算机上的数据包嗅探器,例如 WireShark,并确保来自 TIdHTTP 的 3 次 TCP 握手正确到达服务器计算机。