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

InternetOpenUrl only returns after entire HTTP response is downloaded

本文关键字:HTTP 响应 返回 下载 InternetOpenUrl      更新时间:2023-10-16

我正在使用WinINET编写下载文件实用程序,并且已经注意到(特别是在大型下载时),WinINET InternetOpenUrl()调用仅在整个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);

文档建议发送请求,并处理响应的标头(不完成下载),然后您预计将运行InternetReadFile()循环,直到它返回TRUEdwNumberOfBytesRead为0。

从MSDN


InternetOpenUrl函数: InternetOpenUrl函数解析URL字符串,与服务器建立连接,准备下载URL标识的数据。应用程序可以使用InternetReadFile[…]]来检索URL数据。

InternetReadFile功能:为了确保所有数据都被检索到,应用程序必须继续调用InternetReadFile函数,直到该函数返回TRUE并且lpdwNumberOfBytesRead参数等于零。

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

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

当涉及到超时时,这会使事情变得棘手。如果下载超过了超时时间(看起来默认为30秒),InternetOpenUrl()就会失败。

我有两个问题:

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

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

为什么使它看起来非常像recv()方法包装,如果它只是一个抽象的临时文件,或文件在IE缓存(或更糟,一个浪费的内存块)?

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

这是预期的行为,如果是这样,是否有一种方法来获得数据,因为它是流下来?

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

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

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

重新启动后(在自动更新上浪费了很多很多很多分钟),我又试了一次,还是遇到了同样的问题,但我听取了Alex k和J.J.的建议他的评论认为这不是预期的行为,并开始调查机器上运行的可能干扰的软件。

在许多应用程序被终止,许多服务被关闭之后,我偶然发现了一个我真心希望不会有这种影响的服务,然而它却发生了。

我关闭了"卡巴斯基实验室网络代理",然后,在HTTP响应开始下载后大约2秒,InternetOpenUrl返回。我更喜欢立即下载,但是在75秒的下载过程中,至少有一两秒钟的时间可以让WinINET有时间处理头文件,并做任何可能需要的预处理。

它也证明,如果我不从InternetReadFile()读取数据,下载永远不会完成(通过Charles看到),这意味着(希望)InternetReadFile()是一个包装在recv()调用(正如我所期望的)。

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

所以事实证明,我的(阅读:it安全部门)选择的杀毒软件和它的拦截所有网络层通信保护似乎是问题的原因。