trunx: in einem Netzwerk vom Server aus Clients steuern

Hallo Forum,

ich möchte gern ein kleines Computer-Netzwerk (bestehend aus einem Server und zwei Clienten) so einrichten, dass man vom Server aus ein Programm laufen lässt (vorzugsweise php), welches seine Ausgaben wahlweise zum einen bzw. zum anderen Client-Rechner schickt. Das wird ua. eine Eingabemaske sein (empfiehlt es sich da eine Browser-Instanz zu öffnen und die Ausgabe als HTML zu schicken?), aber auch einfach nur Lesetext.

Wie bewerkstellige ich das? Ich hab nicht den geringsten Ansatz, nicht mal ein Stichwort zum Googeln.

wär wie immer wunderbar, wenn mir wer helfen würde :)

bye trunx

--
Die Standard-Antwort: "Bitte benutze die Forum-Suche!" macht die Forum-Suche kaputt, weil die Suche dann nämlich genau vor allem diese dämliche Standard-Antwort, also Müll liefert. Sinnvoller ist stattdessen folgende Standard-Antwort: "Dieses Thema wurde schon vielfach im Forum besprochen, siehe z.B. <a>hier</a> oder <a>da</a> oder benutze die Forum-Suche z.B. mit den Stichworten 'Stichwort1 Stichwort2'." Danke.
  1. ich möchte gern ein kleines Computer-Netzwerk (bestehend aus einem Server und zwei Clienten) so einrichten, dass man vom Server aus ein Programm laufen lässt (vorzugsweise php), welches seine Ausgaben wahlweise zum einen bzw. zum anderen Client-Rechner schickt. Das wird ua. eine Eingabemaske sein

    Das klingt für mich eher so, als wölltest Du von einem Client aus zwei Server steuern.

    (empfiehlt es sich da eine Browser-Instanz zu öffnen und die Ausgabe als HTML zu schicken?), aber auch einfach nur Lesetext.

    Vermutlich wärst Du erstaunt wenn Du wüsstest, wie viele Programme bei der Ausgabe grafischer Oberflächen der Einfachheit wegen auf HTML zurückgreifen, für dessen Darstellung dann statt eines Browsers eine eingebundene Bibliothek zuständig ist.

    Ich hab nicht den geringsten Ansatz, nicht mal ein Stichwort zum Googeln.

    Nun, es fehlt die "Butter bei den Fischen". Mir ist nicht wirklich klar, was Du willst. Vielleicht sowas?

    1. Mir ist nicht wirklich klar, was Du willst. Vielleicht sowas?

      Thema interessiert mich, aber wieso sollte der Code im verlinkten Dokument ein stream sein? Ich sehe nur eine einmalige Ausgabe:

      <?php
      header('Content-Type: text/event-stream');
      header('Cache-Control: no-cache');
      
      $time = date('r');
      echo "data: The server time is: {$time}\n\n";
      flush();
      ?> 
      

      In welcher Technik funktioniert hier im Forum die Ergänzung neuer Beiträge?

      Linuchs

      1. Tach!

        Thema interessiert mich, aber wieso sollte der Code im verlinkten Dokument ein stream sein? Ich sehe nur eine einmalige Ausgabe:

        Weil das Beispiel bei w3schools ziemlich sinnfrei ist. Das Beispiel im MDN ist schon eher zu gebrauchen.

        Ein Stream ist es, weil ständig Daten fließen und nicht nur das herkömmliche Request-Response-Forget-Spielchen von HTTP zum Einsatz kommt.

        In welcher Technik funktioniert hier im Forum die Ergänzung neuer Beiträge?

        WebSockets (und DOM-Manipulation)

        dedlfix.

      2. Thema interessiert mich, aber wieso sollte der Code im verlinkten Dokument ein stream sein? Ich sehe nur eine einmalige Ausgabe:

        Dann warte mal 10 Sekunden oder passe das PHP-Skript an:

        <!DOCTYPE html>
        <html>
        <!-- FILE: /var/www/Tests/Server-Sent-Events.html -->
        <body>
        
        <h1>Getting server updates</h1>
        <div id="result"></div>
        
        <script>
        if(typeof(EventSource) !== "undefined") {
            var source = new EventSource("Server-Sent-Events.php");
            source.onmessage = function(event) {
                document.getElementById("result").innerHTML = event.data;
            };
        } else {
            document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
        }
        </script>
        
        </body>
        </html>
        

        "Sender":

        <?php
        ## FILE: /var/www/Tests/Server-Sent-Events.php
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache');
        $time = date('r');
        echo "retry: 1000\n";
        echo "data: The server time is: {$time}\n\n";
        flush();
        ?>
        

        Wobei das nichts ist, was man nicht auch mit einem gewöhnlichem XHR-Request hinbekommt, bei welchem man die Daten (data: ...) und die Metainformationen (retry: ..., id: ....) brav in JSON verpackt.

        1. vielen Dank für eure Antworten,

          ich versuche meinen Wunsch etwas anders zu formulieren: das Ganze soll ein Versuchsdesign sein. Ich hätte gern drei Rechnerplätze, an denen je ein Mensch sitzt. An einem Rechner/Server sitzt der Versuchsleiter und verschickt an die Probanden/Clients Aufgaben (also Texte, Bilder und/oder Formulare). UZ. je nachdem wie die Probanden agieren. Wichtig ist dabei, dass die Aufgaben synchron an beide Clients verschickt werden, es bringt für den Versuch nichts, wenn sich die Probanden die Aufgaben holen müssten. Die Funktionen auf den Client-Rechnern soll stark beschränkt sein, weshalb ich eig gern auf einen Browser verzichten würde. Einzig das Ausfüllen und Abschicken des Formulars soll möglich sein (und dessen Werte sollen als Datensatz natürlich auf dem Server gespeichert werden).

          Da ich nur Webseiten mit php und HTML usw. programmieren kann, wird es wohl in diese Richtung zusammen mit websocket laufen. Trotzdem wäre ich für andere Ideen und Blickwinkel dankbar.

          Wird es dadurch etwas klarer, was ich suche?

          --
          Die Standard-Antwort: "Bitte benutze die Forum-Suche!" macht die Forum-Suche kaputt, weil die Suche dann nämlich genau vor allem diese dämliche Standard-Antwort, also Müll liefert. Sinnvoller ist stattdessen folgende Standard-Antwort: "Dieses Thema wurde schon vielfach im Forum besprochen, siehe z.B. <a>hier</a> oder <a>da</a> oder benutze die Forum-Suche z.B. mit den Stichworten 'Stichwort1 Stichwort2'." Danke.
          1. Ich habe noch eine ähnliche Idee in der Schublade.

            Chor-Mitglieder könnten bei Chorproben (ggfs. auch Auftritt) ihre Lieder auf das Tablet bekommen.

            Der Dirigent oder Notenwart "sendet" die Lieder, die geprobt werden. Dann entfällt das unselige Blättern in der Notenmappe.

            Dazu die Frage: Was bedeutet retry: 1000 des Senders an den Client?

            A: "Ich melde mich wieder nach 1 sec"

            B: Hey, Client, ruf mich wieder an nach 1 sec"

            Ich habe das locker umgestellt auf 10 sec. Wenn aber der Client anfragen muss, ist es doch kein PUSH, sondern ein PULL.

            Ich möchte senden, wenn es etwas Neues gibt. Aber sind die Clients mit dieser Technik jederzeit auf Empfang?

            Linuchs

            1. Dazu die Frage: Was bedeutet retry: 1000 des Senders an den Client?

              "Wiederhole in 1000 Millisekunden."

            2. Ich möchte senden, wenn es etwas Neues gibt. Aber sind die Clients mit dieser Technik jederzeit auf Empfang?

              Tja. Das wird komplizierter.

              PHP-Skript:

              prüfen ob ein get-Parameter mit crc32 oder md5-Hash gesendet wurde. Wenn nicht für $oldCRC32 false annehmen Daten lesen, crc32 oder md5-Hash bilden. Hash mit gesendeten bzw, angenommen vergleichen: (Du darfst Syntaxfehler selbst bereinigen.)

              <?php
              header('Content-Type: text/json');
              header('Cache-Control: no-cache');
              $out['retry']=1000;
              
              if ( ! isset($_GET['crc32']) ) {
                  $oldCRC32=false;
              } else {
                  $oldCRC32=$_GET['crc32'];
              }
              
              $text=file_get_contents('file.txt');
              $newCRC32=crc32($text);
              
              if (false===$oldCRC32 or $newCRC32 != $oldCRC32) {
                 $out['data']=$text;
                 $out['crc32']=$newCRC32;
              } else {
                 header('Content-Type: text/json');
                 header('Cache-Control: no-cache');
                 $out['crc32']=$oldCRC32;
              }
              
              echo json_encode($out);
              

              Dann musst Du das Zeug nur in JS auswerten und die CRC32-Summe an den Request als Parameter anhängen.

              Du kannst die crc32-summe auch in eine Datei schreiben, musst dann aber daran denken immer diese Datei mit zu ändern oder zu löschen und dann durch Dein Skript neu anlegen zu lassen.

            3. Tach!

              Ich möchte senden, wenn es etwas Neues gibt. Aber sind die Clients mit dieser Technik jederzeit auf Empfang?

              Nein, jedenfalls nicht, wenn du das PHP-Script nach einer Anfrage beendest. Server können mit keiner Technik (bezogen auf HTTP) zuverlässig Verbindungen zu Clients aufbauen. Das verhindern Techniken wie NAT und Proxy. Der Verbindungsaufbau muss vom Client aus erfolgen. Der Server kann lediglich die Verbindung bis zum Timeout offenhalten. Wenn du PHP auf der Serverseite hast, heißt das, dass das PHP-Script nicht beendet werden darf, wenn du sofort etwas an den Client senden möchtest und nicht warten möchtest, bis der den nächsten Pull macht.

              Und dann ist außerdem noch die große Frage, wie das PHP-Script Änderungen feststellen soll, aufgrund derer etwas zum Client geschickt werden muss.

              dedlfix.

              1. Nein, jedenfalls nicht, wenn du das PHP-Script nach einer Anfrage beendest. Server können mit keiner Technik (bezogen auf HTTP) zuverlässig Verbindungen zu Clients aufbauen. Das verhindern Techniken wie NAT und Proxy. Der Verbindungsaufbau muss vom Client aus erfolgen. Der Server kann lediglich die Verbindung bis zum Timeout offenhalten. Wenn du PHP auf der Serverseite hast, heißt das, dass das PHP-Script nicht beendet werden darf, wenn du sofort etwas an den Client senden möchtest und nicht warten möchtest, bis der den nächsten Pull macht.

                Und dann ist außerdem noch die große Frage, wie das PHP-Script Änderungen feststellen soll, aufgrund derer etwas zum Client geschickt werden muss.

                sprich, es müsste in einer anderen Sprache programmiert werden?

                --
                Die Standard-Antwort: "Bitte benutze die Forum-Suche!" macht die Forum-Suche kaputt, weil die Suche dann nämlich genau vor allem diese dämliche Standard-Antwort, also Müll liefert. Sinnvoller ist stattdessen folgende Standard-Antwort: "Dieses Thema wurde schon vielfach im Forum besprochen, siehe z.B. <a>hier</a> oder <a>da</a> oder benutze die Forum-Suche z.B. mit den Stichworten 'Stichwort1 Stichwort2'." Danke.
                1. Hi,

                  Nein, jedenfalls nicht, wenn du das PHP-Script nach einer Anfrage beendest. Server können mit keiner Technik (bezogen auf HTTP) zuverlässig Verbindungen zu Clients aufbauen. Das verhindern Techniken wie NAT und Proxy. Der Verbindungsaufbau muss vom Client aus erfolgen. Der Server kann lediglich die Verbindung bis zum Timeout offenhalten. Wenn du PHP auf der Serverseite hast, heißt das, dass das PHP-Script nicht beendet werden darf, wenn du sofort etwas an den Client senden möchtest und nicht warten möchtest, bis der den nächsten Pull macht.

                  Und dann ist außerdem noch die große Frage, wie das PHP-Script Änderungen feststellen soll, aufgrund derer etwas zum Client geschickt werden muss.

                  sprich, es müsste in einer anderen Sprache programmiert werden?

                  nein, das Problem ist von der Sprache weitgehend unabhängig. Das Problem liegt in der Natur von Client/Server-Systemen.

                  Ein Server ist eine Software, die auf Anfragen wartet und darauf reagiert; ein Client ist die Software auf der Gegenseite, die was vom Server will. Mit deiner Aufgabenstellung drehst du die Rolle aber um. In deinem Szenario sind eigentlich die Rechner der beiden Versuchspersonen die Server, denn die sollen darauf warten, dass der Rechner des Versuchsleiters (hier der Client) sich meldet und ihnen Daten schickt, und darauf sollen sie reagieren, indem sie den Teilnehmern die Aufgaben anzeigen und nach dem Lösen die Ergebnisse zurücksenden.

                  Dafür ist aber ein Webserver als zentrale Komponente ziemlich ungeeignet. Klar kann man die Server- und Client-Rolle technisch so beibehalten, wie du es dir ursprünglich vorgestellt hast - und dann mit Krücken wie zyklischem Polling die Clients regelmäßig beim Server nachfragen lassen, ob's endlich was Neues gibt.

                  Mit dem EventSource-Objekt kann man das etwas entspannen - da meldet sich der Client sozusagen beim Server und fordert, "Sag mir Bescheid, wenn's was gibt", und hält die Verbindung dann offen. Aber dazu muss natürlich am Server das Script permanent laufen und nicht, wie im Webserver-Umfeld üblich, nach dem Request sofort enden. Es wäre eine etwas andere Philosophie als üblich.

                  Fazit: Deine Aufgabe, die anfangs so einfach klingt, ist alles andere als trivial.

                  So long,
                   Martin

                  --
                  Nothing travels faster than the speed of light with the possible exception of bad news, which obeys its own special laws.
                  - Douglas Adams, The Hitchhiker's Guide To The Galaxy
                2. Tach!

                  sprich, es müsste in einer anderen Sprache programmiert werden?

                  Nein, nicht unbedingt. Man kann nur nicht den üblichen Mechanismus verwenden, für den das PHP erfunden wurde: Einbettung im Webserver (egal ob Modul oder (F)CGI). Das geht allen Systemen so, die nur auf Request-Response-Erledigt ausgelegt sind. Der derzeitge Stand der Technik ist WebSockets. Das kann man auch serverseitig mit PHP hinbekommen, man muss nur ein PHP-Script als Server laufen haben. Dazu benötigt man noch einen Webserver, der die WebSocket-Verbindungen an das Server-Script weiterleiten kann.

                  Die wenigsten Probleme bekommt man meiner Meinung nach, wenn man die Sache mit ASP.NET angeht. Dafür gibt es ein Package namens SignlR. Das kann nicht nur WebSocket, sondern auch Fallback-Mechanismen. Und es nimmt einem die Drecksarbeit ab. WebSocket ist nur die Verbindung. Wenn man darüber Daten austauschen möchte, muss man sich noch ein Protokoll überlegen, ein vorhandenes implementieren oder eine Bibliothek suchen. Mit SignlR arbeitet man schon eine Ebene weiter oben. Man ruft Methoden auf und übergibt denen Daten. Und am anderen Ende bindet man eine Funktion mit gleicher Signatur an SignlR an. Die Serverseite läuft auch ständig, weil das ASP.NET eine Anwendung erzeugt, die mehr oder weniger im IIS eingebettet wird und es nicht nur Scripts sind, die bei Bedarf gestartet werden.

                  Das hört sich, so wie ich das gerade geschrieben habe, gar nicht mal so schlecht an. Aber ganz so einfach ist es dann doch nicht, wenn man so gar keine Erfahrung mit ASP.NET und C# oder zur Not auch VB.NET hat.

                  dedlfix.

        2. Habe versucht, das hier einzubauen, die erste Veranstaltung auf der Seite soll ständig neu geladen werden:

          http://remso.eu

          Mit dem Beispiel der Zeit von http://remso.eu/500/stream_sender.php klappt das prima.

          Aber der gewünschte Inhalt von http://remso.eu/500/p510lm.php wird nicht gezeigt. Da muss es also eine mir noch unbekannte Randbedingung geben.

          Die wäre?

          Linuchs

          1. Ich denke, data: darf nur eine Zeile sein? Habe ich geändert, jetzt klappt's mit dem Anzeigen der Veranstaltung.

            Linuchs

            1. Tach!

              Ich denke, data: darf nur eine Zeile sein? Habe ich geändert, jetzt klappt's mit dem Anzeigen der Veranstaltung.

              Und nun probier das mal im Internet Explorer.

              Wenn man die offizielle Dokumentation sucht, kommt man zu einem Hinweis, dass sich grad niemand um diese API kümmert. Ich würde darauf nicht bauen. Das ist im Prinzip nur ein etwas besserer Pull-Mechanismus. Wenn WebSockets nicht geht (zum Beispiel wegen nicht erfüllbarer technischer Voraussetzungen), kann man auch irgendeinen anderen Pull-Mechanismus verwenden. Ein solcher lässt sich mit einem Timer und Ajax recht einfach grundlegend aufsetzen.

              dedlfix.

              1. Und nun probier das mal im Internet Explorer.

                Bin ich Jesus? Kann ich Lahme zum Laufen bringen?

                Dann bleibt die beim Laden der Seite vorhandene Info eben im Rollstuhl sitzen, das kennen die IE-Betreiber doch nicht anders frechgrins

                1. Und nun probier das mal im Internet Explorer.

                  Bin ich Jesus? Kann ich Lahme zum Laufen bringen?

                  Den hier schon:

                  <!DOCTYPE html>
                  <html>
                  <body>
                  <!-- FILE: /var/www/Tests/Server-Sent-Json.html -->
                  <h1>Getting server updates</h1>
                  <div id="result"></div>
                  
                  <script>
                  function ServerEvents() {
                      var data;
                      var xmlHttp = new XMLHttpRequest();
                      if (xmlHttp) {
                          xmlHttp.open('GET', 'Server-Sent-Json.php', true);
                          xmlHttp.onreadystatechange = function () {
                              if (xmlHttp.readyState == 4) {
                                  data=JSON.parse(xmlHttp.responseText);
                                  window.setTimeout("ServerEvents()", data['retry']);
                                  document.getElementById("result").innerHTML=data['data']
                              }
                          };
                          xmlHttp.send(null);
                      }
                  }
                  ServerEvents();
                  </script>
                  </body>
                  </html>
                  
                  <?php
                  ## FILE: /var/www/Tests/Server-Sent-Json.php
                  header('Content-Type: text/json');
                  header('Cache-Control: no-cache');
                  $out['data'] = 'The server time is: ' . date('r');
                  $out['retry'] = 1000;
                  echo json_encode($out);
                  flush();
                  ?>