如果在回调期间测试已连接,Indy OpenSSL 会出现问题

Indy OpenSSL problems if test Connected during callback

Delphi v10.1 柏林。 Indy v10.6.2 OpenSSL v1.0.2h

我在 Delphi 中设置了一个表单,用于测试使用 TIdIMAP4 和 SSL 连接 (TIdSSLIOHandlerSocketOpenSSL)。因为这是为了测试,所以我设置了一个复选框以显示 IMAP 组件当前是否已连接,并且我将 IMAP 和 SSL IOHandler 的 OnStatus 和 OnStatusInfo 事件连接到更新复选框的代码。该代码很简单:

IsConnectedCB.Checked := imap.Connected;

最终(我花了比我愿意承认的时间更长的时间)我发现这就是破坏 SSL 连接的原因。这是所发生情况的示例(状态消息的日志):

02:35:13 S: Resolving hostname localhost.
02:35:13 S: Connecting to 127.0.0.1.
02:35:13 S: Connected.
02:35:13 S: SSL status: "before/connect initialization"
02:35:13 S: SSL status: "before/connect initialization"
02:35:13 S: SSL status: "SSLv3 write client hello A"
02:35:13 S: SSL status: "SSLv3 read server hello A"
02:35:43 S: SSL status: "SSLv3 read server certificate A"
02:35:46 S: Disconnecting.
02:35:46 S: Disconnected.
02:35:48 E: SSL negotiation failed.

注意 "server hello A" 之后的时差(有时发生在 "client hello A" 之后)- 这是连接尝试超时的地方。

事实证明,对 imap.Connected 的调用最终会在 IOHandler 内部进行查询,这会扰乱回调处理。

解决方案很简单:不要在回调期间读取 Connected 属性。 :-)

但是,我希望能够在测试各种长 运行 进程时更新我的​​表单状态,而 OnStatus/OnStatusInfo 事件对此很方便(而不是在我自己的代码中穿插大量调用更新)。所以...

我的问题是:有没有办法判断何时可以安全地测试 Connected 属性? (在本例中 TIdIMAP4.Connected,但我确信该问题一定适用于使用 OpenSSL 的大多数其他组件。)

Is there a way to tell when it is safe to test the Connected property?

如您所见,Connected 执行读取操作。执行 socket I/O 是确定阻塞套接字是否仍然连接且有效的唯一方法。因此,当读取会干扰还需要执行 I/O.

的其他操作的流程时,您不能使用 Connected

事实上,在大多数情况下,您根本不应该直接使用 Connected。在这种情况下,我建议使用 TIdIMAP4.On(Dis)Connected and/or TIdIMAP4.OnStatus 事件来更新 Boolean 变量,然后让代码的其余部分在需要时简单地检查该变量。