Connection does not disconnect while downloading a file from the Internet

In connection with my record ( How to get a file from the Internet via HTTP? ) About how to easily and safely download a file from the Internet, I found a possible solution - however, it does not work the way it should work.

According to MS documentation, the code below is designed to time out 500 ms after I disconnect from the Internet. However, it looks like it completely ignores the setting of "INTERNET_OPTION_RECEIVE_TIMEOUT". Application freezes at boot time. This feature requires about 20-30 to understand that the Internet connection is disconnected and return control to the GUI.

Does anyone know why?

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; 

Here is the documentation:

 { 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. } 

Edit: I will disconnect the Internet by disconnecting the cable or (for wireless) from the software AFTER the download application starts (I chose to download a large file). It mimics a website going offline.

+3
delphi
source share
4 answers

MS IE code has a documented error. It can only be solved using code in the stream and re-implementing the timeout mechanism.

Details:

"This article shows a workaround for the InternetSetOption API error when setting timeout values ​​by creating a second stream. InternetSetOption does not set a timeout value"

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

Perhaps someone can help implement this bug fix in Delphi as well. I personally have no experience with C. Even a spine in a pseudo-pascal will be enjoyable.

+3
source share

The connection timeout is obviously not applicable in your test, because by the time your test starts (i.e. pull out the plug), the connection is already established. Indeed, the connection is already established before you even get close to setting the timeout parameter.

Reception timeout validity is also suspicious because you have already begun to receive a response.

The most promising timeout is the shutdown timeout, but MSDN says it has not yet been implemented.

It seems to me that the way is to use asynchronous operations. Use InternetReadFileEx and use the irf_Async and irf_No_Wait . If too much time passes without receiving any data, close the connection. Another option is to stick to your synchronous calls, but then call InternetCloseHandle from another thread if the download takes too long.

+5
source share

IMO, you have to run this in a thread. Threading should not mean a loop - it can be a one-and-all thread. Run it this way and your GUI will remain responsive until the thread completes. I understand that this does not really answer your question, but it will make your code better.

Also, if you turn off the Internet during the first cycle, where you check the data, I think it will repeat 10 times. You should detect and then exit immediately.

Finally, I don’t think you should use EXIT when you have pens and stuff. Take a break instead, so that you still go through the disconnects. I would expect your code to bind a socket. I saw this recently during code verification, when there was EXIT, and BREAK caused a memory leak because the objects were created and were never freed. I would use the same rule here.

0
source share

Are you sure you are not using INTERNET_OPTION_CONNECT_TIMEOUT? First he will try to connect, and then he will receive.

To check the connection timeout, it must allow, but never connect. To check the read timeout, it should connect, but never receive any data.

Usually I set the connection timeout to 10 seconds and the read timeout to 30 seconds. Anything else before that, I still think.

0
source share

All Articles