Fabian: Wie Chat updaten?

Hallo!

Das Prinzip eines Chats habe ich bereits realisiert, jedoch bin ich mir noch nicht sicher, wie ich bei den Teilnehmern die Chat-Anzeige updaten soll.

Ich habe mir überlegt, dass ich einen "Hidden-Frame" verwende, der jede Sekunde (oder so ähnlich) per PHP-Script überprüft, ob sich seit dem letzten Einlesen etwas geändert hat ( = jemand hat etwas geschrieben). Gibt es elegantere Methoden? Bei meiner Idee sehe ich als Problem die Performance (dass ich jede Sekunde auf Änderungen überprüfe - wobei eine Änderungsüberprüfung ja eigentlich bei jeder Lösung stattfinden muss- oder?!) und dass manche Browser dann jede Sekunde einen Ladebalken anzeigen und der InternetExplorer sein cooles Reload-Klicken bringt ;-) ).

MfG
Fabian

PS: Ich habe mir mal so einen OpenSource-Chat angeschaut, allerdings ist der so umfangreich, dass die betreffende Stelle nicht so ohne Weiteres auffindbar ist und wahrscheinlich ohnehin an mehreren Stellen bestimmte Bedingungen erfüllt sein müssen...

  1. Ich grüsse den Cosmos,

    Gibt es elegantere Methoden?

    Such mal unter dem Stichwort "Streaming Chat"
    Es wird die HTML-Seite nie fertig geladen, das heisst, sie lädt ewig und dadurch kannst du immer neue Zeilen senden. Wenn keien Eingaben der User erfolgen sendest du halt was anderes, z.B. ein Leerzeichen.

    Möge das "Self" mit euch sein

    --
    Fragt ein Atom das andere: Hast du mein Elektron gesehen? Ich bin heute so positiv.
    ie:{ br:> fl:| va:| ls:& fo:{ rl:( n4:{ de:] ss:) ch:? js:| mo:) sh:( zu:)
  2. Hi,

    Das Prinzip eines Chats habe ich bereits realisiert, [...]

    nach der restlichen Beschreibung zu ureteilen, anscheinend über HTTP.

    Gibt es elegantere Methoden?

    Ja, ein anderes Protokoll. Denn HTTP funktioniert nach dem Prinzip "Anfrage, Antwort, danke". Das heißt, der Client fordert Daten vom Server an, bekommt diese Daten, und damit ist die Verbindung beendet. Wie du selbst schon festgestellt hast, muss der Client von sich aus permanent nachfragen: "Gibt's was Neues?", und das erzeugt unnötig viel Traffic. Die von Manuel vorgeschlagene Lösung, ein "endlos langes" Dokument zu übertragen, ist auch nur ein Notbehelf, auf den nicht alle Browser wie gewünscht reagieren. Entweder sie puffern die Ausgabe und zeigen sie nur schubweise an, wenn es sich endlich lohnt; oder sie brechen gar nach einiger Zeit die Verbindung ab.

    Die bessere Lösung ist, ein Protokoll zu nutzen, bei dem der Server von sich aus neue Daten an den Client sendet, sobald welche vorliegen. Dazu braucht es aber auch eine clientseitig laufende Software, die auf diese Daten reagiert. Ein normaler Browser würde das nicht tun. Die Lösung könnte ein Java-Applet oder ein Flash-Objekt sein - oder eben ein spezielles Programm wie ein "richtiger" Chat-Client.

    [...] und der InternetExplorer sein cooles Reload-Klicken bringt ;-) ).

    Was für ein Klicken? Habe zwar schon öfter gelesen, dass jemand das erwähnt hat, aber noch nie verstanden, was die Leute wirklich meinen bzw. woher das kommen soll.

    So long,
     Martin

    --
    Es sagte...
    ein korpulenter Lehrer zu einem Schüler, der ihn ein Fass genannt hatte: "Nein. Ein Fass ist von Reifen umgeben, ich dagegen von Unreifen."
    1. Ich grüsse den Cosmos,

      Entweder sie puffern die Ausgabe und zeigen sie nur schubweise an, wenn es sich endlich lohnt; oder sie brechen gar nach einiger Zeit die Verbindung ab.

      Welche Browser verhalten sich denn so? Im Konqueror, im IE, im FF/Netscape und im Opera machen Web-Chats auf Streamingbasis keine Probleme.
      Wäre aber gut zu wissen, da ich eine "Tail-Emulation" auf Streamingbasis bauen wollte, die dann evtl. die gleichen Probleme haben könnte.

      Möge das "Self" mit euch sein

      --
      Fragt ein Atom das andere: Hast du mein Elektron gesehen? Ich bin heute so positiv.
      ie:{ br:> fl:| va:| ls:& fo:{ rl:( n4:{ de:] ss:) ch:? js:| mo:) sh:( zu:)
      1. Hallo Manuel,

        Entweder sie puffern die Ausgabe und zeigen sie nur schubweise an, wenn es sich endlich lohnt; oder sie brechen gar nach einiger Zeit die Verbindung ab.

        Welche Browser verhalten sich denn so? Im Konqueror, im IE, im FF/Netscape und im Opera machen Web-Chats auf Streamingbasis keine Probleme.

        Opera (8.x) scheint zu puffern. Wenn der Server langsam ist, erfolgt eine Weile keine Änderung der Anzeige, dann kommt plötzlich wieder ein ganzer Schwall. Könnten -nur grob geschätzt- ungefähr 4kB-Häppchen sein.
        Und beim IE (5.x, 6.0) habe ich schon mehrmals erlebt, dass er von sich aus den Ladevorgang einfach abbricht, wenn eine gewisse Zeit keine Daten mehr vom Server gesendet werden.

        Das sind jetzt Beobachtungen beim Laden ganz normaler Webseiten, aber das Verhalten dürfte bei derart realisierten Chats wohl entsprechend sein.

        Wäre aber gut zu wissen, da ich eine "Tail-Emulation" auf Streamingbasis bauen wollte, die dann evtl. die gleichen Probleme haben könnte.

        Ich bin auf die ersten Tests gespannt, befürchte aber, dass es nicht ohne Schwierigkeiten zu realisieren ist.

        So long,
         Martin

        --
        TEAM: Toll, Ein Anderer Macht's.
        1. Ich grüsse den Cosmos,

          Und beim IE (5.x, 6.0) habe ich schon mehrmals erlebt, dass er von sich aus den Ladevorgang einfach abbricht, wenn eine gewisse Zeit keine Daten mehr vom Server gesendet werden.

          Bei Tests damals für die Entwicklung eines Chats auf JAVA-Basis gabs keine Probleme, da ich jede Sekunde zumindest ein Leerzeichen gesendet hab. Seltenst abbrüche und kein Puffern.
          Allerdings hab ich in der Richtung schon lange nichts mehr gemacht, vielleicht gibt es mittlerweile Probleme.

          Ich bin auf die ersten Tests gespannt, befürchte aber, dass es nicht ohne Schwierigkeiten zu realisieren ist.

          Da überleg ich ja, ob ich nicht bei meiner AJAX-Variante bleib und die ein wenig ausarbeite. Alleine schon, wenn es Probleme geben _kann_ ist eine komplette Umstrukturierung schon nichtmehr sinnvoll. Ich lass mir das Ganze nochmal durch den kopf gehen.

          Möge das "Self" mit euch sein

          --
          Fragt ein Atom das andere: Hast du mein Elektron gesehen? Ich bin heute so positiv.
          ie:{ br:> fl:| va:| ls:& fo:{ rl:( n4:{ de:] ss:) ch:? js:| mo:) sh:( zu:)
    2. Hallo,

      Die bessere Lösung ist, ein Protokoll zu nutzen, bei dem der Server von sich aus neue Daten an den Client sendet, sobald welche vorliegen. Dazu braucht es aber auch eine clientseitig laufende Software, die auf diese Daten reagiert. Ein normaler Browser würde das nicht tun. Die Lösung könnte ein Java-Applet oder ein Flash-Objekt sein - oder eben ein spezielles Programm wie ein "richtiger" Chat-Client.

      Hmm, eigentlich möchte ich weder Flash noch Java-Applets in meine Seite einbauen. Die Lösung von Manuel habe ich mal in einer Demo getestet, jedoch ist sie, wie du bereits sagtest, eher suboptimal.
      Ich habe mir mal den HTTP-Chat der Seite www.freewar.de angeschaut, da ich diesen recht gut implementiert respektive umgesetzt finde und die Seite, genau wie meine, auf PHP und JavaScript zurückgreift. Leider verstehe ich den Source nicht so ganz, aber vielleicht könnt ihr ihn mir ja erklären :-)

      Also der Aufbau des Framesets wird folgendermaßen bewerkstelligt:

        
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">  
      <html>  
      <head>  
      <title>Freewar.de - Welt 3</title>  
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">  
      <script>if(ProxSuccessStartCode) { document.location.href='frset.php?uclocal=1'; }</script></head>  
        
      <frameset rows="*" cols="*,280" framespacing="0" frameborder="no" border="0">  
        <frameset rows="*,200" cols="*" framespacing="0" frameborder="NO" border="0">  
       <frameset rows="75,*" cols="*" framespacing="0" frameborder="NO" border="0">  
        <frame src="banner.php" name="bannerFrame" scrolling="NO">  
           <frame src="main.php" name="mainFrame" scrolling="auto">  
        
          </frameset>  
          <frameset rows="*,0" cols="*" framespacing="0" frameborder="NO" border="0">  
            <frameset rows="*,35" cols="*" framespacing="0" frameborder="NO" border="0">  
              <frame src="chattext.php#bancor" name="chattextFrame" frameborder="no" scrolling="auto" noresize>  
              <frame src="chatform.php" name="chatformFrame" scrolling="NO" noresize>  
            </frameset>  
            <frameset rows="*,0" cols="*" framespacing="0" frameborder="NO" border="0">  
             <frame src="refresh.php" name="reloadChatFrame" scrolling="NO" noresize>  
             <frame src="chatupdate.php" name="chatupdateFrame" scrolling="NO" noresize>  
        
         </frameset>  
          </frameset>  
        </frameset>  
        <frameset rows="*,375" cols="*" framespacing="0" frameborder="NO" border="0">  
          <frame src="item.php" name="itemFrame" frameborder="no" scrolling="auto" noresize>  
       <frameset rows="*,50" cols="*" framespacing="0" frameborder="NO" border="0">  
            <frame src="map.php" name="mapFrame" scrolling="NO" noresize>  
             <frame src="menu.php" name="menuFrame" scrolling="NO" noresize>  
          </frameset>  
        
        </frameset>  
      </frameset>  
      <noframes><body>  
      Sie muessen einen Broswer verwenden der Frames unterstuetzt um FreeWar zu spielen.  
      </body></noframes>  
      </html>  
      
      

      Die für den Chat relevanten Frames sind offensichtlich chattextFrame, chatformFrame, reloadChatFrame und chatupdateFrame, wobei für das Update der Anzeige scheinbar die beiden letzteren verantwortlich sind.
      Den Code dieser Seiten habe ich mir mal angeschaut (zumindest das, was der Server mir von den PHP-Files ausliefert):
      Frame: reloadChatFrame (Datei refresh.php):

        
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
      <html>  
      <head>  
      <title>Unbenanntes Dokument</title>  
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">  
      </head>  
        
      <body onLoad="init();">  
      [code lang=javascript]  
      <script language="JavaScript">  
      function getHTTPObject()  
      {  
          var xmlhttp;  
          try  
          {  
              xmlhttp = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");  
          }  
          catch (e)  
          {  
              alert('ActiveX Elemente wurden im Browser deaktiviert. Bitte aktiviere ActiveX in den Sicherheitseinstellungen deines Browsers. Folgendes muss z.B. im Internet Explorer aktiviert sein: Extras->Internetoptionen->Sicherheit->Stufe anpassen->ActiveX-Steuerelemente ausführen, die für Scripting sicher sind - aktivieren.');  
          }  
          return xmlhttp;  
      }  
        
      var httpReloadChat = getHTTPObject();  
        
      function init()  
      {  
          pollStatus();  
      }  
        
      function pollStatus()  
      {  
          if(httpReloadChat.readyState == 4 || httpReloadChat.readyState == 0)  
       {  
              var ran_unrounded=Math.random()*100000000;  
              var ran_number=Math.round(ran_unrounded);  
             httpReloadChat.open("GET",'rel_files/47963.htm?dynamicid='+ran_number, true);  
           httpReloadChat.onreadystatechange = handleChatReload;  
          httpReloadChat.send(null);  
       }  
      }  
        
      function handleChatReload()  
      {  
          if(httpReloadChat.readyState == 4)  
          {  
              window.setTimeout('pollStatus()', 1500);  
              if(httpReloadChat.responseText.length==1)  
              {  
                  parent.chatupdateFrame.location.href = "chatupdate.php";  
              }  
          }  
      }  
        
      </script>  
      
      

      </body>
      </html>
      [/code]

      Frame: chatupdateFrame (Datei chatupdate.php, beim Anschauen des Sources übrigens geladen per chatupdate.php?stoperror=1)

        
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
      <html>  
      <head>  
      <title>Unbenanntes Dokument</title>  
      <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">  
      </head>  
        
      <body>  
      [code lang=javascript]  
      var IE = document.all ? 1:0;  
      parent.chattextFrame.add('', 0);  
      if (IE)  
      {  
          if(parent.mainFrame.formular.block_reload.value != 'true')  
           parent.mainFrame.location.href = 'main.php';  
      }  
      else  
      {  
          if(parent.frames.mainFrame.document.formular.block_reload.value != 'true')  
           parent.frames.mainFrame.location.href = 'main.php';  
      }  
      </script>  
      
      

      </body>
      </html>
      [/code]

      Also so wie ich das sehe, ist die Datei chatupdate.php dafür zuständig, das eigentliche Chat-Fenster neu zu laden, sobald chatupdate.php selbst neu geladen wird (der Umweg über chatupdate.php zum Laden von main.php anstatt direkt main.php neu zu laden, scheint  darin begründet, dass man zwischen Browsern unterscheiden kann und das Neuladen auch unterbinden kann). Dieser Source ist relativ einfach zu verstehen.
      Mehr Probleme bereitet mir die Datei refresh.php:
      Wenn ich es richtig verstehe, stellt bei Nicht-IE-Browsern die Variable httpReloadChat eine Referenz auf ein XMLHttpRequest-Objekt und bei IE-Browser eine auf ein ActiveXObject dar (implementiert in der Funktion getHTTPObject). Danach scheint das Prinzip in etwa das zu sein, was ich in meinem Eröffnungspost dieses Threads vorgeschlagen habe:
      Alle 1,5 Sekunden (siehe Funktion handleChatReload: window.setTimeout('pollStatus()', 1500)) wird in der Funktion pollStatus httpReloadChat mit dem Inhalt der Datei rel_files/47963.htm befüllt (wobei der Name der zu lesenden Datei wahrscheinlich mit PHP immer wieder verändert wird). Der Sinn der generierten DynamicID entzieht sich mir leider, was das Verständnis des Codes erschwert. Jedenfalls enthält die Datei rel_files/47963.htm eine 1 als Inhalt, wenn man sie ohne jegliche Parameter mit dem Browser öffnet. Damit hätte der Inhalt von httpReloadChat die Länge 1, was die Abfrage im Event-Handler handleChatReload() (if(httpReloadChat.responseText.length==1)) wahr werden ließe- oder von was ist responseText abhängig? Mit httpReloadChat.send(null) wird wohl einfach ein Event für den Event-Handler gefeuert, oder?

      Einige Dinge sind mir also noch unklar, wodurch mir eine Implementierung anhand des vorhandenen Source-Codes unmöglich ist. Könnt ihr meine Fragen beantworten (speziell den Sinn der DynamicID und ob ich den Code ansonsten richtig verstanden habe, oder etwas übersehen habe. Ließe sich der Chat so implementieren? Und ist responseText.length tatsächlich abhängig von der Länge des Inhalts der Datei rel_files/47863.htm?) ?

      MfG
      Fabian

      PS:

      [...] und der InternetExplorer sein cooles Reload-Klicken bringt ;-) ).

      Was für ein Klicken? Habe zwar schon öfter gelesen, dass jemand das erwähnt hat, aber noch nie verstanden, was die Leute wirklich meinen bzw. woher das kommen soll.

      Der InternetExplorer hat die nervige Eigenschaft (zumindest habe ich dies schon bei mehreren IE-Usern beobachtet), dass er bei einem Reload einer Seite (also immer dann, wenn die blaue ProgressBar erscheint) so ein “Maus-Klicken” ertönen lässt.

      1. Ach so- noch was:
        Wenn anhand der Datei rel_files/47863.htm überprüft wird, ob sich etwas geändert hat (= in rel_files/47863.htm steht Inhalt von der Länge 1, z.B. die Zahl 1), woher weiß denn dann der Server, ob er eine 1 oder sonstwas reinschreiben soll? Er weiß ja nicht, ob sich für den Client was geändert hat. Ich glaube genau an dieser Stelle habe ich beim Script respektive der Logik etwas falsch verstanden... .

        MfG
        Fabian