Christoph Zurnieden: HTTP-Request abbrechen

Beitrag lesen

Hallo,

IMHO ist das aber kein Grund, aufwendige Javascript/Session/Sonstwas-Abbruchkonstruktionen zu basteln. Denn _sowas_ führt meiner Erfahrung nach nur zu mehr Problemen als das es welche löst. Wie Du bereits sagtest: es gibt "zuviele Clients als das man sich [..] auf irgendetwas verlassen könnte" - da nehme ich doch lieber den einfachsten Weg.

Ich fand das den einfachsten Weg (den über Sessions)
Wenn Du etwas Einfacheres hast: nur raus damit!
Ich wäre der Letzte, der sowas nicht begrüßen würde.

Wie gesagt, mod_fastcgi spuckt ein Signal aus, wenn versucht wird, in eine bereits geschlossene Verbindung zu schreiben. Damit kann man zwar leider nicht exakt synchron mit dem Ereignis selber beenden, aber ein Leerzeichen alle x Durchläufe (oder was auch immer das Skript macht) tut IMHO niemandem weh.

Höchstens dem Geldbeutel.

Wer unbedingt die Rechenleistung braucht, die in diesen wenigen Sekunden Verzögerung vom Skript "nutzlos" verbraten wird, sollte sich vielleicht Gedanken darüber machen, ob er die richtige Hardware für sein Vorhaben auf dem Tisch stehen hat.

Das liegt schonlange nicht mehr ander Hardware, sondern am Durchsatz. Transfer ist heutztage das Teure.
Selbst so ein Leerzeichen kann sich summieren übers Jahr. Wenn die Paketgröße bei den jetzt üblichen ~1500 Bit liegt ...

Das Problem bei TCP ist nur, das die Verbindung _aktiv_ geschlossen werden muß.
Ansonsten kann nur ein Timeout greifen.

Keine Ahnung auf welchen Timeout Du Dich beziehst, aber spätestens wenn Du versuchst, in eine geschlossene Verbindung zu schreiben, kriegst Du ein's auf den Deckel. Man muß diesen, oben bereits beschrieben "Test" also nur serverseitig entsprechend realisieren. Sollte nicht so schwer sein.

Es geht aber nicht um den Server, sondern um den Client. Von da aus gibt es nicht viele Möglichkeiten.

HTTP hat mit der darunterliegenden Netzwerkverbindung TCP absolut garnichts zu tun. HTTP sieht keinen "Befehl" zum unerwarteten Beenden einer Verbindung vor, das stimmt. Das ist auch nicht nötig, weil man einfach die Netzwerkverbindung (TCP) beendet.

Schön, aber wie machst Du es mit einem Browser?

Stopp drücken oder Seite wechseln. Wenn ich eine riesige Datei runterlade und mittendrin Stopp drücke, hört die Übertragung sofort auf und meine Mikro-Firewall zeigt die Verbindung als geschlossen an (genauer: zeigt sie nicht mehr an) -> Ziel erreicht.
Was ist denn daran so schwierig?

Das der Server davon evt nichts mitbekommt. Meistens ist das ordentlich implementiert und die Verbindung wird ordnungsgemäß nach TCP beendet, aber eben nur meistens.
Das es bei Dir so ist, heißt nicht, das es überall so ist.
Was machst Du außerdem, wenn Du diverse Forks laufen hast? Das kann auch eine Subshell sein, nicht zwingend ein reguläres Child. Die rennt dann weiter, wenn sie nicht abgeschossen wird.

So ist es auch in der HTTP-Spezifikation dokumentiert und mit mehr oder weniger unerwartet abbrechenden Verbindungen sollte im übrigen jede Netzwerkapplikation schon von Natur aus rechnen.

Ja, und? Die Verbindung zwischen Webserver und -client besteht nunmal aus der _Einheit_ TCP und HTTP. HTTP führt übrigens kein Eigenleben, es wird vom Browser angewendet. Insofern kann es sich nicht garicht "für irgendetwas interessieren", der einzige Interessierte ist der Browser, und der sieht sowohl seine HTTP-Anfrage als auch seine Netzwerkverbindung.

Nein, er nutzt die Netzverbindung nur, er sieht sie aber nicht.
HTTP braucht zur Funktion nur einen Gegenspieler und eine Verbnindung dazu, kein spezielles Netz.
Du kannst also sagen, das HTTP eine Verbindung braucht. Wie diese aussieht, ist aber völlig egal, Postkarten würden reichen.

Mit Verlaub, das ist als Begründung für einen aufwendigen CGI-Abbruch über Sessionprüfungen etwas sehr weit aus der Theorie hergeholt.

"Über 90% der Surfer nutzen den IE, warum soll ich mich für die restlichen paar Prozente abmühen?"

Ne ne, Herr Kollege, so nicht! ;-)

Das ursprüngliche Problem war, auch wenn sich der Threadinitiator schon längst sehr irritiert zurückgezogen hat, vom Client aus aktiv(!) dem Server ein Signal zum Abbruch eines vorher vom selbem Client angestoßenen Prozesses zu übermitteln. Da der Client sich mit dem Server über HTTP unterhält, war die einzige Möglichkeit, die mir einfiel eben jene: mittels SessionID alle Mittäter zu identifizieren und dadurch eine Möglichkeit zu schaffen den fraglichen Prozess zu killen.
Alles andere ist nicht sicher genug und selbst meine Methode hat einige Schwachstellen.
Nur vom Server aus wäre es möglich, den Client regelmäßig "anzupingen" um sein Interesse nachzuprüfen. Bei länger andauernden Serverprozessen, z.B. die Volltextsuche in Terabytedatenbanken o.ä., wäre das sogar zu empfehlen, um ein evt Timeout auf Clientseite zu verhindern.

Es würde mich doch ein wenig wundern, wenn irgendeine HTTP-Anwendung allen Ernstes so geschrieben wurde, daß die HTTP-Schicht keine Ahnung von der Transportschicht hat und insbesondere nichts vom Beenden der Transportverbindung mitbekommen würde.

Tut sie auch nicht, dafür sind andere zuständig.
Sollten zumindest ;-)

Es wäre doch völliger Quatsch, wenn man Kontrollnachrichten der Transportschicht nicht verarbeitet bzw. in die Bearbeitung bei der HTTP-Schicht mit einbezieht.

Das wiederspräche aber der so heiß und innig geliebten Objektorientiertheit. >;->

Diese Vorgehensweise hätte etwas von einem Auto, in dem die Insassen erst mitbekommen, daß sie wegen leerem Tank wohl nicht am Ziel ankommen werden, nachdem die Karre zehn Minuten lang regungslos auf der Autobahn gestanden hat..

Beinahe hätte ich gesagt, daß dieser Vergleich nicht nur hinkt, sondern sogar schon im Rollstuhl sitzt, aber ich kenne da einen ADAC Straßenwachtfahrer: Sowas gibt es öfters als man annimmt.

Anderes Praxisbeispiel:

Wenn ich mich per telnet an einen HTTP-Server klemme, dann sagt telnet mir automatisch und ohne Zeitverzögerung, daß die Verbindung getrennt wurde, sobald der Server seine Antwort geschickt hat.

Ja, denn Telnet hängt etwas mehr an TCP. Das HTTP besorgst Du da ja händisch.

So. Wo ist denn bitte da die relevante Eieruhr, um die Du Dich sorgst? Für mich sieht das jedenfalls so aus, als wenn telnet, das ja nun unwiderlegbar keinerlei Ahnung davon hat, daß ich es für HTTP mißbrauche, von dem Verbindungsabbruch von Seiten des Webservers auf irgendeine Art und Weise informiert wurde, und zwar innerhalb weniger Zehntelsekunden.

Es wird nach TCP die Verbindung beendet. Das _muß_ nach Telnet Protokol beachtet werden, deshalb tut telnet das auch. (Ach, wenn doch auch die Browser sich daran halten würden: "... muß nach HTTP, deswegen macht der Browser das auch so"  *sigh* )

Warum soll das mit anderen Anwendungen nicht auch funktionieren?

Andere Protokolle?

Aus RFC 793, 3.5, "Closing a [TCP] connection", lese ich davon mal abgesehen, daß TCP durchaus eine geordnete Möglichkeit vorsieht, eine Verbindung zu beenden, namentlich mittels FIN- und CLOSE-Segmenten, nicht mittels "seit fünf Minuten kein Bit auf der Leitung".

Ja (Das meinte ich übrigens mit "sauber beenden"), aber lies mal weiter:

The normal TCP close sequence delivers buffered data
reliably in both directions.  Since the two directions of a
TCP connection are closed independently, it is possible for
a connection to be "half closed," i.e., closed in only one
direction, and a host is permitted to continue sending data
in the open direction on a half-closed connection.

[es folgen noch eine Sätze, die allerdings durch die Benutzung von MAY und SHOULD relativiert werden]

Klingt eindeutig? Na, dann schau Dir mal einige der Implementierungen an.

Somit sollte es für den TCP-Stack (zumindest theoretisch) kein Problem sein, die Anwendung von einer geschlossenen Verbindung unverzüglich zu informieren und diese sollte daraufhin auch in der Lage sein, ihre Aktivitäten unverzüglich zu beenden. Das hat mit HTTP letztenendes garnichts mehr zu tun.

Deshalb läßt es sich auch für das Problem nicht benutzen.

Das es kein Problem darstellt, jemanden zu informieren heißt leider noch lange nicht, das es auch getan wird. Siehe auch die derzeitigen Problem an der Elbe und Umgebung.

Also ich sehe das Zeitproblem immernoch nicht.

Das Timeoutproblem entsteht nur, wenn _nicht_ ordnungsgemäß geschlossen wurde.
Das passiert aber leider häufiger, als nötig.

so short

Christoph Zurnieden