从互联网下载文件时连接不会超时 [英] The connection does not timeout while downloading file from internet

查看:38
本文介绍了从互联网下载文件时连接不会超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与我的一个帖子有关( 如何检索通过 HTTP 从 Internet 下载文件?)关于如何轻松、可靠地从 Internet 下载文件,我找到了一个可能的解决方案 - 但是没有按预期工作.

Related to a post of mine ( How to retrieve a file from Internet via HTTP? ) about how to easily and robustly download a file from Internet, I have found a possible solution - however is not working as it was supposed to work.

根据 MS 文档,在我断开互联网连接后,下面的代码应该在 500 毫秒后超时.但是,它似乎完全忽略了INTERNET_OPTION_RECEIVE_TIMEOUT"设置.应用程序在下载过程中冻结.此函数需要大约 20-30 分钟才能意识到 Internet 连接已断开并将控制权交还给 GUI.

According to MS documentation, the code below is supposed to time-out at 500ms after I disconnect myself from internet. However, it looks like it totally ignores the 'INTERNET_OPTION_RECEIVE_TIMEOUT' setting. The application freezes during download. It takes about 20-30 to this function to realize that there the Internet connection is down and to give the control back to the GUI.

有人知道为什么吗?

function GetBinFileHTTP (const aUrl: string; const pStream: TStream; wTimeOut: Word= 500; wSleep: Word= 500; wAttempts: Word= 10): Integer;
CONST
  BufferSize = 1024;
VAR
  hSession, hService: HINTERNET;
  Buffer     : array[0..BufferSize-1] of Char;
  dwBytesRead, dwBytesAvail: DWORD;
  lSucc        : LongBool;
  lRetries, dwTimeOut: Integer;   
begin
 Result:= 0;
 if NOT IsConnectedToInternet then
  begin
   Result:= -1;
   EXIT;
  end;

 hSession := InternetOpen(PChar(ExtractFileName(Application.ExeName)), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);  { The INTERNET_OPEN_TYPE_PRECONFIG flag specifies that if the user has configured Internet Explorer to use a proxy server, WinInet will use it as well. }
 if NOT Assigned(hSession) then
  begin
   Result:= -4;
   EXIT;
  end;

 TRY
   hService := InternetOpenUrl(hSession, PChar(aUrl), nil, 0, INTERNET_FLAG_RELOAD, 0);
   if NOT Assigned(hService) then Exit;
   TRY
     FillChar(Buffer, SizeOf(Buffer), 0);

     { Set time out }
     dwTimeOut:= wTimeOut;
     InternetSetOption(hService, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeOut, SizeOf(dwTimeOut));   { use INTERNET_FLAG_RELOAD instead of NIL to redownload the file instead of using the cache }


     InternetSetOption(hService, INTERNET_OPTION_CONNECT_TIMEOUT, @dwTimeOut, SizeOf(dwTimeOut));

     REPEAT
       lRetries := 0;

       REPEAT
         lSucc:= InternetQueryDataAvailable( hService, dwBytesAvail, 0, 0);
         if NOT lSucc
         then Sleep( wSleep );
         if lRetries > wAttempts
         then Result:= -2;
       UNTIL lSucc OR (Result= -2);

       if NOT InternetReadFile(hService, @Buffer, BufferSize, dwBytesRead) then
        begin
          Result:= -3;                                                          { Error: File not found/File cannot be downloaded }
          EXIT;
        end;

       if dwBytesRead = 0
       then Break;

       pStream.WriteBuffer(Buffer[0], dwBytesRead);

     UNTIL False;
   FINALLY
     InternetCloseHandle(hService);
   end;
 FINALLY
   InternetCloseHandle(hSession);
 end;

 Result:= 1;
end;

这里是文档:

{

INTERNET_OPTION_CONNECT_TIMEOUT         Sets or retrieves an unsigned long integer value that contains the time-out value to use for Internet connection requests. If a connection request takes longer than this time-out value, the request is canceled. When attempting to connect to multiple IP addresses for a single host (a multihome host), the timeout limit is cumulative for all of the IP addresses. This option can be used on any HINTERNET handle, including a NULL handle. It is used by InternetQueryOption  and InternetSetOption.
INTERNET_OPTION_RECEIVE_TIMEOUT         Sets or retrieves an unsigned long integer value that contains the time-out value to receive a response to a request.      If the response takes longer than this time-out value, the request is canceled. This option can be used on any HINTERNET handle, including a NULL handle. It is used by InternetQueryOption and InternetSetOption. For using WinInet synchronously, only the default value for this flag can be changed by calling InternetSetOption and passing NULL in the hInternet parameter.
                  INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT - Identical to INTERNET_OPTION_RECEIVE_TIMEOUT. This is used by InternetQueryOption and InternetSetOption.
}

在应用程序开始下载(我选择下载大文件)后,我通过从软件中拔下电缆或(对于无线)来断开 Internet 连接.模拟网站下线.

I disconnect the Internet by unplugging the cable or (for wireless) from software AFTER the application starts the download (I chose to download large file). It simulates the web site going offline.

推荐答案

MS IE 代码中有一个已记录的错误.只能通过在线程中使用代码并重新实现超时机制来解决.

There is a documented bug in MS IE code. Can only be solved by using the code in a thread and re-implementing the time out mechanism.

详情:

这篇文章展示了通过创建第二个线程来设置超时值的 InternetSetOption API 错误的解决方法.InternetSetOption 不设置超时值"

"This acticle shows a workaround to the InternetSetOption API bug on setting timeout values by creating a second thread. InternetSetOption Does Not Set Timeout Values"

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q224318
(链接被报告损坏.怪 MS 而不是我)

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q224318
(Link was reported broken. Blame MS not me)

也许有人可以帮助在 Delphi 中实现此错误修复.我个人没有使用 C 的经验.即使是伪 Pascal 的主干也会很好.

Maybe somebody can help with implementing this bug fix also in Delphi. I personally don't have experience with C. Even the backbone in pseudo-Pascal will be nice.

这篇关于从互联网下载文件时连接不会超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆