使用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.
从OPM版本10.6.2.5494安装的Lazarus 2.0.6 Indy。
注意:在Windows上,使用带有Delphi的Indy 10.6.2.5366的相同代码,结果按预期工作
[您不需要在IOHandler本身上手动设置:~$ ./mcve https://x.x.x.x
Socket Error # 0
00:03:38 <-- NOT Correct / More than SSL.ReadTimeout value.
和ConnectTimeout
,仅在客户端组件(在本例中为ReadTimeout
)上即可。 TIdHTTP
将为您分配值到IOHandler。
TIdTCPClient.Connect()
在基础套接字连接到服务器时适用,在创建任何SSL / TLS会话之前,因此无论您是否使用SSL / TLS,它的操作都相同。
ConnectTimeout
适用于Indy尝试从IOHandler的内部连接读取字节的情况。当不使用SSL / TLS时,这意味着它直接进入套接字,从而在没有字节到达套接字时超时。但是,当使用SSL / TLS时,Indy使用OpenSSL的旧版ReadTimeout
API,而不是其较新的SSL_...()
API,这意味着OpenSSL代表Indy进行自己的套接字读取和缓冲,因此当OpenSSL不提供任何内容时,Indy超时解密的应用程序字节。
BIO_...()
在Windows与其他平台上的运行方式的一个区别是仅在Windows Vista +上,TIdSSLIOHandlerSocketOpenSSL
确实通过IOHandler的TIdSSLIOHandlerSocketOpenSSL
方法将ReadTimeout
应用于基础套接字的SO_RCVTIMEO
和SO_SNDTIMEO
超时,作为Windows上的OpenSSL错误的解决方法。对于其他平台,Indy当前未设置这两个套接字超时。
手动设置那些超时的一个好地方是在IOHandler的Binding.SetSockOpt()
事件中,该事件在套接字连接到服务器之后并且在创建任何SSL / TLS会话之前触发。