【问题标题】:Indy 10 + SSL = works in Windows 7, does not work on XPIndy 10 + SSL = 适用于 Windows 7,不适用于 XP
【发布时间】:2013-03-12 13:49:43
【问题描述】:

我正在使用 Indy 10 Http Client(最新的 SVN 版本)和 SSL 处理程序(Delphi 7)来获取 https://www.webtide.com/choose/jetty.jsp 网站的内容。

它在 Windows 7 x64(在两个系统上测试)上运行良好,但在 WindowsXP x86(在 3 个系统上测试)上,测试应用程序只是挂在 TIdHTTP.Get() 上而没有恢复的可能性(意味着即使在工作程序/线程不起作用!)。测试应用无法恢复,必须使用任务管理器关闭。

SSL 库(32 位 x86!)来自这里:http://slproweb.com/products/Win32OpenSSL.html 但我尝试了来自不同网站的 5 个其他版本,结果相同。

这是一个包含源代码、编译后的可执行文件和 SSL 库的 zip 包:

https://www.dropbox.com/s/pd5soxon0qbnnl0/IndyTest.zip

这里是源代码(表单有一个按钮和两个备忘录):

 procedure TForm1.Button1Click(Sender: TObject);
 var IdHTTP1: TIdHTTP;
     sl : TStringList;
     SSL1: TIdSSLIOHandlerSocketOpenSSL;
 begin
   try
    try
      IdHTTP1 := TIdHTTP.Create(nil);
      sl := TStringList.Create;

      SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
      SSL1.SSLOptions.Method := sslvSSLv23;

      with IdHTTP1 do
      begin
           ConnectTimeout := 10 * 1000;
           ReadTimeout := 10 * 1000;
           IOHandler := SSL1;

           Request.UserAgent := 'Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)';
           Memo2.Text := 'connecting...';
           Application.ProcessMessages;
           Memo1.Text := Get('https://www.webtide.com/choose/jetty.jsp');
           Memo1.Lines.Add ('response: '+ResponseText);
           Memo2.Text := 'connected or timeout...';
      end;
    except
      On e: Exception do
           Memo2.Text := 'Exception: '+e.Message;
    end;
   finally
      IdHTTP1.Free;
      SSL1.Free;
      sl.Free;
   end;
 end;

为什么它在 WindowsXP 上崩溃/挂起?

【问题讨论】:

  • 你有什么问题?
  • 为什么它在 WindowsXP 上崩溃/挂起?
  • 你就不能问问调试器为什么挂了?暂停程序,调试器会告诉你它在哪里等待。您可以使用此代码连接到任何其他站点,还是仅此特定代码使您的程序挂起?
  • 调试 indy 非常困难,因为当你以慢动作连接时会发生奇怪的事情。如果我暂停代码并使用 F8 Delphi 会遍历所有消息句柄。没有显示任何 Indy 代码。
  • Indy 的ConnectTimeout 仅在建立底层 TCP/IP 连接时适用于套接字 API connect() 函数。之后调用SSL_connect() 来启动SSL 握手,这是应用程序数据,因此不受ConnectTimeout 的约束。值得一提的是,Indy 确实使用其ReadTimeout 属性在 OpenSSL 连接上分配套接字级读/写超时,但仅在 Vista+ 上作为 OpenSSL 错误的解决方法。在 XP 上,默认套接字读/写超时适用。

标签: delphi openssl jetty indy indy10


【解决方案1】:

Indy 的 ConnectTimeout 属性仅在建立底层 TCP/IP 连接时适用于套接字 API connect() 函数。 SSL_connect() 稍后被调用以启动 SSL 握手,这是应用程序数据,因此不受 ConnectTimeout 的约束。

Indy 确实使用其ReadTimeout 属性在 OpenSSL 连接上分配套接字级别的读/写超时,但仅在 Vista+ 上作为 OpenSSL 错误的解决方法。在 XP 和更早版本上,应用默认的套接字读/写超时。 ReadTimeout 只告诉 Indy 在读取数据时要等待多长时间,但它并不应用于套接字本身。如果你想这样做,你可以在建立 TCP/IP 连接之后但在开始 SSL 握手之前调用 TIdSocketHandle.SetSockOpt() 方法手动完成,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
  IdHTTP1: TIdHTTP;
  SSL1: TIdSSLIOHandlerSocketOpenSSL;
begin
  try
    IdHTTP1 := TIdHTTP.Create(nil);
    try
      SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
      SSL1.SSLOptions.Method := sslvSSLv23;

      with IdHTTP1 do
      begin
        ConnectTimeout := 10 * 1000;
        ReadTimeout := 10 * 1000;
        IOHandler := SSL1;

        OnConnected := IdHTTPConnected;
        OnStatus := IdHTTPStatus;

        Request.UserAgent := 'Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)';

        Memo1.Text := Get('https://www.webtide.com/choose/jetty.jsp');
        Memo1.Lines.Add('response: '+ ResponseText);

        Memo2.Text := 'finished...';
      end;
    finally
      IdHTTP1.Free;
    end;
  except
    on e: Exception do
      Memo2.Text := 'Exception: ' + e.Message;
  end;
end;

procedure TForm1.IdHTTPStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
begin
  case AStatus of
    hsResolving: Memo2.Text := 'resolving...';
    hsConnecting: Memo2.Text := 'connecting...';
    hsConnected: Memo2.Text := 'connected...';
    hsDisconnecting: Memo2.Text := 'disconnecting...';
    hsDisconnected: Memo2.Text := 'disconnected...';
  end;
  Update;
end;

procedure TForm1.IdHTTPConnected(Sender: TObject);
begin
  with TIdHTTP(Sender).Socket.Binding do
  begin
    SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, 10 * 1000);
    SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, 10 * 1000);
  end;
end;

【讨论】:

  • 雷米,我试过你的代码。在 Win7 上运行良好,但在 WindowsXP 上它仍然挂起(因为现在测试应用程序有一个沙漏图标 10 分钟)。 memo2 中没有“正在连接...”。更糟糕的是,当它挂起时,您无法暂停应用程序并在 Delphi IDE 中使用调试器,因为 IDE 标题更改为“正在停止...”并挂在那里,直到您终止应用程序!
  • 我认为这里的问题是没有应用接收/发送超时,因为它已经在连接/握手时挂起,而不是在发送/接收数据时。
  • @Casady:如果您没有看到OnStatus 事件以hsConnecting 状态触发,那么 Indy 根本没有尝试将套接字连接到服务器,这与使用 SSL。 OnConnected 事件在套接字连接时立即触发,在任何数据交换之前,因此这是设置套接字超时的最早机会。
  • @Casady:假设您至少看到OnStatus 事件触发器处于hsResolving 状态,那么您会遇到主机名到IP 地址的DNS 解析挂起,这种情况会发生在套接字可以连接之前。该分辨率由操作系统处理,而不是由 Indy 处理,因此 Indy 无法为此使用任何超时。如果事实证明这是您的挂起实际发生的地方,那么您的 PC 在 Indy 之外遇到了 DNS 问题。
猜你喜欢
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-24
相关资源
最近更新 更多