[gelöst]fpHTTPServer in einem Thread stoppen?

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
Soner
Beiträge: 724
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

[gelöst]fpHTTPServer in einem Thread stoppen?

Beitrag von Soner »

Ich habe einen fpHTTPServer in einem Thread, wenn ich das aus LCL-Anwendung stoppen möchte so z.B:

Code: Alles auswählen

procedure TForm1.BtnStartStopClick(Sender: TObject);
begin
  FServerThread.Server.Active:=false; //Server ist immer noch Aktiv
end;
dann geht das nicht, aber wenn ich eine URL zum stoppen aufrufe so z.B.:

Code: Alles auswählen

http://localhost:8080/close
dann klappt das.
Merkwürdigeweise sitzt der Requesthandlerfunktion in LCL-App:

Code: Alles auswählen

procedure TForm1.DoHandleRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; //..
begin
  FURL:=Arequest.URL;
  if FURL='/close' then FServer.Server.Active:=false //Server wird gestpppt
  end
  else HtServeDocAsStr('<html><body>Hello.</body><html>');
end;

Weiß jemand woran das liegt?

Also man muss zuerst fpHTTPServer stoppen, sonst kann Thread nicht gestoppt bzw. freigegeben werden.

Beispielprogramm liegt bei.
lclhttpserver1-pub.zip
(3.6 KiB) 69-mal heruntergeladen
Zuletzt geändert von Soner am Di 17. Dez 2024, 12:37, insgesamt 1-mal geändert.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 359
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: fpHTTPServer in einem Thread stoppen?

Beitrag von Jorg3000 »

Hi!

Ich glaube dein Programm ist in folgenden Zeilen "zu schnell" ...

Code: Alles auswählen

FServer.Server.Active:=false;
if FServer.Server.Active then ...
Das Setzen auf false weist die Listen-Schleife im Thread an, sich bei nächster Gelegenheit zu beenden. In der nächsten Zeile ist das aber noch nicht passiert, weil der andere Thread zwischenzeitlich noch gar nicht wieder ausgeführt wurde und noch gar nicht mitgekriegt hat, dass er sich beenden soll. Die Abfrage .Active ist keine Variable, sondern eine Funktion, und liefert deshalb wohl immer noch true zurück.

Ich würde deshalb .FreeOnTerminate:=true; setzen, damit du dich nicht darum zu kümmern brauchst. In deinem Programm hast du .FreeOnTerminate ausgeklammert.
Ich würde dir auch raten dein TForm1.FServer in .FServerThread umzubennen, denn FServer.Server ist verwirrend und macht nicht klar, welches der Thread ist.

Funktionsweise ... In THTTPServerThread.Execute() wird mittels FServer.Active:=true; eine Funktion aufgerufen, die eine Listen-Schleife enthält.
Dieser Aufruf FServer.Active:=true; kehrt nicht zurück! Das ist sehr komisch umgesetzt, denn man würde nicht erwarten, dass das bloße Setzen einer scheinbaren "Variable" auf true, nicht zurückkehrt.
Und zwar kehrt es solange nicht zurück, bis von einem anderen Thread aus (dem Hauptprogramm) wieder FServer.Active:=false gesetzt wurde.

Sobald nach FServer.Active:=false der ServerThread bei nächster Gelegenheit wieder ausgeführt wird, wird die Listen-Dauerschleife verlassen, wodurch erst das ursprüngliche .Execute() verlassen wird.
Wenn .FreeOnTerminate:=true gesetzt war, zerstört sich der ServerThread nach nun verlassenem .Execute() von selbst.

Blöd dabei ist, dass die Referenz auf das Thread-Objekt in TForm1 bei .FreeOnTerminate nicht auf NIL gesetzt wird.
Um das zu lösen, habe ich eine abgeleitete Klasse des Thread erstellt, darin .Destroy überschrieben, wofür ich mir einen Pointer auf einen Pointer hinterlegt habe, der letztlich TForm1.FServerThread auf NIL setzt.
Ist alles ein bisschen umständlich.
Grüße, Jörg

Soner
Beiträge: 724
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: fpHTTPServer in einem Thread stoppen?

Beitrag von Soner »

Ich habe gestern Gedankenfehler gemacht, Ich dachte nicht stoppen von Server trotz Active=false hat mit Thread zu tun. Aber es ist nicht so. Die Server-Schleife wartet bis ein Htttp-Request auftritt, wenn man fpHttpServer.Active:=false setzt und dann irgendwelche URL, egal welche aufruft, dann wird der Server sofort gestoppt.

Lösung des Problems:
Falls jemand Server wiederholt starten und stoppen möchte, dann kann er das zum stoppen machen:
1) fpHttpServer.Active:=false setzen, dann irgendein URL von diesem Server aufrufen.
2) Man erledigt das gleich mit URL-Aufruf in OnRequest-Ereignis:

Code: Alles auswählen

procedure fpHttpServer..HandleRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; var AResponse: TFPHTTPConnectionResponse);
begin
 if Arequest.URL='/close' then  //Aufruf z.B.: 'http://localhost/close'
    FServer.Server.Active:=false
  else .... //normales Verhalten
end;

Soner
Beiträge: 724
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: [gelöst]fpHTTPServer in einem Thread stoppen?

Beitrag von Soner »

Ich habe das Beispielprogramm verbessert und vereinfacht. Httpserver kann jederzeit gestoppt und gestartet werden. Ich lade es hoch falls jemand so etwas braucht kann es verwenden. Falls jemand auch Fehler oder Verbesserungsmöglichkeit sieht, dann bitte hier melden.
lclhttpserver2-pub.zip
(70.9 KiB) 74-mal heruntergeladen
Mir ist aufgefallen, dass der Thread sich mit Thread.Start nicht neu starten läßt, d.h. Thread.Execute wird trotz der Aufruf von Thread.Start nicht nochmal aufgerufen.
Wie kann man einen Thread nochmal starten? Muss man es immer freigeben und neu erstellen und starten?

Ich dachte erst das hat mit TfpHttpServer zu tun, deshalb es neu erstellt, aber dann ist mir aufgefallen, dass der Thread.Execute nicht mehr aufgerufen wird. Darum wird ab dem 2. Restart von HttpServer auch Serverthread freigegeben und neu erstellt.

Antworten