当 InternetOpenURL 尝试(并且失败)连接时,如何避免充分利用 CPU 或终止?

Posted

技术标签:

【中文标题】当 InternetOpenURL 尝试(并且失败)连接时,如何避免充分利用 CPU 或终止?【英文标题】:How to avoid full CPU utilisation, or terminate, while InternetOpenURL is trying (and failing) to connect? 【发布时间】:2011-09-16 11:00:46 【问题描述】:

我有一个相当简单的应用程序,它在一个线程中下载文件。该线程使用WinINet APIs,开头如下:

    HINTERNET hInternet = InternetOpen(strUserAgent.c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    DWORD dwFlags = INTERNET_FLAG_NO_UI | INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD;
    HINTERNET hUrl = InternetOpenUrl(hInternet, m_strURL.c_str(), L"", 0, dwFlags, NULL);

但是,如果没有 Internet 连接,或者远程主机已关闭,InternetOpenUrl 将需要很长时间才能超时并完成。当它这样做时——也就是说,只有在它无法连接到远程主机的情况下——它将使用一个 CPU 的 80-100%,直到它最终返回。由于超时延迟设置,这通常会持续一分钟左右。在一个系统上,尽管有超时设置(如下所述),但这种情况会持续长达十分钟。

我该怎么做:

在尝试连接时避免如此大量的 CPU 使用? 如果我想关闭应用程序,请通知线程终止?通常超时是可以的,但如果应用程序需要关闭,那么它将等待这个线程完成,这会花费大量 CPU 在 InternetOpenUrl 中做很少的事情。

[旁白:我系统上的当前超时设置,如 InternetQueryOption 所示:

INTERNET_OPTION_CONNECT_TIMEOUT: 60s INTERNET_OPTION_RECEIVE_TIMEOUT: 30s INTERNET_OPTION_SEND_TIMEOUT: 30s

更改这些将减少方法放弃并返回之前的时间,从而减少使用这么多 CPU 所花费的时间,但可能会影响连接 - 毕竟,超时是有原因的。此应用程序可用于奇怪的连接情况,例如在船上,在这种情况下,连接可能通过卫星进行,具有高延迟,并且比标准桌面互联网连接需要更长的时间。我不知道合理的超时时间是多少。此外,必须有一种更好的方法来避免 CPU 使用并比简单地缩短超时更快地终止。]

【问题讨论】:

这很奇怪。您是否在许多计算机上都遇到过这种 CPU 堵塞问题,还是仅在您的计算机上?我不希望 WinInet 出现这种行为。 它至少在两台机器上:Windows 7 在 WMWare Fusion 机器上(我的 - 它只在我的机器上飙升到 80%)和 Windows XP(我认为)在第二台机器上(QA 工作人员的.) 你试过在异步模式下使用WinInet吗? @Sergius:不,我没有。事实上,我忘记了它有一个异步模式。一些谷歌搜索出现了an interesting article,其中特别提到了终止。我认为您应该将此添加为答案! 在这种情况下我看不到任何 CPU 使用率,并且几乎立即返回错误。可能是硬件或驱动程序问题。 【参考方案1】:

您可以在asynchronous mode 中使用 WinInet。不确定它是否解决了 CPU 利用率问题,但可以正确处理终止。

【讨论】:

阅读文档,这对我来说似乎是最安全的终止选项。在赏金到期之前我没有时间尝试它,但听起来不错,所以给自己加分! @David,异步模式对您的情况没有帮助,尽管它是使用 WinINet 库的推荐方式。在您的情况下 InternetOpenUrl 需要时间,因此在异步模式下,除非您关闭会话句柄,否则您也无法终止该功能。 @Vishal,InternetOpenUrl 不应在异步模式下阻塞。 @Sergius,同意 InternetOpenUrl 在异步模式下不会阻塞,但它需要完成并返回句柄才能对该句柄进行任何处理。就术语而言,将其放在单独的线程中并不好。【参考方案2】:

我认为您可以使用 InternetCloseHandle 关闭从 InternetOpen 返回的会话句柄。

根据http://msdn.microsoft.com/en-us/library/aa384350(v=VS.85).aspx,它将取消阻止对该句柄的任何挂起操作。

所以基本上如果您将 InternetOpenUrl 保留在一个单独的线程中,您仍然可以从父线程关闭会话句柄(如果您在异步模式下使用它,则不需要单独的线程)。您可以为任何资源清理设置状态回调函数。

如果您想设置不同的超时,请使用 InternetSetOption。

PS:我已经用WinINet库做了一段时间了,所以我不能保证上面的方法会起作用。

【讨论】:

有趣 - 所以我会调用 InternetOpenUrl 但将它返回的句柄传递给可以关闭它的主线程? 我说的是你可以将 InternetOpenUrl 保留在一个单独的线程中,当你想停止操作时,关闭你作为主线程中第一个参数提供的 HINTERNET 句柄。

以上是关于当 InternetOpenURL 尝试(并且失败)连接时,如何避免充分利用 CPU 或终止?的主要内容,如果未能解决你的问题,请参考以下文章

R - 尝试安装包时:InternetOpenUrl 失败

InternetOpenUrl 在第三次和后续调用中挂起并失败

<WinInet.h> API 中的 InternetOpenUrl 和 InternetReadFile 帮助

挂钩 InternetOpenUrl

减少 InternetOpenUrl 超时?

InternetOpenURL 的默认缓存刷新时间是多少?