AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Thema durchsuchen
Ansicht
Themen-Optionen

TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

Ein Thema von MStoll · begonnen am 31. Dez 2013 · letzter Beitrag vom 2. Jan 2014
Antwort Antwort
Seite 1 von 3  1 23      
MStoll

Registriert seit: 15. Nov 2005
131 Beiträge
 
Turbo Delphi für Win32
 
#1

TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 00:21
Hallo,

ich schreibe gerade eine Anwendung zur Steuerung einer Startampel für Motorsport-Veranstaltungen mittels eines Raspberry Pi und compiliere diese mit FreePascal 2.6.0. Dieser steuert über die GPIO-Ports die eigentliche Ampel-Schaltung bzw. liest deren Zustand aus. Dazu enthält die Anwendung auch einen Webserver auf Indy-Basis (TIdHTTPServer). Gleichzeitig ist an das Kamera-Interface des Pi auch noch eine passende Kamera angeschlossen, die einen Videostream liefert, aus dem dann interrupt-gesteuert bei Auslösen einer Lichtschranke das aktuelle Frame des Videostreams zwischengespeichert wird. Dies zur Überwachung des Startbereiches, für den die Startampel zuständig ist.

Eben dieses zwischengespeicherte Videoframe möchte ich als JPEG-Bild über den HTTP-Server ausgeben. Geht auch alles wunderbar, solange nur 1 Client auf das Webinterface zugreift. Sobald mehrere auf das Videobild zugreifen, stürzt die Software ab. Ich muss folgendes dazu sagen: die Umwandlung des Videoframes in das JPEG-Format einschließlich der Ausgabe in einen MemoryStream dauert ca. 2-3 Sekunden. Solange müssen alle Webclients warten, da die Erstellung mittels einer Critical Section geschützt ist.

Nochmal eine kurze Funktionsübersicht:
- Steuerung bzw. Auslesen der Startampel mittels GPIOs und Interrupts
- Abfangen einzelner Video-Frames der CSI-Kamera über einen GPIO-Interrupt, der durch eine angeschlossene Lichtschranke ausgelöst wird
- Ausgabe des Startampel-Zustands (Zählerstand, welche roten bzw. grünen LEDs leuchten etc.) + Steuerung über Webinterface mittels von TIdHTTPServer abgeleiteter Klasse

Nach langem Testen habe ich herausgefunden, dass die zeitliche Dauer der JPEG-Erstellung das Problem ist, da ich den Absturz der Anwendung auch dadurch herbeiführen kann, dass ich in das DoCommandGet-Event ein Sleep(2000) einfügen kann. Dies führt dann selbst beim Aufruf einfacher Text-Pages zum Absturz, unabhängig davon, ob ich "ContentText" oder "ContentStream" für die Ausgabe verwende. Dann auch schon, wenn nur 1 Webclient auf das Webinterface zugreift.

Wenn ich in der "TIdHTTPResponseInfo.WriteContent"-Methode (TIdCustomHTTPServer.pas)die "FConnection.IOHandler.Write"-Aufrufe auskommentiere, geht naturgemäß zwar keine Webausgabe, aber dann stürzt auch mein Programm nicht ab. Bei kurzen Antwortzeiten (kleine Seiten, Bilder etc.), die nur wenige Millisekunden benötigen, funktioniert alles wunderbar.

Ein kurzes Code-Beispiel:
Delphi-Quellcode:
procedure THTTPServer.DoCommandGet(AContext: TIdContext;
      ARequestInfo: TIdHTTPRequestInfo;
      AResponseInfo: TIdHTTPResponseInfo);
var
  fs : TFileStream;
  fileExt, document, content, filePath, fileName : string;
  commandNumber : Integer;
begin
  document := 'HTTP' + StringReplace(ARequestInfo.Document, '..', '', [rfReplaceAll]);
  if document = 'HTTP/then
    document := document + 'index.html';

  filePath := SysUtils.ExtractFilePath(document);
  fileName := SysUtils.ExtractFileName(document);
  try
   // ...
   // Hier werden ContentText bzw. ContentStream befüllt
   // ...
  finally
    if Assigned(AResponseInfo.ContentStream) then
    begin
      try
        Sleep(2000); // <--- führt zum kommentarlosen Crash
        AResponseInfo.WriteContent;
      except on e: exception do
        Writeln(e.Message);
      end;
    end
    else if AResponseInfo.ContentText <> 'then
    begin
      Sleep(2000); // <--- führt ebenfalls zum kommentarlosen Crash
      AResponseInfo.WriteContent;
    end;
  end;
end;
Es wird auch keine Fehlermeldung angezeigt. Die Anwendung ist eine Konsolenanwendung (ohne LCL) und ist dann einfach weg.

Ich hoffe, dass von euch jemand Erfahrungen und evtl. auch Lösungsansätze in der Richtung hat. Vielen Dank für eure Mühen!
"Man soll nie mehr essen als mit Gewalt reingeht!" (n.n.)

Geändert von MStoll (31. Dez 2013 um 00:23 Uhr) Grund: Compiler-Angabe vergessen
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 01:44
Wenn du das Signal der Lichtschranke bekommst, dann wandle den Frame in ein JPEG um (eigener Thread) und liefere das einfach an die Clients aus.

Solange da noch nichts vorliegt liefere einfach ein Dummy-Bild aus.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
MStoll

Registriert seit: 15. Nov 2005
131 Beiträge
 
Turbo Delphi für Win32
 
#3

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 02:00
Danke für die Antwort. Aber das Blockieren (bis das Bild fertig berechnet ist) macht schon Sinn.

Und generell möchte ich ungern daraufhin programmieren, irgendwelche zeitlichen Grenzen zu unterbieten, um einen Programmabsturz zu verhindern. Es könnte ja auch aus anderen Gründen dazu kommen, dass die Bearbeitung einer Anfrage mal länger dauert. Und dann wäre der Programmabsturz da. Von daher wäre es gut, wenn man das Problem irgendwie lösen könnte anstatt es für den Einzelfall zu umgehen.
"Man soll nie mehr essen als mit Gewalt reingeht!" (n.n.)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 03:14
LCL? Delphi oder doch Lazarus?


Also der ganze Server ist also eine Konsolenanwendung und du hast vermutlich vergessen die eine Exception abzufangen.
Und hier wird vermutlich das Transfer-Timeout der Klientanwendung zuschlagen.

Es ist grundsätzlich so, daß wenn Exceptions, welche bis zur Basis zum Windows gelangen das Programm abschießen.
Bei der VCL ist es so, daß die Message-Behandlung über ein Try-Except geschützt ist und Exceptions so praktisch nie bis zur obersten Ebene durchgelangen.

Windows zeigt keine Exceptions an. Dieses macht das Programm selber, indem es sie abfängt und "verarbeitet".
Ist eine Exception durchgerauscht, dann gibt das Programm maximal noch einen Fehlercode zurück (System.ExitCode > in DOS das berühmte ERRORLEVEL)
und eventuell wird noch eine Meldung in die Ereignisanzeige vom Windows geschrieben.

Aus diesem Grund hatte Embarcadero vor einer ganzen Weile auch die Vorlage für Konsolenanwendungen erweitert.
Delphi-Quellcode:
program Project10;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

begin
  try
    { TODO -oUser -cConsole Main : Code hier einfügen }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.
$2B or not $2B

Geändert von himitsu (31. Dez 2013 um 03:17 Uhr)
  Mit Zitat antworten Zitat
MStoll

Registriert seit: 15. Nov 2005
131 Beiträge
 
Turbo Delphi für Win32
 
#5

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 13:37
LCL? Delphi oder doch Lazarus?
Weder noch, einfach nur Free Pascal mit einer zur Laufzeit erzeugten Indy-Komponente (HTTP-Server) auf einem Raspberry Pi.

Also der ganze Server ist also eine Konsolenanwendung und du hast vermutlich vergessen die eine Exception abzufangen.
Und hier wird vermutlich das Transfer-Timeout der Klientanwendung zuschlagen.

Es ist grundsätzlich so, daß wenn Exceptions, welche bis zur Basis zum Windows gelangen das Programm abschießen.
Bei der VCL ist es so, daß die Message-Behandlung über ein Try-Except geschützt ist und Exceptions so praktisch nie bis zur obersten Ebene durchgelangen.

Windows zeigt keine Exceptions an. Dieses macht das Programm selber, indem es sie abfängt und "verarbeitet".
Ist eine Exception durchgerauscht, dann gibt das Programm maximal noch einen Fehlercode zurück (System.ExitCode > in DOS das berühmte ERRORLEVEL)
und eventuell wird noch eine Meldung in die Ereignisanzeige vom Windows geschrieben.
Mir ist schon klar, wie das mit den Exceptions funktioniert. In deiner Vorlage würde eine Exception aber auch zum Beenden des Programms führen, da nach dem except-Block das Programm endet. Es soll ja auch nicht der ganze HTTP-Server abstürzen, wenn es mal irgendwo zu einem Timeout kommt.

Wie man an dem Beispiel oben sieht, habe ich zumindest für den Fall des ContentStreams (bei dem der Fehler ursprünglich auftrat) einen try...except-Block um den "WriteContent"-Aufruf herum platziert.

Ich werde aber wohl mal zum Test einen try...except-Block um das ganze Hauptprogramm herum machen und schauen, ob mir dann eine Fehlermeldung angezeigt wird. Evtl. tritt die Exception ja an einer anderen Stelle im Programm auf.

Und was Windows oder DOS machen, ist ja für einen Raspberry Pi nicht ganz so interessant
"Man soll nie mehr essen als mit Gewalt reingeht!" (n.n.)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 14:03
Das mit dem try .. finally in deinem Code habe ich aber auch nicht verstanden.

Du möchtest also, auch wenn vorher eine Exception geworfen wurde, immer einen Response abliefern, ohne zu wissen, ob der nun sinnvoll oder sinnentleert ist.

Wenn in dem Code eine Exception auftritt, dann kann man die behandeln, weil man das erwartet hat und dafür eine Möglichkeit hat, das noch zu retten oder man lässt diese Exception passieren (und fängt diese an anderer Stelle zum Loggen).

Der finally Block ist hervorragend zum Aufräumen gedacht um keine Speicherlecks zu hinterlassen. Oder etwas zu schließen, was vorher geöffnet wurde.

Insgesamt sehe ich hier auch eine fehlerhaftes Management der Exceptions.

Und warum der gleiche Frame immer wieder in ein JPEG umgerechnet werden soll erschließt sich mir auch nicht.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
MStoll

Registriert seit: 15. Nov 2005
131 Beiträge
 
Turbo Delphi für Win32
 
#7

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 16:22
Das try...finally ist weniger der Exceptions wegen (die erwarte ich im try-Block nicht), sondern dazu, dass ich im try-Block ein exit ausführen kann, wenn ich weiter innen mit dem Aufstellen der Antwort fertig bin. Kann man auch anders lösen, muss man aber nicht.

Im übrigen ist das ein Beispiel-Code, um zu zeigen, wo das Sleep platziert ist, und nicht etwa der Code im Endzustand. Da müsste auch noch ein try...except, um den Block, der den ContentText behandelt herum, um konsistent zu sein. Aber der beschriebene Fehler tritt in erster Linie im ContentStream-Block auf.

Und ich habe nicht gesagt, dass ich das gleiche Frame jedesmal in JPEG umwandle. Aber wenn alle Clients während der 2-3 Sekunden, in denen die Umwandlung zum ersten und einzigen Mal stattfindet, anfragen, dann müssen sie halt auch alle warten, bis die erste Erstellung vorbei ist. Und dieses Warten ist, wie gesagt, so gewollt. Danach wird bis zum Zwischenspeichern eines anderen Frames aus einem Cache, der die JPEG-Variante enthält, gelesen.

Und nochmal: ich habe hier das recht _allgemeine_ Problem, dass bei einer langen Antwortberechnung (egal wie die jetzt im Detail aussieht, ob ContentText oder ContentStream benutzt wird etc.) das Programm _kommentarlos_ abstürzt.

Ich bin dankbar für eure Mühen.
Aber ich bin kein Anfänger, dem man die Grundlagen des Exception-Handlings erklären muss, NUR weil in dem unfertigen Beispiel-Stück vielleicht das eine oder andere Detail noch nicht ganz perfekt aussieht. Das Problem liegt hier an einer anderen Stelle, soweit bin ich schon gekommen. Mein Problem ist, dass ich den detaillierten Aufbau des Indy HTTP-Servers nicht kenne und mir das Programm mangels Fehlermeldung auch keinerlei Hinweis darauf gibt, wo das Problem sein könnte (trotz try...except-Block um die betreffende Stelle).
Und sollte es da irgendwo eine Zugriffsverletzung geben, dann weiß ich nicht, wie das Programm auf derartige Exceptions reagiert. Da habe ich schon unterschiedlichste Erfahrungen gemacht, je nach dem, ob solche Exceptions in eingebundenen Laufzeitbibliotheken (statisch oder dynamisch eingebunden) oder im Hauptprogramm, im Main-Thread oder einem Hintergrund-Thread auftreten. Die Bandbreite reicht von Exception mit Fehlermeldung, über Fehlermeldungen mit Programmabsturz, Einfrieren des Programms bis hin zum kommentarlosen verschwinden. Und das alles auch, wenn der entsprechende Teil mit einem try...except-Block geschützt war. Evtl. räumt ja der Indy HTTP-Server irgendwo nach einem Timeout was auf, was noch nicht aufgeräumt werden sollte.

Ich werde jetzt mal einen try...except-Block um das ganze Programm machen, in der Hoffnung, irgendwas zu finden. Da es sich allerdings um einen Server handelt und der Fehler beim Senden der Antwort liegt, weiß ich nicht, ob der try...except-Block dann den richtigen Thread "umfasst".
"Man soll nie mehr essen als mit Gewalt reingeht!" (n.n.)
  Mit Zitat antworten Zitat
MStoll

Registriert seit: 15. Nov 2005
131 Beiträge
 
Turbo Delphi für Win32
 
#8

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 16:31
Update: auch ein try...except-Konstrukt, in dem der Exception-Block die Exception-Nachricht ausgibt, um das Haupt-Programm ändert nichts am kommentarlosen Absturz.
"Man soll nie mehr essen als mit Gewalt reingeht!" (n.n.)
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.144 Beiträge
 
Delphi 10.3 Rio
 
#9

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 16:38
Update: auch ein try...except-Konstrukt, in dem der Exception-Block die Exception-Nachricht ausgibt, um das Haupt-Programm ändert nichts am kommentarlosen Absturz.
Ich "glaube" nicht an ein Zeitverhalten...

Kann es sein, dass dir irgend etwas durch den Speicher rauscht?

Mavarik
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung

  Alt 31. Dez 2013, 16:48
Den ExitCode auslesen wäre mal ein Versuch. (vielleicht wird ja irgendwo ein hartes Delphi-Referenz durchsuchenHalt aufgerufen, auch wenn ich das nicht hoffe)
Oder gibt es sowas unter Linux nicht? (hätte vermutet, daß die sowas auch haben)



Raspberry Pi ... hmmmmm

Hat der Raspberry Pi auch ein Eventlog im System?

Und mit dem Debuggen wird es dort wohl nicht so einfach?



Mit etwas "Glück" hast du einen Bug im FPC oder im Raspberry Pi entdeckt und kannst da nicht viel machen.
(außer diese Pausen zu verhindern)
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      

 

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 23:36 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