Autor Beitrag
idefix123456
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Mi 13.04.11 19:09 
Hallo,

Nach stundenlangem Suchen und ausprobieren, frage ich hier einfach mal nach. Ich habe die untere Funktion. Damit rufe ich eine URL im Hintergrund auf. Als Result wird mir dann der JSON übergabe wert als String zurückgeliefert. Ziel ist es von Delphi aus Daten über die URL an das php script auf meinen Server zu schicken, dieser wertet das ganze aus, und schickt einen json string an Delphi zurück. Soweit funktioniert das Ganze auch super! Vorausgesetzt es besteht eine Internet Verbindung!

Und da liegt mein Problem. Wenn keine Verbindung besteht, dann Versucht die funktion quasi in einer Endlosschleife die URL zwanghaft doch zu öffnen, was ja nicht geht, und deswegen hängt sich immer die komplette Form auf wodurch ich das Programm beenden muss!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
  function LoadURL(url: string): string;
    var
      HttpLoader: TIdHttp;
  begin
    HttpLoader := TIdHttp.Create;
    try
      result := HttpLoader.Get(url);
    finally
      HttpLoader.Free;
    end;
  end;




Jetzt versuche ich seit Stunden einen Timeout mit in der funktion einzubauen. Also das die funktion 3 sekunden lang versuchen kann die URL zu öffnen, wenn das nicht gelingt wird die funktion abgebrochen, und false zurückgeliefert!


Habe schon:

Idhttp1.ReadTimeout := 3000;
Idhttp1.ConnectTimeout := 3000;

ausprobiert, das funktioniert aber nicht, da dennoch nicht abgebrochen wird.



Wer kann helfen?
Danke
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 13.04.11 19:54 
Da Indy mit blocking sockets arbeitet, wird das nicht so gehen. Das ist aber ohnehin wenig sinnvoll so, da du deinen Hauptthread so blockierst.

Lagere das ganze am besten in einen Thread aus. Dafür erzeuge dir zuerst mit CreateEvent ein Ereignis. Dieses gibst du dann zusammen mit der Adresse an den Thread weiter. Danach wartest du mit MsgWaitForMultipleObjects (mit QS_ALLINPUT) auf dein Ereignis (ohne Timeout, damit nichts blockiert) und wartest bis du entweder ein Ergebnis bekommst oder die 3 Sekunden herum sind. In der Schleife kannst du Application.ProcessMessages aufrufen.

Im Thread wiederum hast du diesen Quelltext. Wenn du die Seite erfolgreich abrufen konntest, speicherst du das Ergebnis in einer public Eigenschaft des Threads und löst dann mit SetEvent das Ereignis aus.

Außerhalb des Threads bekommst du jetzt von MsgWaitForMultipleObjects gemeldet, dass das Ereignis ausgelöst wurde und du kannst das Ergebnis aus der Eigenschaft des Threads lesen.

Auf diese Weise kannst du ohne deine GUI zu blockieren warten. Du kannst natürlich auch gar nicht warten und auf das Signal aus dem Thread warten, dass er fertig ist, aber das würde die Bestimmung des Timeouts schwieriger machen, es sei denn der Thread verschluckt das Ergebnis einfach nach dem Ende des Timeouts. Ganz wie du möchtest. ;-)
Thom
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 70
Erhaltene Danke: 5


Delphi 10 Seattle Prof.
BeitragVerfasst: Mi 13.04.11 20:23 
Vielleicht hilft das weiter.
idefix123456 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 23



BeitragVerfasst: Do 14.04.11 15:09 
Hi,

Danke für die Antworten...

Da ich noch nicht so richtig mit Threads gearbeitet habe, hab ich mich mal ein wenig bei google drüber schlau gemacht und folgenden code zusammengeschustert (ungetestet)

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
var
  GlobalURL: string;



procedure OpenURLResult(json: string);
begin

  ShowMessage(json);

end;
  


procedure OpenURLThread();

  function LoadURL(url: string): string;
    var
      HttpLoader: TIdHttp;
  begin
    HttpLoader := TIdHttp.Create;
    try
      result := HttpLoader.Get(url);
    finally
      HttpLoader.Free;
    end;
  end;
  
  var
    json: string;
begin

  json := LoadURL(GlobalURL);
  OpenURLResult(json);

end;



procedure OpenURL(url: string);
  var
    ThreadID: DWORD;
begin
  GlobalURL := url;
  CreateThread(nil0, TFNThreadStartRoutine(@OpenURLThread), nil0, ThreadID);
end;




Wenn ich jetzt OpenURL('http://www.google.de') ausführe, sollte eingentlich ein einem neuen Thread das ganze gestartet werden, und wenn eine Verbindung hergestellt ist, sollte die procedure OpenURLResult ausgeführt werden.

Jetzt habe ich noch 2 fragen, und zwar wenn das ganze nun in einem Nebenthread anstatt in dem Haupttread gestartet wird und es besteht Keine Verbindung zum Internet, dann müsste sich aber doch der Nebenthread dennoch aufhängen anstatt wie zuvor die Komplette Form (da ja trotzdem kein Abbruch nach 3 skeunden). Das sich der Thread Aufhängt sollte doch eigentlich egal sein, aber Verbraucht das dann nicht doch dennoch Resourcen???

Außerdem könntest du das mit dem MsgWaitForMultipleObjects und das "speicherst du das Ergebnis in einer public Eigenschaft des Threads und löst dann mit SetEvent das Ereignis aus" nochmal etwas genauer erklären!


Danke
haentschman
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 285
Erhaltene Danke: 33


DX10 Berlin Professional
BeitragVerfasst: Do 14.04.11 21:45 
Hallo...

da du noch nie mit Threads gearbeitet hast empfehle ich dir TThread. Dieses ist etwas leichter zu verstehen als der direkte Weg über die API. Suche mal hier im Forum danach.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 15.04.11 06:16 
user profile iconidefix123456 hat folgendes geschrieben Zum zitierten Posting springen:
Außerdem könntest du das mit dem MsgWaitForMultipleObjects und das "speicherst du das Ergebnis in einer public Eigenschaft des Threads und löst dann mit SetEvent das Ereignis aus" nochmal etwas genauer erklären!
Ganz kurz als Gerüst, weil ich bald zur Arbeit los muss:
Im Hauptthread:
ausblenden Delphi-Quelltext
1:
2:
3:
MyEvent := CreateEvent(nil, True, False, nil);
MyThread := TUrlLoadThread.Create(MyUrl, MyEvent);
Wait...


Im Thread:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
property LoadResult: string read FLoadResult;

constructor Create(const AUrl: string; AMyEvent: THandle);
begin
  FMyUrl := AMyUrl;
  FMyEvent := AMyEvent;
  inherited Create(False);
end;

procedure Execute;
begin
  // ladeversuch
  ...
  // erfolgreich:
  FLoadResult := ...
  SetEvent(FMyEvent);
end;

Für die Wait-Funktion schau dir am besten das an:
www.delphipraxis.net/6620-delay.html