【问题标题】:How to set ConnectTimeout/ReadTimeout in Indy SSL如何在 Indy SSL 中设置 ConnectTimeout/ReadTimeout
【发布时间】:2019-11-09 12:57:38
【问题描述】:

使用 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 上使用带有 Indy 10.6.2.5366 的 Delphi 的相同代码,结果按预期工作

【问题讨论】:

    标签: delphi indy lazarus freepascal


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 如何在 OnBeforeConnect 中手动设置?我在 OnBeforeConnect 事件 uses unixtype, sockets; var time : timeval; begin time.tv_sec := 5000; time.tv_usec := 0; fpsetsockopt(ASender.Binding.Handle, Id_SOL_SOCKET, Id_SO_RCVTIMEO, @time, SizeOf(time)); fpsetsockopt(ASender.Binding.Handle, Id_SOL_SOCKET, Id_SO_SNDTIMEO, @time, SizeOf(time)); end; 上试过这个,但没有任何变化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 2021-04-16
    • 2020-07-26
    • 1970-01-01
    相关资源
    最近更新 更多