Visualizzazione dei risultati da 1 a 3 su 3
  1. #1

    [DELPHI] Download HTTP asincrono.

    Sto creando un componente per scaricare da internet una lista di files in simultanua. Per fare questo mi avvalgo di una serie di Threads (8 per la precisione). All'intereno della procedura Exceute dei Threads ho scritto del codice per permettere il download dei file.
    La parte del codice incaricata del download è stata ripresa da un piccolo componente liberamente scaricabile da qui (si chiama TMHttpGetResume), in sostanza si fa uso di WinINET per scaricare i files.
    Ora il problema è che in TMHttpGetResume il download non avviene in maniera asincrona e quindi quando faccio partire i miei Threads la mia applicazione si congela fin tanto che il download non è terminato.
    Ho fatto qualche ricerca ma non riesco a capire come usare WinINET in maniera asincrona per scaricare files attraverso il protocollo HTTP. Esiste infatti la costante INTERNET_FLAG_ASYNC ma questa pare funzionare solo per il protocollo FTP.
    Qualcuno mi può aiutare, sono disposto a cambiare anche tutta la parte relativa al download se necessario l'importante è che non mi facciate usare componenti quali INDY o simili, ovvero appartenti ad una suite (devo creare un componente autonomo).

    GRAZIE.

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Penso che il problema sia riconducibile ad una codifica errata dei tuoi thread: che la libreria, la funzione o il metodo utilizzato sia sincrono o asincrono, se ne fai uso in un thread secondario - quindi slegato dal thread primario dell'applicazione - ma il tuo programma si blocca, significa che da qualche parte hai inserito una sincronizzazione, un'attesa o un accesso ad una risorsa condivisa con il thread tale per cui il thread primario si blocca, contrariamente a quanto voluto.

    Fai qualche verifica in merito a questa casistica.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  3. #3
    Intanto grazie per la risposta. A seuito del tuo messaggio mi sono messo a semplificare di molto il mio componente la il risultato è sempre lo stesso.

    Vi posto la parte di codice dove credo risieda il problema nella speranza che mi possiate aiutare (non ho mai fatto uso di threads prima d'ora).

    Dunque nel mio componente credo una serie di Threads che iniziamente sono "sospesi" e ne setto 2 variabili contententi la lista dei URL e dei file su disco da salvare:

    procedure TMioComponente.StartDownload();
    var error, I: Integer;
    begin
    if Assigned(fStartDownload) then
    fStartDownload(Self);

    for i := 1 to fThreads do
    begin
    ThreadList[i] := TMDThread.create(self);
    ThreadList[i].fUrlsList := fUrlsList;
    ThreadList[i].fFilesList := fFilesList;
    end;

    ...

    for i := 1 to fThreads do
    begin

    ThreadList[i].Execute;
    end;

    if Assigned(fEndDownload) then
    fEndDownload(Self);
    end;


    Ora posto invece il codice relativo al thread:


    constructor TMDThread.Create(AOwner: TMapDownloader);
    begin
    inherited Create(True);
    fOwner := AOwner;
    fUrlsList := TStringList.Create;
    fFilesList := TStringList.Create;
    fLog := TStringList.Create;
    fUserAgent := AOwner.fUserAgent;
    FreeOnTerminate := True;
    end;

    procedure TMDThread.Execute;
    var
    RBSIZE:dword;
    httpstatus,httpsize,err:integer;
    dwIdx:dword;
    dwBufSize:dword;
    ms:TFileStream ;
    len:dword;
    cbuf:array[0..255] of char;
    rb:array[0..4095] of byte;
    fISession:hinternet;
    fIHttp:hinternet;
    cancel:boolean;

    const
    FileOpenModes: array[Boolean] of DWORD = (fmCreate, fmOpenWrite);

    begin
    while fUrlsList.Count > 0 do
    begin
    fISession := InternetOpen(PChar(fUserAgent),INTERNET_OPEN_TYPE_ PRECONFIG,nil,nil,0);
    Beep;

    if not (fISession = nil) then
    begin
    fIHttp := InternetOpenURL(fISession,pchar(fUrlsList[0]),nil,0,
    INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_RELOAD,0);

    if not (fIHttp = nil) then
    begin
    dwBufSize := SizeOf(cbuf);
    dwidx:=0;
    HttpQueryInfo(fIHttp,HTTP_QUERY_STATUS_CODE,@cbuf, dwBufSize,dwIdx);

    val(cbuf,httpstatus,err);

    if not((httpstatus <> 200) or (err <> 0)) then
    begin
    dwBufSize:=sizeof(cbuf);
    dwidx:=0;
    HttpQueryInfo(fIHttp,HTTP_QUERY_CONTENT_TYPE,@cbuf ,dwBufSize,dwIdx);

    if (pos('IMAGE',uppercase(strpas(cbuf)))=0) then
    begin
    dwBufSize := SizeOf(cbuf);
    dwidx := 0;
    HttpQueryInfo(fIHttp,HTTP_QUERY_CONTENT_LENGTH,@cb uf,dwBufSize,dwIdx);

    Val(cbuf,httpsize,err);

    if not((httpsize = 0) or (err <> 0)) then
    begin
    len := 4096;
    RBSIZE := 4096;

    ms := TFileStream.Create(fFilesList[0], FileOpenModes[FileExists(fFilesList[0])]);

    Cancel := False;

    while (len > 0) and not Cancel do
    begin
    InternetReadFile(fIHttp,@rb,RBSIZE,len);
    if len > 0 then
    ms.WriteBuffer(rb,len);
    end;

    ms.Free;

    InternetCloseHandle(fIHttp);
    InternetCloseHandle(fISession);
    end
    else
    begin
    InternetCloseHandle(fISession);
    InternetCloseHandle(fIHttp);
    fLog.Add('Image size is 0');
    end;
    end
    else
    begin
    InternetCloseHandle(fISession);
    InternetCloseHandle(fIHttp);
    fLog.Add('Resource is not of image type');
    end;
    end
    else
    begin
    InternetCloseHandle(fISession);
    InternetCloseHandle(fIHttp);
    fLog.Add('Cannot open URL');
    end;
    end
    else
    begin
    InternetCloseHandle(fISession);
    fLog.Add('Cannot open http connection');
    end;
    end
    else
    begin
    fLog.Add('Cannot open internet session');
    end;

    fUrlsList.Delete(0);
    FFilesList.Delete(0);
    end;
    end;


    Il risultato che che vengono creati un numero giusto di threads ma solo il primo viene eseguito e blocca tutta l'applicazione.

    Mi potete dare una mano.

    Altri 2 chgiamenti:
    1) c'è modo di passare informazioni la mia applicazione e i threads che crea senza che l'applicazione si blocchi (vorrei passare il contenuto della variabile fLog prima che il thread venga distrutto.).
    2) dalla mia applicazione c'è modo di interrompere l'esecuzione dei threads (come se volessi annullare il download)?

    GRAZIE.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.