delphi - 如何在 Indy SSL 中设置 ConnectTimeout/ReadTimeout
问题描述
使用 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 的相同代码,结果按预期工作
解决方案
您不需要在 IOHandler 本身上手动设置ConnectTimeout
and ReadTimeout
,只需在客户端组件上(在本例中为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 不提供任何解密的应用程序字节时,Indy 会超时。
在 Windows 与其他平台上的操作方式的一个区别TIdSSLIOHandlerSocketOpenSSL
是,仅在 Windows Vista+ 上,TIdSSLIOHandlerSocketOpenSSL
确实通过 IOHandler 的方法将 应用于ReadTimeout
底层套接字SO_RCVTIMEO
和SO_SNDTIMEO
超时Binding.SetSockOpt()
,作为 Windows 上 OpenSSL 错误的解决方法。对于其他平台,Indy 目前没有设置这两个套接字超时。
手动设置这些超时的好地方是在 IOHandler 的OnBeforeConnect
事件中,该事件在套接字连接到服务器之后和创建任何 SSL/TLS 会话之前触发。
推荐阅读
- docker - 在 docker swarm stack deploy 期间没有在工作节点上创建覆盖网络
- python - 找不到模板 Django
- c++ - 链表“抛出异常”
- windows - 如何从桌面上删除除 .Ink 快捷方式以外的所有文件?(视窗 10)
- javascript - 将图像添加到使用 jsPDF 创建的 pdf,然后使用 jsZIP 压缩 pdf
- r - 带有可点击链接的 tmap 传单上的弹出窗口
- r - 使用 3d 加速度计算动物滚动的正确方法?
- reactjs - 标记图标未显示在传单中
- c# - 如何更改从 monthCalendar 输出的日期格式
- ruby-on-rails - 如何扩展 ActiveSupport::TaggedLogging 以输出 json 行