delphi - 如何在 Indy SSL 中设置 ConnectTimeout/ReadTimeout

标签 delphi indy lazarus freepascal

使用 SSL 时如何在 Indy 中设置 ConnectTimeout/ReadTimeout ?

MCVE:

program mcve;

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}SysUtils, IdHTTP, IdSSLOpenSSL, DateUtils;

var
  HTTP    : TIdHTTP;
  SSL     : TIdSSLIOHandlerSocketOpenSSL;
  Started : TDateTime;
begin
  HTTP := TIdHTTP.Create();
  try
    HTTP.ReadTimeout            := 1000;
    HTTP.ConnectTimeout         := 2000;
    SSL                         := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
    SSL.ConnectTimeout          := HTTP.ConnectTimeout;
    SSL.ReadTimeout             := HTTP.ReadTimeout;
    SSL.SSLOptions.SSLVersions  := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    HTTP.IOHandler              := SSL;
    Started := Now;
    try
      HTTP.Get(ParamStr(1));
    except
      On E: Exception do WriteLn(E.Message);
    end;
    Writeln(FormatDateTime('hh:nn:ss', SecondsBetween(Started, Now) / SecsPerDay));
  finally
    HTTP.Free;
  end;
end.

当使用 http 时,ConnectTimeout/ReadTimeout 可以正常工作,只有在使用 https 时才可以解决此问题,如下所示:

:~$ ./mcve http://x.x.x.x
Read timed out.
00:00:01 <-- Correct.
<小时/>
:~$ ./mcve https://x.x.x.x
Socket Error # 0

00:03:38 <-- NOT Correct / More than SSL.ReadTimeout value.

从 OPM 版本 10.6.2.5494 安装 Lazarus 2.0.6 Indy。

注意:在 Windows 上使用 Delphi 和 Indy 10.6.2.5366 的相同代码,结果按预期工作

最佳答案

您无需手动设置ConnectTimeoutReadTimeout在 IOHandler 本身上,仅在客户端组件上(在本例中为 TIdHTTP )。 TIdTCPClient.Connect()将为您将值分配给 IOHandler。

ConnectTimeout在创建任何 SSL/TLS session 之前,底层套接字连接到服务器时适用,因此无论您是否使用 SSL/TLS,它的操作都是相同的。

ReadTimeout当 Indy 尝试从 IOHandler 的内部连接读取字节时适用。当不使用 SSL/TLS 时,这意味着它直接进入套接字,因此当没有字节到达套接字时就会超时。但是当使用 SSL/TLS 时,Indy 使用 OpenSSL 的遗留 SSL_...() API,而不是较新的 BIO_...() API,这意味着 OpenSSL 正在代表 Indy 进行自己的套接字读取和缓冲,因此当 OpenSSL 不提供任何解密的应用程序字节时,Indy 会超时。

方式上的一个区别TIdSSLIOHandlerSocketOpenSSL在 Windows 上运行与其他平台相比,仅在 Windows Vista+ 上运行,TIdSSLIOHandlerSocketOpenSSL确实适用 ReadTimeout到底层套接字的 SO_RCVTIMEOSO_SNDTIMEO通过 IOHandler 的超时 Binding.SetSockOpt()方法,作为 Windows 上 OpenSSL 错误的解决方法。对于其他平台,Indy 目前没有设置这两个套接字超时。

手动设置这些超时的好地方是 IOHandler 的 OnBeforeConnect事件,该事件在套接字连接到服务器之后、创建任何 SSL/TLS session 之前触发。

关于delphi - 如何在 Indy SSL 中设置 ConnectTimeout/ReadTimeout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58779531/

相关文章:

delphi - 使用自定义组件

delphi - 以较慢的速率发送 TCP POST 请求

http - 如何在 Delphi 中使用 Indy 添加 "Authorization=Bearer" header ?

delphi - 使用 Indy 将文件上传到 FTP 服务器

c++ - 如何在 Lazarus (freepascal) 中使用 C++ 生成的 .dll 或 .lib 文件中定义的函数?

delphi - 使用 Delphi 和 Access

forms - 数据库组件或新组件的视觉继承?

delphi - 在登录之前,如何在运行时确定 Crystal XI 报表的连接方法?

delphi - 从 imap4 服务器发送 'BAD error_here' 时检索错误消息

resources - 有关 Lazarus 和/或 FPC 的活跃博客