Markus Möller: ServerPush, ClientPull und Alternativen

Hallo zusammen!
Ich habe folgendes Problem:
Ich habe ein Servet, das Informationen stückweise erhält (also ca. eine Minute lang alle 2 Sekunden weitere 100 Daten).
Jetzt soll das ganze in einer HTML-Tabelle dargestellt werden. Nun sieht es so aus, dass erst diese eine Minute gewartet wird, bis alle Daten da sind und das dann alles zusammen raus zum Browser geht. Ich möchte aber, dass der Benutzer schon nach 2 Sekunden die ersten 100 Datensätze sieht, 2 Sekunden später dann die nächsten (also insgesamt 200) usw.
Die Tabelle soll sich also schrittweise aufbauen.
Laufen muss das in Netscape >=6, MSIE >=5, Mozilla und Opera >=6
Nun habe ich mir schon mehrere Möglichkeiten ausgedacht:

SERVER PUSH:
Mit multipart/x-Mixed-Replace würde es wohl gehen, aber eben nicht überall. Außerdem würde die Seite dann auch jedesmal neu aufgebaut. Ich muss das Dokument ja auch nicht jedesmal überschreiben, sondern ein anhängen würde ja ausreichen. Also fällt das schon weg.
Ich habe aber auch multipart/mixed gefunden, kann damit aber nichts anfangen. Kann mir jemand etwas darüber sagen?

CLIENT PULL:
Unschön, weil ich a) nicht weiß, wann Daten kommen (die 2 Sekunden im Beispiel sind nicht konstant) und b) die Seite nicht jedesmal neu laden will.

CLIENT PULL mit Trick:
Jetzt habe ich mir überlegt, in einem versteckten Frame bzw. IFrame die neusten Daten per Client Pull zu holen und dann diese per DHTML dynamisch an die Tabelle zu fügen. Dies finde ich nicht besonders elegant und außerdem ist es fraglich, ob das auch wirklich überall klappt. Gerade bei Opera und DHTML brallen zwei Welten aufeinander...

AUSGABE UNGEPUFFERT RAUSSCHRIEBEN:
Dazu habe ich ein kleines Demo, das aber irgendwie nicht das tut, was es soll:

----------------------------
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Countdown2 extends HttpServlet {

public void doGet(
  HttpServletRequest req,
  HttpServletResponse res
 )
 throws
  ServletException,
  IOException
 {
  res.setBufferSize(0);
  ServletOutputStream out = res.getOutputStream();

for (int i = 10; i > 0; i--) {
   out.println(i + "...");
   out.flush();
   res.flushBuffer();
  try { Thread.sleep(1000); } catch (InterruptedException e) { }
  }
  out.println("P E N G");
 }
}
----------------------------

Das Servlet soll im Sekundentakt von 10 auf 1 runterzählen und schließlich auch "PENG" ausgeben.
Gedacht ist es so, dass erst "1" da steht, dann "1 2", dann "1 2 3", ...
Tatsächlich dauert es aber erst 10 Sekunden und dann kommt die komplette Ausgabe.
Kann ich das Servlet nicht anweisen, seine Ausgaben DIREKT rauszuschreiben?

Wäre schön, wenn mir jemand weiterhelfen, Antworten oder sonstige Tipps geben könnte.

  1. Moin!

    Laufen muss das in Netscape >=6, MSIE >=5, Mozilla und Opera >=6
    Nun habe ich mir schon mehrere Möglichkeiten ausgedacht:

    SERVER PUSH:

    Vergiß den ganz schnell. Geht nur mit Netscapes, und da auch nur bis Version 3.0 - also eher ungeeignet. Das "x-" im Mimetyp deutet ja auch darauf hin, daß es experimentell ist bzw. war.

    Abgesehen davon lädt so ein Server-Push immer komplette Dateien neu - vom Server initiiert. Du mußt also nicht den Client anweisen, regelmäßig neue Seiten abzuholen, sondern könntest dann, wenn es etwas neues gibt, eine neue, komplette Seite raushauen. Bei 100 Meßwerten alle 2 Sekunden werden solche Seiten aber ziemlich groß.

    CLIENT PULL:
    Unschön, weil ich a) nicht weiß, wann Daten kommen (die 2 Sekunden im Beispiel sind nicht konstant) und b) die Seite nicht jedesmal neu laden will.

    Dann geht das nicht. Das, was du willst, wäre beispielsweise auch in einem Chat das Problem: Unregelmäßig sagen Leute etwas, und alle sollen es mitbekommen. HTTP ist nicht das richtige Protokoll für solche Datenverbindungen, und ein Browser nicht das richtige Anzeigeinstrument.

    CLIENT PULL mit Trick:
    Jetzt habe ich mir überlegt, in einem versteckten Frame bzw. IFrame die neusten Daten per Client Pull zu holen und dann diese per DHTML dynamisch an die Tabelle zu fügen. Dies finde ich nicht besonders elegant und außerdem ist es fraglich, ob das auch wirklich überall klappt. Gerade bei Opera und DHTML brallen zwei Welten aufeinander...

    Eben, das dürfte mit Opera garnicht gehen. Abgesehen davon hättest du möglicherweise ein Laufzeitproblem. Wenn der Browser regelmäßig (zeitlich gesteuert) neue Daten vom Server abholt und der Tabelle hinzufügt: Was passiert, wenn das Seitenladen der versteckten Hinzufüge-Seite noch nicht abgeschlossen ist, bevor die Zeit um ist? Daten würden verloren gehen.

    Andererseite: Wenn die Seite automatisch neu lädt, wenn alle Eintragungen abgeschlossen sind, in der Zwischenzeit aber zuviele neue Daten eingetroffen sind, so daß die nächste Seite wesentlich größer wird, und die übernächste Seite noch viel größer - dann geht irgendwann garnichts mehr.

    AUSGABE UNGEPUFFERT RAUSSCHRIEBEN:
    Dazu habe ich ein kleines Demo, das aber irgendwie nicht das tut, was es soll:

    Tja, das ist etwas tricky mit dem ungepufferten Rausschreiben. Ich hab von JSP keine Ahnung, wie es da gehen könnte.

    Du mußt aber bedenken: Manche Browser schreiben, auch wenn sie die Daten schon haben, nur zeilen- oder absatzweise (Netscape 4 beispielsweise), oder sie warten auf einen etwas größeren Datenblock, um was zu tun.

    Und natürlich mußt du mit den üblichen Browserverhaltensweisen kämpfen: Eine Tabelle wird erst dargestellt, wenn sie komplett geladen ist und </table> empfangen wurde etc.

    Insgesamt kann ich mir irgendwie nicht so recht vorstellen, daß für deine Anforderungen ein nackter Browser geeignet ist. 100 Meßwerte wollen ja irgendwie dargestellt werden - und ich kann mir kaum vorstellen, daß jemand das überblickt, wenn alle 2 Sekunden weitere 100 Werte eintrudeln.

    Ein Java-Applet (welches auch ganz andere Möglichkeiten der Client-Server-Kommunikation hat) wäre da ganz sicher besser - wenn du keinen eigenständigen Client schreiben willst. Dann kannst du nämlich doch wieder Server-Push realisieren, was für die Aufgabenstellung ideal ist. Und das Applet übernimmt die Darstellung.

    - Sven Rautenberg

    1. Hallo Sven und danke!
      Hmm, jetzt bin ich ein wenig schlauer.
      Tatsächlich ist der Browser wohl nicht das richtige Werkzeug, aber es ist nun mal meine Diplomarbeit (eben der Versuch, ob soetwas geht) und da kann ich jetzt nichts mehr dran drehen. Auf jeden Fall kann ich jetzt was darüber schreiben, wofür und weshalb HTML bzw HTTP nicht geeignet ist.
      Nichtsdestotrotz suche ich weiterhin nach einer Lösung.
      Also das dynamische anhängen über verborgenen Frame ist über Bord geworfen. Die von dir geschilderte Situation hatte ich gar nicht bedacht und ist wohl als KO-Kriterium ausreichend.
      Server-Push ist wohl auch gegessen.
      D.h. es wird wohl CLient-Pull (tja, wenn nix anderes geht, dann eben hässlich) oder das ungepufferte rausschreiben.
      Vielleicht ließt das ja der ein oder andere Java-(Servlet-)-Crack und kennt die Lösung.
      Ansonsten hab ich da noch etwas von Keep-Alive-Verbindungen aufgeschnappt. Wäre das ne Möglichkeit?

      Oh je, Fragen über Fragen und wer weiß; vielleicht sogar mit ein paar Antworten.

      Auf jeden Fall danke!