AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Verständnisfrage zur Erstellung eines Dienstes
Thema durchsuchen
Ansicht
Themen-Optionen

Verständnisfrage zur Erstellung eines Dienstes

Ein Thema von Jumpy · begonnen am 27. Jul 2012 · letzter Beitrag vom 6. Aug 2012
Antwort Antwort
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.737 Beiträge
 
Delphi 6 Enterprise
 
#1

Verständnisfrage zur Erstellung eines Dienstes

  Alt 27. Jul 2012, 12:44
Hallo,

hab mir schon einige Threads und Tutorials zur Erstellung eigener Dienste mit Delphi durchgelesen und wollte das mit der TService Klasse und der TService Application umsetzen.

Der Dienst soll nicht in einer Schleife immer wieder eine Aktion durchführen oder so, sonder es soll ein TTimer aktiviert und ein TServerSocket geöffnet werden. Nun soll nur noch mit entsprechenden Funktionen auf deren Events reagiert werden (TimerTimer, ServerSocker.On ClientRead,...).

Reicht es dazu, "einfach" diese Komponenten im OnExecute des Services zu aktivieren?:

Delphi-Quellcode:
procedure TService1.ServiceExecute(Sender: TService);
begin
  ServerSocket.Open
  Timer.Enabled:=true;
  while not Terminated do
    ServiceThread.ProcessRequests(True); // or False?
  ServerSocket.Close
  Timer.Enabled:=false;
end;
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 27. Jul 2012, 12:49
Bei uns sieht es so aus.
Delphi-Quellcode:
  while not Terminated do
    try
      ServiceThread.ProcessRequests(False);
      Sleep(10);
    except
      on E: Exception do begin
        // Fehler loggen
      end;
    end;

Frag mich aber nicht, ob das Sleep wirklich nötig ist. Ich glaub das war mal drin, um die CPU-Last etwas zu begrenzen, falls ServiceThread.ProcessRequests genauso brutal reagiert, wie Forms.Application.ProcessMessages und die CPU voll auslastet, selbst wenn nix zu tun ist.


Bei inst sieht aber eigentlich so aus
Zitat:
while Assigned(Sender) and not Terminated do
und nach der Schleife kommt kein Code in der ServiceExecute vor.

Im ServiceCreate steht dann noch Folgendes, um den Service als normale "Anwendung" starten zu können und in Ruhe zu debuggen.
Delphi-Quellcode:
  if IsDebuggerPresent or FindCmdLineSwitch('DEBUG', ['-', '/'], True) then begin
    Forms.Application.MainFormOnTaskBar := False; // geht leider doch nicht ohne Form
    Forms.Application.CreateForm(TForm, Temp); // Form zum Beenden und für Eintrag in Taskbar
    Temp.Caption := 'Debug-Mode: ' + SvcMgr.Application.Title;
    Temp.OnCloseQuery := DebugServiceClose;
    Temp.Visible := True;
    { SvcMgr.Application.Run; }
    {}if FindCmdLineSwitch('INSTALL', ['-', '/'], True) then
    {}  TServiceApplicationHack(Application).RegisterServices(True, FindCmdLineSwitch('SILENT', ['-', '/'], True))
    {}else if FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) then
    {}  TServiceApplicationHack(Application).RegisterServices(False, FindCmdLineSwitch('SILENT', ['-', '/'], True))
    {}else begin
    {}  Started := True;
    {}  ServiceStart(Self, Started);
    {}  if Started then begin
    {}    ServiceExecute(nil);
    {}    while not Terminated do
    {}      try
    {}        Forms.Application.ProcessMessages;
    {}        Sleep(10);
    {}      except
    {}        on E: Exception do begin
    {}          DM1.LogEvent('ServiceExecute: es ist ein nicht abgefangener Fehler aufgetreten', E);
    {}          Sleep(1000);
    {}        end;
    {}      end;
    {}  end;
    {}  Forms.Application.Terminate;
    {}end;
  end;
$2B or not $2B

Geändert von himitsu (27. Jul 2012 um 13:08 Uhr)
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.737 Beiträge
 
Delphi 6 Enterprise
 
#3

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 27. Jul 2012, 14:23
Hallo,

hab mal eine kleinen Test gebaut:

Delphi-Quellcode:
procedure TService1.ServiceExecute(Sender: TService);
begin
  Timer1.Interval:=10000;
  Timer1.Enabled:=true;
  while not Terminated do
    begin
    ServiceThread.ProcessRequests(True); //false
    //Sleep(10);
    end;
  Timer1.Enabled:=false;
end;

procedure TService1.Timer1Timer(Sender: TObject);
var t:TStringlist;
begin
  t:=TStringlist.Create;
  t.LoadFromFile('C:\Test\Servicetext.txt');
  t.Add(DateTimeTostr(now));
  t.SaveToFile('C:\Test\Servicetext.txt');
  t.Free;
end;
Die Variante von himitsu ist OK, belastet die CPU nicht:
ServiceThread.ProcessRequests(false)+Sleep(10)

Lass ich das Sleep weg, so hab ich direkt 50% CPU Dauerauslastung.

Was auch noch geht (ohne Sleep) ist:
ServiceThread.ProcessRequests(true)

Weiß nicht genau, was der Parameter true statt false bewirkt, so ginge es aber scheinbar auch.
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 28. Jul 2012, 07:34
Der Name des Parameters WaitForMessage lässt mich annehmen, dass dort schon gewartet wird und deshalb die Last nicht hochgeht.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von divBy0
divBy0

Registriert seit: 4. Mär 2007
Ort: Sponheim
1.021 Beiträge
 
Delphi XE2 Professional
 
#5

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 28. Jul 2012, 07:36
Bei true wird MSDN-Library durchsuchenGetMessage() verwendet, bei false MSDN-Library durchsuchenPeekMessage().
Marc
9 von 10 Stimmen in meinem Kopf sagen ich bin nicht verrückt, die 10. summt die Melodie von Tetris... | Wenn das die Lösung ist, dann hätte ich gerne mein Problem zurück! | engbarth.es
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.737 Beiträge
 
Delphi 6 Enterprise
 
#6

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 3. Aug 2012, 10:10
Hallo,

ich hab's jetzt so umgesetzt wie in am Anfang von himitsus post mit dem Loggen im Fall einer Exception. Der Dienst macht was er soll nur ab und an stürzt er wohl noch ab und dann nur mit der folgenden exception-message:

Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000

Da das ja ein Dienst ist, kann ich nicht den Fehler finden, wo das passiert. Ich habe das Programm separat als From-Anwendung entwickelt, da läuft das stabil.

Gibt es eine Möglichkeit, den Dienst zu debuggen?

Mittleweile kann ich den Fehler glaub ich auch reproduzieren. Der Dienst macht eine ServerSocket auf. Ein Client meldet sich an und beauftragt den Server "Dinge" zu tun. Client meldet sich wieder ab. 1-2 Minuten später kommt dann der Absturz.
In der Form-Anwendung, wo an den entscheidenden Stellen mMn alles gleich ist, passiert das nicht.

Ich kappsele jetzt mal jede Prozedur in einen Try-Except-Log Block, vllt. krieg ich so mehr raus. Aber vllt. hat jemand noch eine andere Idee?
Ralph
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#7

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 3. Aug 2012, 10:20
Du kannst Dienste durchaus debuggen.
Zum Dienststart ein kleines Delay einbauen (Sleep 10000) in Delphi

Start/Mit Prozess verbinden

ab Vista muss Delphi hierbei als Adminstrator ausgeführt werden.

Der Fehler klingt als ob Du auf etwas zugreifst was zu dem Zeitpunkt nicht mehr existiert (Thread/Socket etc ..)
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.771 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 3. Aug 2012, 10:23
Zugriffsverletzung bei Adresse 00000000. Lesen von Adresse 00000000
Die Fehlermeldung deutet darauf hin, dass auf eine Instanz (lesend) zugegriffen wird die nicht existiert oder nicht mehr existiert.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.737 Beiträge
 
Delphi 6 Enterprise
 
#9

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 3. Aug 2012, 13:59
Vielen Dank schon mal an alle Helfer, aber leider:

Ich komm dem Fehler nicht auf die Spur. Ich hab alles in try...except gekapselt, aber keiner dieser Blöcke springt an. Ich hatte es jetzt auch zweimal so, das ein Dialogfenster mit dem Fehler eingeblendet wurde (nicht von mir und ich war nicht im Debugmodus). Das verrückte war, solange dieses Dialogfenster offen war lief der Dienst weiter. Er meldete Timergesteuert jede Minute, das er noch lebt ins Log und schickt auch ein Statusupdate an den Client, d.h. die Socket-Verbindung blieb besthen.
Erst wenn der Dialog mit 'OK' bestätigt wird, semmelt der Dienst ab.

Vllt. zum Hintergrund. Eine der Aufgaben des Dienstes ist es (auf Aufforderung des Clients) eine Klasse zu erzeugen, in der dynamisch ein Timer und ein TelnetClient erzeugt werden. Dann erfolgt eine Kommunikation zw. Telnet-Client und Telnet-Server in einem ganz anderen Porgramm (ServersAlive)). Dann wird die Telnet-Verbindung getrennt und diese Klasse mit FreeAndNil() freigegeben.

Für die Klasse gibt's eine globale Variable und immer wenn eine Instanz davon gebraucht wird schau ich immer erst ob die variable nil ist und wenn ja, dann erzeug ich die Klasse. Das sollte doch so gehen, oder hab ich den Zweck von FreeAndNil() falsch verstanden?

Meine Befürchtung ist auf jeden Fall, dass das irgendwo aus den Tiefen der Indys kommt aber wie gesagt: Ich find's nit

Ich lad das Projekt (sind eh nur 3 Units) mal hoch, vllt. hat ja wer von euch am Wochenende mal Langeweile und findet, woran es liegen könnte. Wegen einem Trauerfall in der Familie, komm ich am WE selber nicht dazu und mach jetzt auch schon Feierabend.

Danke,
Jumpy

P.S.: Hab ich vergessen: Wenn ich alles auskommentiere, was mit der benachrichtigung von ServersAlive via Telnet zu tun hat, läuft der Dienst stabil, erfüllt auch seine Aufgabe (andere Dienste an und auszustellen) stabil. Deswegen hab ich das oben explizit erklärt.
Angehängte Dateien
Dateityp: zip Testprojekt.zip (11,5 KB, 21x aufgerufen)
Ralph

Geändert von Jumpy ( 3. Aug 2012 um 14:02 Uhr)
  Mit Zitat antworten Zitat
Jumpy

Registriert seit: 9. Dez 2010
Ort: Mönchengladbach
1.737 Beiträge
 
Delphi 6 Enterprise
 
#10

AW: Verständnisfrage zur Erstellung eines Dienstes

  Alt 6. Aug 2012, 11:56
Ich hab es jetzt so umgeändert, das die Klasse, die die Telnetverbindung zu SA aufbaut, nicht jedes mal "neu erzeugt und dann ge-FreeAndNilled" wird, sondern sie wird nur einmal beim ersten Aufruf erzeugt. Hat sie ihr Ding gemacht, wird die Telnet-Connection geschlossen, und alle Werte zurückgesetzt. Bei späteren Aufrufen, werden nur die Propertys neu gesetzt und die Klasse "gestartet".

So scheint es zu funktionieren. Irgendwas am ständigen freigeben und neu erzeugen hat wohl nicht funktioniert. Hab die neue Lösung jetzt mal im Dauertest, schaun, ob noch Fehler auftauchen.
Ralph
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:21 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz