![]() |
TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
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:
Es wird auch keine Fehlermeldung angezeigt. Die Anwendung ist eine Konsolenanwendung (ohne LCL) und ist dann einfach weg.
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; Ich hoffe, dass von euch jemand Erfahrungen und evtl. auch Lösungsansätze in der Richtung hat. Vielen Dank für eure Mühen! :thumb: |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
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. |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
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. |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
LCL? Delphi oder doch Lazarus?
Also der ganze Server ist also eine Konsolenanwendung und du hast vermutlich vergessen die eine Exception abzufangen. :angel: 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. |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Zitat:
Zitat:
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 ;) |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Das mit dem
Delphi-Quellcode:
in deinem Code habe ich aber auch nicht verstanden.
try .. finally
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
Delphi-Quellcode:
Block ist hervorragend zum Aufräumen gedacht um keine Speicherlecks zu hinterlassen. Oder etwas zu schließen, was vorher geöffnet wurde.
finally
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. |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
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. :thumb: 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". |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Update: auch ein try...except-Konstrukt, in dem der Exception-Block die Exception-Nachricht ausgibt, um das Haupt-Programm ändert nichts am kommentarlosen Absturz.
|
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Zitat:
Kann es sein, dass dir irgend etwas durch den Speicher rauscht? Mavarik |
AW: TIdHTTPServer: Programmabsturz bei langwieriger ResponseInfo-Berechnung
Den ExitCode auslesen wäre mal ein Versuch. (vielleicht wird ja irgendwo ein hartes
![]() 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) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:23 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