jjzjj

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

coder 2024-02-08 原文

我正在使用 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);

文档建议这会发送请求,并处理响应的 header (不完成下载),然后您需要运行 InternetReadFile() 循环直到返回 TRUE 并且 dwNumberOfBytesRead 为 0。

From MSDN
InternetOpenUrl Function: The InternetOpenUrl function parses the URL string, establishes a connection to the server, and prepares to download the data identified by the URL. The application can then use InternetReadFile [...] to retrieve the URL data.

InternetReadFile Function: To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero.

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

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

这让超时问题变得棘手。如果下载超过超时(看起来默认为 30 秒),InternetOpenUrl() 将失败。

所以我有两个问题:

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

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

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

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

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

在慢速连接或大文件的情况下,可以想象在整个下载完成之前可以对数据做很多工作。在 HTTP 的经典 Berkley 套接字重新实现中,循环调用 recv() 会在数据下降时为我提供数据,这正是我最终需要的。

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

最佳答案

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

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

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

我关闭了“Kaspersky Lab Network Agent”,嘿,很快,InternetOpenUrl 在开始下载 HTTP 响应后大约 2 秒返回。我宁愿立即下载,但 75 秒下载中的一两秒至少让 WinINET 有时间处理 header 并进行可能需要的任何预处理。

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

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

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

关于c++ - InternetOpenUrl 仅在下载整个 HTTP 响应后返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5771636/

有关c++ - InternetOpenUrl 仅在下载整个 HTTP 响应后返回的更多相关文章

  1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  4. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  5. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  6. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  9. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  10. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

随机推荐