effel: Einzelwerte über Nodeserver zum Client

Hallo an Alle,

Ich benutze den Server in Node. Es funktioniert alles gut.

Ich will direkt aus Node heraus Werte über den Server schicken (Einzelzahlen aus Berechnungen),

aber im NodeServer geht es nur über Dateien.

Also: aus einer Berechnung: Ergeb= 1.618 und das zum Client.

Wer mache ich das?

Effel

  1. Hallo,

    Ich will direkt aus Node heraus Werte über den Server schicken (Einzelzahlen aus Berechnungen), aber im NodeServer geht es nur über Dateien.

    das ist für deine Aufgabenstellung unerheblich.

    Also: aus einer Berechnung: Ergeb= 1.618 und das zum Client.

    Ja, und das geht nicht einfach so. HTTP funktioniert nach dem Prinzip: Eine Anforderung (Request) vom Client, darauf eine Antwort (Response) vom Server.

    Entweder muss also der Client die Anfrage "auf Verdacht" stellen und beliebig lange auf die Antwort warten, und bei einem HTTP-Timeout die Anfrage einfach wiederholen.

    Oder man verwendet eine Technologie wie Websockets. Das ist im Grunde dasselbe, nur sauber standardisiert.

    Einen schönen Tag noch
     Martin

    --
    Manchmal kann man gar nicht so viel fühlen, wie man denkt.
    Und manchmal fühlt man so viel, dass man gar nicht denken kann.
    1. Hallo,

      und das Schöne an Node ist – im Gegensatz zu Apache oder nginx –, dass Websockets ein eingebautes Feature sind. Long Polling als klassischer Websocket-Fallback ist nicht erforderlich.

      Es gibt im Web reichlich Beispiele dafür, unter anderem auch im Selfwiki.

      Rolf

      --
      sumpsi - posui - obstruxi
      1. Hallo Rolf,

        ich habe den Timesevice-Server aus dem wiki eingebaut.

        ich habe das nodemodul mit: npm install --save ws geladen, ist auch da. Dann habe lt.Anweisung in C:User\Administrator (dort liegen die npmModule) in die Datei package.jons eingetragen: "type": "module"

        {
          "type":"module",
          "dependencies": {import { WebSocket }from 'ws' ;
          "@svgdotjs/svg.js": "^3.1.2",
          ...
          "ws": "^8.18.3",
        }
        

        Damit ein ES6 Modul entstehe. Frage: Warum nicht require, da node ?

        Es entstand der Fehler:

        import { WebSocket }from 'ws' ;
               
        
        SyntaxError: Unexpected token '{'
            at compileSourceTextModule (node:internal/modules/esm/utils:337:16)
            at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:166:18)
            at callTranslator (node:internal/modules/esm/loader:437:14)
            at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:443:30)
            at async ModuleJob._link (node:internal/modules/esm/module_job:106:19)
        
        Node.js v22.9.0
        

        oder:

        import WebSocket from 'ws' ;
        
               ^^^^^^^^^
        
        SyntaxError: Unexpected identifier 'WebSocket'
            at compileSourceTextModule (node:internal/modules/esm/utils:337:16)
            at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:166:18)
            at callTranslator (node:internal/modules/esm/loader:437:14)
            at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:443:30)
            at async ModuleJob._link (node:internal/modules/esm/module_job:106:19)
        
        Node.js v22.9.0
        

        Außerdem ging jetzt das require in meine anderen Programmen nicht mehr !!

        Danke im voraus! Gruß Effel

        1. Hallo effel,

          {
            "type":"module",
            "dependencies": {import { WebSocket }from 'ws' ;
            "@svgdotjs/svg.js": "^3.1.2",
            ...
            "ws": "^8.18.3",
          }
          

          WTF?

          Das steht so nicht im Wiki. Guck nochmal dorthin.

          Es entstand der Fehler:

          import { WebSocket }from 'ws' ;
          SyntaxError: Unexpected token '{'
          

          Ja natürlich, wenn Du JavaScript-Code in eine JSON-Datei haust, kann das ja nur schiefgehen. import { WebSocket } from 'ws' ; gehört nicht in die package.json, sondern in dein Node-Programm.

          Ob type=module für Dich funktioniert, wenn Du noch andere Module dazu lädst, ist so eine Sache, das kann ich nicht beurteilen. Aber @svgdotjs/svg.js sieht so aus, als wäre es auch ein ES6-Modul und die Anleitung sagt, man solle es per import laden.

          Warum nicht require, da node ?

          Weil ES6-Modul, genau wie @svgdotjs/svg.js mit import eingebunden werden muss. Wie bindest Du es ein?

          Require = Altes Modulsystem (CommonJS), Import = ES6-Modulsystem.

          Außerdem ging jetzt das require in meine anderen Programmen nicht mehr !!

          Jepp, ES6-Modulsystem und CommonJS-Modulsystem vertragen sich nicht. Wie hast Du denn vor dem Hinzufügen von ws die Module geladen - insbesondere svg.js?

          Man kann CommonJS und ES6-Module mixen, das ist aber etwas Frickelei. Welche Module bindest Du mit require ein?

          Rolf

          --
          sumpsi - posui - obstruxi
          1. Da habe ich wohl etwas falsch dargestellt:

            "type":"module" sollte in die package.json

            { "type":"module", (das habe ich eingetragen)

            "dependencies": {

            "@svgdotjs/svg.js": "^3.1.2",
            
            "child_process": "^1.0.2",
            
            "child-process": "^1.0.2",
            
            "fix-esm": "^1.0.1",
            
            "jsdom": "^21.1.1",
            
            "open": "^10.1.0",
            
            "svg": "^0.1.0",
            
            "svg.js": "^2.7.1",
            
            "svgdom": "^0.1.13",
            
            "util": "^0.12.5",
            
            "ws": "^8.18.3",
            

            } }

            das unter nodejs laufende Programm, wie es im Wki steht Ohne Veränderung:

            function timeserver(){

            import { WebSocket } from 'ws' ;

            const socketServer = new WebSocket({ port:8443 });

            setInterval(() => {

            const data = JSON.stringify({'type': 'time', 'time': new

            Date().toTimeString()});

            socketServer.clients.forEach((client) => {

              client.send(data);
            

            });

            }, 500); }

            aufgerufen so:

            C:\Programme\nodejs\node.exe timeserver.js

            dann die beschriebenen Fehler

            dann bis morgen

            Effel

            1. Hallo effel,

              wenn Du meine Fragen nicht beantwortest, kommen wir nicht weiter. Ich habe dich gefragt, wie Du die übrigen Module einbindest. require oder import? Sind das ES6- oder CommonJS-Module? Das schau ich jetzt bestimmt nicht einzeln nach. Aber ich würde vermuten, du lädst alles mit require()?

              Sodann: Das import-Statement muss am Anfang eines ES6-Moduls stehen. In einer Funktion klappt das nicht. Was aber in einem CommonJS-Ökosystem (also: KEIN type=module in der package.json) geht, ist dies:

              async function timeserver(){
              
                const ws = await import('ws'),
                      socketServer = new ws.WebSocket({ port:8443 });
              
                setInterval(() => {
                  const data = JSON.stringify({
                     'type': 'time',
                     'time': new Date().toTimeString()
                  });
                  socketServer.clients.forEach((client) => {
                    client.send(data);
                  });
                }, 500);
              }
              

              Das import-Statement ist auf ES6-Module beschränkt und muss am Anfang stehen. Es wird nämlich synchron durchgeführt und der Code im Modul läuft erst los, wenn alle imports befriedigt sind.

              Aber die import-Funktion kannst Du auch ohne type=module aufrufen, sie arbeitet asynchron und liefert Dir ein Promise für das Modul-Objekt. Mit await wird gewartet, bis das Promise erfüllt (also: das Modul verfügbar) ist und dann findet man in ws die Konstruktorfunktion für den WebSocket. Das ganze muss in eine async-Funktion hinein, weil await außerhalb von Funktionen nur in ES6-Modulen erlaubt ist und das hast Du ohne type=module nicht.

              Es geht auch andersrum, mit module.createRequire kann man sich in ES6-Modulen eine require-Funktion generieren lassen. Aber was für Dich richtig ist, kann ich Dir nicht sagen, wenn Du die Details für Dich behältst.

              Rolf

              --
              sumpsi - posui - obstruxi
              1. Hallo Rolf,

                noch einmal zu meinem Problem:

                import muß am Anfang stehen - ok

                require gehr auch const WebSocketServer = require('ws');ok

                Fehler:

                in module ws/lib/websocket: (Zeile 692)

                const socketServer = new WebSocketServer({ port:8443 }); let parsedUrl; if (address instanceof URL) { parsedUrl = address; } else { try { parsedUrl = new URL(address); } catch (e) { throw new SyntaxError(Invalid URL: ${address}); } }

                SyntaxError: Invalid URL: [object Object]

                was habe ich versucht:

                npm install url 0k version in package.json "url": "^0.11.4",

                npm install URL Error

                nodejs Aktuelle Versin 24.5.0

                es scheint mir, daß url ({ port:8443 }) nicht verarbeiten kann

                was ich gefunden habe(weiß nicht mehr wo):

                In modernen Node.js (v10.0.0+) können Sie entweder die Legacy-API oder die neuere Klasse (WHATWG URL API) verwenden:URL

                BeispielHolen Sie sich Ihren eigenen Node.js Server // Using the legacy API const url = require('url');

                // Using the modern URL class (WHATWG API) const { URL } = require('url'); let url = require('url');

                habe ich Legacy-API (module)

                hast Du eine Lösung?

                Effel

                1. Hallo

                  Fehler:

                  in module ws/lib/websocket: (Zeile 692)

                  const socketServer = new WebSocketServer({ port:8443 });
                   let parsedUrl;
                    if (address instanceof URL) {
                      parsedUrl = address;
                    } else {
                      try {
                        parsedUrl = new URL(address);
                      } catch (e) {
                     throw new SyntaxError(`Invalid URL: ${address}`);
                      }
                    }
                  
                  SyntaxError: Invalid URL: [object Object]
                  

                  Was erwartest du, das passiert? Welchen Wert hat die Variable address? Die Fehlermeldung am Schluss lässt stark vermuten, dass die Verarbeitung im Else-Zweig landet und address keine URL enthält, womit new URL() scheitert.

                  Tschö, Auge

                  --
                  „Habe ich mir das nur eingebildet, oder kann der kleine Hund wirklich sprechen?“ fragte Schnapper. „Er behauptet, nicht dazu imstande zu sein“ erwiderte Victor. Schnapper zögerte (…) „Nun …“ sagte er schließlich, „ich schätze, er muss es am besten wissen.“ Terry Prattchett, Voll im Bilde
                  1. ja es ist so,

                    adress hat den "wert" port:8443

                    von const socketServer = new WebSocketServer({ port:8443 });

                    habe einige Beispeile gefunden, wo die Einrichtung von WebsocketServer ähnlich aussah, also nur ({ port: (die PortNr) })

                    ist mir auch sehr unverständlich!

                    Effel

                2. Hallo effel,

                  lass uns das nochmal sortieren. Und zuerst: Wenn Du Code postest, dann schreibe in die Zeile davor bitte ~~~js und dahinter ein ~~~. Dadurch bleiben die Zeilen erhalten und es gibt ein JavaScript-Syntaxhighlighting. Für andere Sprachen muss js durch das entsprechende Sprachkürzel ersetzt werden, z.B. html, css, php, sql.

                  Du hast new WebSocketServer({ port: 8443}) und den Rest direkt hintereinander geschrieben. Aber so wie ich das sehe, ist diese Zeile dein Code und der Rest ist aus den Tiefen des ws-Moduls.

                  Generell muss dieser Aufruf funktionieren, ich habe das timeservice-Beispiel bei mir laufen lassen und es hat funktioniert.

                  Die Angabe {port:8443} ist keine URL, das ist richtig. Es muss erst eine draus werden. Wenn der Server nur einen Port bekommt, dann lauscht er auf diesen Port von localhost, und dein Client muss dementsprechend ws://localhost:8443 als URL für den WebSocket angeben.

                  Was mich wundert: Im ganzen lib-Ordner des ws-Moduls steht nirgends new WebSocket, und das wäre die einzige Möglichkeit, wie die initAsClient-Methode aufgerufen werden könnte. Ich glaube deshalb, dass zwischen dem new WebSocketServer-Aufruf und der Fehlermeldung keine Beziehung besteht.

                  Könntest du das bitte genauer beschreiben? Erzeugt dein node-Programm einen Websocket-Client?! So richtig ist mir nicht klar, was Du da gemacht hast.

                  Rolf

                  --
                  sumpsi - posui - obstruxi
                  1. Hallo Rolf

                    aus dem selfhtml wiki habe ich das entnommen:

                    (Server-Implementierung mit node.js,Ein Zeitanzeigeservice)

                    import { WebSocketServer } from 'ws';
                    
                    const socketServer = new WebSocketServer({ port:8443 });
                    
                    setInterval(() => {
                       const data = JSON.stringify({'type': 'time', 'time': new Date().toTimeString()});
                       socketServer.clients.forEach((client) => {
                          client.send(data);
                       });
                    }, 1000);
                    

                    statt import habe ich genommen:

                    const WebSocketServer = require('ws');

                    auch als ich bei import geblieben war, war das Ergebnis wie bei require

                    ich habe folgende module

                    "url": "^0.11.4", "ws": "^8.18.3" das habe ich aus C:\Users\Administrator\package.json genommen.
                    (in C:\Users\Administrator\node_modules sind ei mir die nodemodule gespeichert)

                    Sind noch aktuell?

                    Es stimmt, "new WebSocket" finde ich auch nicht im ws/lib.

                    Es wird websocket.js aus der ws/lib genommen und mit initAsClient(this, address, protocols, options);//zeile 86 function initAsClient gestartet

                    in Zeile 685 und 694 steht(ich habe meine Kommentare hinzugefügt):

                      let parsedUrl;
                      if (address instanceof URL) {  //adress ist kein Instanz von URL
                        parsedUrl = address;
                      } else {
                        try {
                          parsedUrl = new URL(address); //hier ist der Fehler
                        } catch (e) {
                      throw new SyntaxError(`Invalid URL: ${address}`);//das wird ausgegeben
                        }
                      }
                    

                    Für address steht hier port:8443 und URL konnte das nicht verarbeiten.

                    es wird kein Websocket-Client erzeugt

                    Rolf, ich hoffe, daß ich jetzt alles richtig dargestellt habe.

                    Effel

                    1. Hallo effel,

                      boah ey, ich habe keine Ahnung was dieser require treibt, aber offenbar liefert er Dir ein komisches Konglomerat aus WebSocket-Konstruktor und Modulinformation zurück und erzeugt damit das Gleiche wie der Import.

                      Du bekommst eine Funktion zurück. Und offenbar ist das der WebSocket-Konstruktor (also der Client), angereichert um zusätzliche Eigenschaften.

                      Hab ich so rausgefunden:

                      const ws = require('ws');
                      console.log(typeof ws);
                      console.log(ws);
                      

                      Mach's mal so:

                      const { WebSocketServer } = require('ws');
                      const socketServer = new WebSocketServer({ port:8443 });
                      .... rest unverändert
                      

                      Die Deklaration const { WebSocketServer } = ... ist eine sogenannte Destrukturierung. require liefert ein Objekt, das die WebSocketServer-Eigenschaft enthält, und durch das Destrukturierungsmuster links vom = weiß JavaScript, dass Du Dich nur für diese Eigenschaft interessierst.

                      Rolf

                      --
                      sumpsi - posui - obstruxi
                      1. jetzt funktioniert es

                        und danke Effel

    2. Hallo Martin,

      ich hab das schon verstanden, ich wollte nur den Umweg über Datei

      vermeiden: Im Nodeserver von Selfhtml wird eine Datei gelesen und

      in die Variable "file" gespeichert und dann mit response.write

      an respons übrgeben.

      Ich müßte den ErgebnisWert 1.618 zunächst in eine Datei schreiben,

      die dann der Nodeserver lies und an respons übergibt.

      Frage: warum nicht gleich den Ergebniswert direkt in den Server geben ?

      Effel

      1. Hallo effel,

        guck in das WS Tutorial, das ich verlinkt hatte, da geht's auch anders.

        Ich guck mal, wie ich die Verlinkung verbessern kann.

        Rolf

        --
        sumpsi - posui - obstruxi
  2. Lieber effel,

    aber im NodeServer geht es nur über Dateien.

    das ist so:

    1. Browser sendet eine (Text-)Datei als Anforderung (Request)
    2. Server sendet eine Datei als Erwiderung (Response)

    Kommunikation via HTTP funktioniert eben so. Der Server kann keine Antwort geben, ohne dabei eine Datei zu senden. Das hat insbesondere damit zu tun, dass dieser auch etwas zu der Datei selbst sagen muss (Meta-Daten), damit der Browser verstehen kann, wie er mit der Response umgehen muss. Das kennst Du, wenn eine Bilddatei, die der Browser eigentlich haben wollte, als eine HTML-Datei (z.B. mit 404-Fehlermeldung darinnen) geliefert wurde.

    Liebe Grüße

    Felix Riesterer

  3. Einzelwerte (Du schreibst im Plural) werden durch serverseitiges ECMA-Skript („Java-Script“) als JSON abgebildet und verschickt, und dann clientseitig (Java-Script im Browser) ausgewertet.

    Man macht das auch, wenn man nur einen Wert versendet (im Hinblick auf künftige Weiterungen, Fehlermeldungen) e.t.c.

    Welcher Teil davon bereitet Dir Probleme?