Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi urlDownloadToFile hängt sich bei IP-Wechsel auf (https://www.delphipraxis.net/127458-urldownloadtofile-haengt-sich-bei-ip-wechsel-auf.html)

Mendelsohn 13. Jan 2009 18:13


urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Hallo,

da ich hier nicht mehr weiterkomme, wende ich mich einmal an das Forum:
Ich möchte mit urlDownloadToFile Dateien herunterladen, allerdings hängt sich die Routine auf, sobald die Verbindung abbricht (z.B. weil gerade routinemäßig die dynamische IP vom Provider gewechselt wird). Aus Gründen der Benutzerfreundlichkeit habe ich den Download schon einmal in einen eigenen Thread ausgelagert.

Mit folgenden Ansätzen gab es bis jetzt leider kein weiterkommen:

Der Download kann nicht abgebrochen werden, weil dies über den Rückgabewert der Methode .OnProgress geschehen muss, die ab und an von urlDownloadToFile aufgerufen wird. Sobald die Verbindung aber abbricht, wird die Methode auch nicht mehr aufgerufen, sodass ein normaler Abbruch nicht mehr möglich ist.

Den Download-Thread ordnungsgemäß mit Thread.Terminate; Thread.Free; zu beenden funktioniert auch nicht, so sich ja urlDownloadToFile und damit auch der Thread aufgehängt hat.

Es bleibt nur noch den Thread gewaltsam mit TerminateThread (Thread.Handle,Thread.ThreadID); ThreadFree; abzuwürgen, da aber nicht alles ordnungsgemäß beendet wird, funktioniert ein erneuter Downloadversuch mit urlDownloadToFile danach nicht mehr richtig. Wie ich inzwischen herausgefunden habe, liegt dies daran, dass nach dem "Abschuss" des Download-Threads auf die halbfertige Datei auf der Festplatte immer noch zugegriffen wird. Bei einem erneuten Download-Versuch müsste die Datei dann also unter einem anderen Namen gespeichert und die halbfertige Dateileiche liegengelassen werden, was aber sehr unsauber wäre. :(


Grüße,

Mendelsohn

Sir Rufo 13. Jan 2009 18:20

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Nimm doch mal ...
Delphi-Quellcode:
try
  UrlDownloadToFile( ... );
except
end;
denn bei einer exception hört der Code einfach auf zu laufen, und bei einem Thread bekommt man da nix mit ;)

Leider kein Code dabei, also auch keine weitere Hilfestellung möglich

cu

Oliver

Luckie 13. Jan 2009 18:33

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Also API -Funktiinen werfen in der Regel keine Exceptions. Ein try-except-Block wird da also nicht viel helfen.

toms 13. Jan 2009 18:40

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Zitat:

Zitat von Luckie
Also API -Funktiinen werfen in der Regel keine Exceptions. Ein try-except-Block wird da also nicht viel helfen.

Try...Except funktioniert da IMO schon. Auch dürfte GetLastError() einen Fehlercode zurückliefern.

SirThornberry 13. Jan 2009 18:43

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Funktionieren sollte es schon allerdings wird niemals in den Except-Zweig gesprungen weil die Api-Funktionen in aller Regel über Rückgabewert + GetLastError ihre Fehler kommunizieren und nicht über das Auslösen von Exceptions. :)

Sir Rufo 13. Jan 2009 18:48

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Da wir auch nicht wissen, was er sonst noch im Thread ausführt, hilft wohl nur noch die Kristallkugel

Mendelsohn 13. Jan 2009 18:53

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Richtig, es wird leider keine Exception geworfen.

Die gewüschnte Beispiel-Implementierung wäre:

Delphi-Quellcode:
uses classes,urlmon,Dialogs;

type
  TThreadDownload = class (TThread)
  protected
      fileURL,filePath : string;
      procedure Execute; override;
      procedure info;
  public
      downloadSuccess : integer;
      constructor create (url,path : string; suspended : boolean);
      procedure FreeInstance; override;
  end;

implementation

constructor TThreadDownload.create (url,path: string; suspended : boolean);
begin
    inherited create (suspended);

    fileURL := url;
    filePath := path;
end;

procedure TThreadDownload.Execute;
begin
    // Download starten und Ergebnis notieren
    downloadSuccess := urlDownloadToFile (nil,pchar (fileURL),pchar (filePath),0,nil);
end;

procedure TThreadDownload.info;
begin
    showmessage ('Free!');
end;

procedure TThreadDownload.FreeInstance;
begin
    inherited FreeInstance;

    synchronize (info);
end;
für den Download-Thread und

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
//
// Download-Thread starten
//
begin
    Thread1 := TThreadDownload.create ('http://upload.wikimedia.org/wikipedia/en/d/d4/Delphi_Composite.jpg','c:\delphi1.jpg',false);

    Thread1.FreeOnTerminate := true;
end;

procedure TForm1.Button2Click(Sender: TObject);
//
// Kill
//
begin
    // Download-Thread über die WinAPI abschießen
    Thread1.Suspend;
    TerminateThread (Thread1.Handle,Thread1.ThreadID);
    Thread1.Free;
end;
als Test-Beispiel.

Sir Rufo 13. Jan 2009 18:58

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Eine Exception, die in einem Thread auftaucht, wirst du auch nicht zu Gesicht bekommen, was nicht heisst, dass es sie dort nicht gibt ;)

Wenn du das reproduzieren kannst, dann setz doch einfach mal das try ... except um den downloadbefehl, denn ausser dem würde mir da nichts weiter auffallen.

cu

Oliver

Mendelsohn 13. Jan 2009 19:01

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Habe ich natürlich auch schon versucht, aber urlDownloadToFile wirft keine Exceptions, sondern reagiert bei Verbindungsabbruch einfach nicht mehr (bzw. ruft .onProgress nicht mehr auf, wenn man ein IBindStatusCallback-Objekt eingebunden hat, um damit mit urlDownloadToFile zu kommunizieren, sodass man den Download auch nicht mit E_ABORT regulär abbrechen könnte).

Sir Rufo 13. Jan 2009 19:10

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
ok, weil ich hätte dir sonst den link mal ans herz gelegt
http://www.delphipraxis.net/internal...downloadtofile

Mendelsohn 13. Jan 2009 19:23

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Wie gesagt, ohne das onProgress aufgerufen wird, funktioniert auch kein E_ABORT mehr.

Gibt es eine Möglichkeit die Datei nach dem Abschuss des Download-Threads von den Resten des Zugriffs von urlDownloadToFile zu befreien, sodass es möglich ist, die Dateileiche zu löschen und den Download danach mit demselben Dateinamen zu wiederholen?

Mendelsohn 21. Jan 2009 14:05

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Nun ich habe das Problem inzwischen dadurch "gelöst", indem ich statt dem verbuggeten Microsoft/Borland urlDownloadToFile bzw. TDownLoadURL Zeug mir eine neue Thread-Download Klasse auf Basis der Indys geschrieben haben, die mit HTTP get arbeitet. Also falls jemand mal ein ähnliches Problem hat, versucht es damit:

Delphi-Quellcode:
unit ThreadDownload;

interface

uses classes, IdHTTP;

type
  TThreadDownload = class (TThread)
  protected
      totalSize : cardinal;
      fileURL : string;
      statusMessage : string;
      HTTP : TIdHTTP;
      Content : TFilestream;
      procedure Execute; override;
  public
      isDownloading : boolean;
      constructor create (url,path : string);
      procedure cancel;
      function getActualSize : cardinal;
      function getTotalSize : cardinal;
      function getStatusMessage : string;
      function getDownloadSuccess : boolean;
      procedure FreeInstance; override;
  end;

implementation

constructor TThreadDownload.create (url,path: string);
//
// Object Initialization
//
begin
    // signalize the download-thread is running
    isDownloading := true;

    fileURL := url;

    Content := TFilestream.Create (path,fmcreate);
    HTTP := TIdHTTP.Create;

    inherited create (false);
end;

procedure TThreadDownload.Execute;
//
// Thread
//
begin
    statusMessage := 'Verbinde';

    // get filesize
    HTTP.Head (fileURL);
    totalSize := HTTP.Response.ContentLength;

    statusMessage := 'Download gestartet';

    HTTP.Get (fileURL,Content);

    statusMessage := 'Download beendet';

    // signalize the download-thread was stopped
    isDownloading := false;
end;

procedure TThreadDownload.cancel;
//
// cancels the download
//
begin
    HTTP.Disconnect;

    statusMessage := 'Download abgebrochen';

    // signalize the download-thread was stopped
    isDownloading := false;
end;

function TThreadDownload.getActualSize : cardinal;
//
// returns the number of bytes already downloaded
//
begin
    result := Content.Position;
end;

function TThreadDownload.getTotalSize : cardinal;
//
// returns the file's size in byte
//
begin
    result := totalSize;
end;

function TThreadDownload.getStatusMessage : string;
//
// returns the actual status-message
//
begin
    result := statusMessage;
end;

function TThreadDownload.getDownloadSuccess : boolean;
//
// is true if the file was completely downloaded
//
begin
    if (Content.Position = totalSize) then result := true
    else result := false;  
end;

procedure TThreadDownload.FreeInstance;
//
// Garbage Collection
//
begin
    Content.Free;
    HTTP.Free;

    inherited FreeInstance;
end;

end.
Ein Implementations-Beispiel wäre:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
//
// downlad [url]http://upload.wikimedia.org/wikipedia/en/d/d4/Delphi_Composite.jpg[/url]
//
var url,path : string;
begin
    url := 'http://upload.wikimedia.org/wikipedia/en/d/d4/Delphi_Composite.jpg';
    path := 'c:\Delphi.jpg';

    DownloadThread := TThreadDownload.create (url,path);
    DownloadThread.FreeOnTerminate := false;

    while (DownloadThread.isDownloading) do
    begin
        sleep (100);
        Application.ProcessMessages;
    end;

    showmessage ('Done!');

    DownloadThread.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
//
// cancel download
//
begin
    DownloadThread.cancel;
end;
Das cancel hier macht keine Zicken und der Thread lässt sich danach auch anstandslos beenden und die Dateileiche wird freigegeben. Mithilfe von getActualSize und getTotalSize kann man sich die aktuelle Geschwindigkeit berechnen und so im Falle eines Verbindungsabbruchs, IP-Wechsels, ect. wenn die Geschwindigkeit eine gewisse Zeig lang bei 0 lag, den Download dann automatisch abbrechen und wiederholen.

Luckie 21. Jan 2009 14:10

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Was ist das:
Delphi-Quellcode:
while (DownloadThread.isDownloading) do
    begin
        sleep (100);
        Application.ProcessMessages;
    end;
Warum löst dein Thread kein Ereignis aus, wenn er fertig ist und warum löst er kein Fortschrittsereignis aus?

Mendelsohn 21. Jan 2009 14:17

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Zitat:

Zitat von Luckie
Warum löst dein Thread kein Ereignis aus, wenn er fertig ist und warum löst er kein Fortschrittsereignis aus?

Die Fortschrittsanzeige realisiere ich über einen Timer der eine Progressbar auf Basis von getActualSize und getTotalSize aktualisiert. Was meinst du mit Ereignis? Einen Rückgabewert?

Das

Delphi-Quellcode:
while (DownloadThread.isDownloading) do
begin
    sleep (100);
    Application.ProcessMessages;
end;
ist dazu da, die Programmausführung zu unterbrechen bis der Thread die Datei fertig heruntergeladen hat, ohne die Benutzeroberfläche von Form1 einzufrieren.

Luckie 21. Jan 2009 14:51

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Zitat:

Zitat von Mendelsohn
Die Fortschrittsanzeige realisiere ich über einen Timer der eine Progressbar auf Basis von getActualSize und getTotalSize aktualisiert.

Das wird ja immer grausamer. Erst langerst du alles in einen Thread aus und dann brauchst du doch noch Application.Processmessages und einen Timer.

Zitat:

Was meinst du mit Ereignis?
Nein, ich meine ein Ereignis und kein Rückgabewert.

Zitat:

Das

Delphi-Quellcode:
while (DownloadThread.isDownloading) do
begin
    sleep (100);
    Application.ProcessMessages;
end;
ist dazu da, die Programmausführung zu unterbrechen bis der Thread die Datei fertig heruntergeladen hat, ohne die Benutzeroberfläche von Form1 einzufrieren.
Ähm, ich bin mir sehr wohl bewußt, was der Code macht. Aber genau deswegen habe ich gefargt, was diese Zeilen da zu suchen haben. Die Thread-Klasse der VCL kennt ein Ereignis, wenn der Thread beendet ist.

Ich glaube, du solltest dich mal mit der objektorientierten Programmierung auseinandersetzen.

Mendelsohn 21. Jan 2009 15:31

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
Zitat:

Zitat von Luckie
Ähm, ich bin mir sehr wohl bewußt, was der Code macht. Aber genau deswegen habe ich gefargt, was diese Zeilen da zu suchen haben. Die Thread-Klasse der VCL kennt ein Ereignis, wenn der Thread beendet ist.

Ich glaube, du solltest dich mal mit der objektorientierten Programmierung auseinandersetzen.

Ja, ich hätte DownloadThread.OnTerminate := zeigeMeldung; für dieses kleine Beispiel daraus machen können.
Aber in dem eigentlichen Programm, in dem ich diese Thread-Klasse einsetze, gibt es kein simples showmessage, sondern es sollen in einer Schleife mehrere Dinge, unter anderem ein paar Downloads, nacheinander abgearbeitet werden. Wenn ich statt einfach zu warten bis der Download fertig ist, das onTerminate-Ereignis verwende, dann müsste ich die ganze Schleife auseinander nehmen und in zwei Teile (bis TThreadDownload.create und dann wieder ab der Methode die OnTerminate zugewiesen ist) spalten.

paperboy 24. Jun 2009 01:24

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
hallo zusammen...

ich bin auch auf eine ähnliches problem gestossen wie das das Mendelsohn hatte und zwar das nach einem abbruch meines Threads
über TerminateThread die datei die mittels TDownloadURL gerade geladen wurde nicht gelöscht werden kann da wenn ich den thread beende
die onProgress prozedur noch läuft... Free funktioniert an keiner stelle (ausser der DL ist beendet)...
gibts denn wirklich keinen weg die dateileiche irgendwie frei zu bekommen?! ich weis ich könnte jetzt auch seine lösung versuchen
oder das programm einfach mit parametern restarten und das file dann löschen aber ich wollte bevor ich zu diesen mitteln greife noch
mal sicherheitshalber fragen ob sich da nicht doch etwas vor mir verbirgt :wink:

lg paperboy

himitsu 24. Jun 2009 09:03

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
in dem Thread wird die Datei ja geöffnet und wenn du den Thread hart beendest, dann gibt er diese Datei nicht mehr frei, das passiert nur, wenn der gesamte Prozess beendet wird (dann macht es Windows für dich).

paperboy 24. Jun 2009 09:25

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
hey himitsu,

danke erstmal für die antwort...
in bezug zu meinem anderen thread gibt es also keine "einfache" möglichkeit diese windwos funktion zu emulieren so
das ich mein prog nicht erst abschiessen muss? oder gibt es vllt auch eine möglichkeit die datei freizubekommen bevor ich meinen thread
abschiesse ohne warten zu müssen das der DL fertig wird? wie gesagt er steckt ja beim beenden grad in der OnDownlaodProgress prozedur...

lg paperboy

himitsu 24. Jun 2009 09:31

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
wenn es im eigenem Prozess ist, dann gäre es zwar eine "Möglichkeit"

MSDN-Library durchsuchenGetFileInformationByHandle

Allerdings müßtest du damit alle möglichen Handles einzeln prüfen (auch jene, welche grad nicht in Benutzung sind, da es halt keine "leicht" zugängliche und einheitliche Liste mit allen Handle gibt)
und schauen, ob das Handle zur Datei gehört.
Dazu kommt noch, daß diese Funktion nicht immer funktioniert und unter verschiedenen Umständen keine Informationen liefert
und selbst wenn Infos ausgelesen können, kann es sein, daß das Format des Dateinamens nicht einfach zu interpretieren ist.

paperboy 24. Jun 2009 09:38

Re: urlDownloadToFile hängt sich bei IP-Wechsel auf
 
ok... vielen dank nochmal himitsu...
ich werd dann wohl darauf zurückgreifen mein programm mit einem parameter neu zu starten der dafür sorgt das
die datei beim wiederausführen gelöscht wird... ist zwar irgendwie unschön in meinen augen aber eine
methode zu verwenden dessen erfolg nicht immer garantiert ist ist natürlich noch unschöner :)

lg paperboy


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz