InternetOpenUrl 仅在下载整个 HTTP 响应后返回

2023-12-30

我正在使用 WinINET 编写一个下载文件实用程序,并且注意到(特别是在大型下载时),WinINETInternetOpenUrl()调用仅在整个 HTTP 响应下载完毕后返回。

我通过使用 Charles 代理工具以及 WireShark 确认了这一点,并注意到下载完全完成,然后 WinINET 才通知我的代码。

一些简化的(同步)代码:

hInt = InternetOpen(USER_AGENT_NAME, INTERNET_OPEN_TYPE_PRECONFIG, 
                    NULL, NULL, 0);
DWORD dwRequestFlags = INTERNET_FLAG_NO_UI   // no UI please
            |INTERNET_FLAG_NO_AUTH           // don't authenticate
            |INTERNET_FLAG_PRAGMA_NOCACHE    // do not try the cache or proxy
            |INTERNET_FLAG_NO_CACHE_WRITE;   // don't add this to the IE cache

hUrl = InternetOpenUrl(hInt, szURL, NULL, 0, dwRequestFlags, NULL);
if (hUrl)
{
  // <only gets here after entire download is complete>

  InternetCloseHandle(hUrl);
}
InternetCloseHandle(hInt);

文档suggests这会发送请求,并处理响应的标头(未完成下载),然后您预计会运行InternetReadFile()循环直到返回TRUE and dwNumberOfBytesRead is 0.

来自MSDN
InternetOpenUrl 函数 http://msdn.microsoft.com/en-us/library/aa385098(v=VS.85).aspx:InternetOpenUrl 函数解析 URL 字符串,建立与服务器的连接,并prepares下载由 URL 标识的数据。然后应用程序可以使用 InternetReadFile [...] 来检索 URL 数据。

网络读取文件函数 http://msdn.microsoft.com/en-us/library/aa385103(v=VS.85).aspx:为了确保检索到所有数据,应用程序必须继续调用 InternetReadFile 函数,直到该函数返回 TRUE 并且 lpdwNumberOfBytesRead 参数等于 0。

我也尝试过使用异步方法,并注意到同样的事情。具体来说,INTERNET_STATUS_RESPONSE_RECEIVED仅在下载完成后发送到注册的回调方法。这意味着我的客户端只能在下载完成后开始访问数据。

同样,我也实现了一个使用 WinHttp 库的版本,并注意到完全相同的结果。

当涉及到超时时,这会让事情变得棘手。如果下载超过超时(默认为 30 秒),InternetOpenUrl() fails.

所以我有两个问题:

如果这是 WinInet 和 WinHttp 库的预期行为,为什么文档建议循环遍历InternetReadFile()调用时,为什么不直接读取整个缓冲区(毕竟 WinINET 已经有了)?

我理解提供该功能,因为您并不总是希望分配 150MB 内存块,但提供的借口是您不知道有多少数据可用......但 WinINET 已经完成了下载。

为什么让它看起来非常像recv()如果方法只是对临时文件或 IE 缓存中的文件(或更糟糕的是浪费的内存块)的抽象,那么方法就结束了?

我应该将超时长度设置为多少?如果我永远不知道超时之前数据有多大,那么我如何决定将超时值设置为多少?

这是预期的行为吗?如果是,是否有办法在数据流式传输时获取数据?

在连接速度较慢或文件较大的情况下,可以想象在整个下载完成之前可以对数据进行大量工作。在 HTTP 的经典 Berkley 套接字重新实现中,循环遍历recv()调用将为我提供数据,这最终是我所需要的。

是的,我可以使用简单的套接字重写一个实现,但我不想浪费时间来支持整个 HTTP 规范和 SSL 加密,更不用说 WinINET 中的代理支持了。


我知道回答你自己的问题可能不礼貌,但我相信我找到了问题所在。

重新启动后(很多很多,many在自动更新上浪费了几分钟)我再次尝试,遇到了同样的问题,但我从 Alex K. 和 J.J. 的评论中得到了建议,表明这不是预期的行为,并开始调查机器上运行的可能会干扰的软件。

在许多应用程序被终止、许多服务被关闭之后,我偶然发现了一项服务,我真的希望它不会产生这种效果,但它确实产生了这种效果。

我关闭了“卡巴斯基实验室网络代理”,突然间,InternetOpenUrl 在开始下载 HTTP 响应后约 2 秒返回。我更希望立即下载,但 75 秒下载中的一两秒至少可以让 WinINET 有时间处理标头并进行可能需要的任何预处理。

事实证明,如果我不从 InternetReadFile() 读取数据,下载永远不会完成(如通过 Charles 看到的),这意味着(希望) InternetReadFile() 确实是 recv() 调用的包装器(正如我所见)会预料到)。

连续重新启用和禁用网络代理服务验证了这一发现。我想以某种方式最终证明(或反驳)这一点。

事实证明,我(阅读:IT 安全部门)选择的防病毒及其拦截全网络层通信保护似乎是问题的原因。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

InternetOpenUrl 仅在下载整个 HTTP 响应后返回 的相关文章

随机推荐