Démo de WebSocket

Code serveur et client pour échanger texte et image entre un serveur et un navigateur, par WebSocket.

Typiquement, WebSocket transmet des chaînes de caractères, même si certains framework semblent transmettre des objets plus complexes, ils le font par des transformations en arrière-plan. Pour véhiculer un objet, on le place directement entre guillements pour en faire une chaîne, ou on recourt à la méthode stringify. Les deux sont utilisés dans la démo, qui utilise node.js coté serveur et un framework WebSocket coté serveur, tandis que l'objet WebSocket standard est utilisé coté navigateur.

Cette démonstration est minimaliste, elle envoie quelques messages entre le navigateur et le système de fichier, local ou distant, et elle transmet une image qui sera affichée dans une balise canvas. Cela procure un code de base que l'on peut facilement étendre pour une application réelle. Il convient plutôt pour des applications locales ou le contrôle d'un robot à partir d'un ordinateur ou un mobile (la section montages électroniques montre comment le mettre en pratique).

Coté serveur on installe Node.js puis le framework nodejs-websocket:

node npm nodejs-websocket

Cela pourrait aussi être ws, ou socketjs qui permet aussi la connexion entre navigateurs, ou toute autre bibliothèque. Socket.io devient difficile à installer, je ne le retiendrais pas une introduction comme celle-ci mais il peut convenir pour des applications Web.

On échange entre le client et le serveur des objets de la forme:

{ "text" : "...un message..." }

ou

{ "image" : "...chemin de l'image sur le serveur..." }

Une autre option serait d'échanger des objets un peu plus complexes avec une propriété "type", comme le fait la démo de Xul.fr, le type étant "text" ou "image".

Dans tous les cas, un objet est converti en chaîne de caractère avant d'être transmis, et à la réception décodé par la méthode JSON parse.

Le code coté serveur

var ws = require("nodejs-websocket")
var fs = require("fs")

var server = ws.createServer(function (connect) {
  console.log("Server started...")
   
  connect.on("text", function (str) {
     var jobj = JSON.parse(str);
     if("text" in jobj) {
         console.log("Received: " + jobj["text"])
         connect.sendText('{ "text": "Server connected to browser."}')
         return;
     }
     if("image" in jobj) {  
         console.log("Image asked.")
         var path ="house.png";        // for this demo, only one image
         console.log("Sending image: " + path);
         fs.exists(path, function(result) {
              var data = JSON.stringify( {'image' : path } );
              connect.sendText(data); 
         });
         return;
        }
    })

    connect.on("close", function (code) {
        console.log("Browser gone.")
    })
});

server.listen(8100)

Comme on le voit dans le cas d'un image, le serveur vérifie l'existence du fichier puis se borne à envoyer le chemin local de l'image. On va voir dans le code coté client qui cela suffit au navigateur.

Le chemin de l'image doit être relatif à celui de la page et pas un chemin sur le système local de fichier, sinon le navigateur Chrome refusera l'assignement.

Code JavaScript coté client

 var socket = new WebSocket("ws://localhost:8100");
  var canvas;
  var inner;
  window.onload=function() {
    canvas = document.getElementById("mycanvas");
    inner = document.getElementById("inner");
  }
  
  var image = new Image();
  
  function processImage(imagePath)  {       
    image.onload = function ()
    {
      // le code de l'ajustement de la taille d'image est dans l'archive
       var context = canvas.getContext("2d");
       context.scale(scalew, scaleh);
       context.drawImage(image, 0, 0);

       // on affiche le nom du fichier et les dimensions de l'image
       var message = imagePath + ", " + ow + " x " + oh + " px";
       if(w < ow || h < oh)
        message += ", resized to " + w.toFixed() + " x "+ h.toFixed();
       document.getElementById('storage').innerHTML = message;
     }
  }

  socket.onopen = function (event) {
    socket.send('{ "text": "Browser ready!"}' ); 
  };

  socket.onmessage=function(event) { 
    var command = JSON.parse(event.data);
    for(var comm in command)
    {
      switch(comm) {
        case "text":
            document.getElementById("storage").innerHTML = command["text"];
            reak;
        case "image":
            var fname = command["image"];
            image.src= fname
            processImage(fname);
            reak;	
       }
    }
  };

  function askImage()  {
    socket.send('{ "image": ""}'); 
  }

L'image est chargée directement par le navigateur en assignant la propriété src de l'objet image avec le chemin fourni par le serveur. Avant d'être affichée dans la balise canvas, elle peut recevoir des transformations, comme un ajustement de taille, mais le code n'est pas affiché ici (il est disponible dans l'archive).

Code HTML

<form action="" method="">
  <input type="button" onclick="askImage()" value="Send me an image">
</form>
<div id="inner">
<fieldset>
<div id="storage"></div>
</fieldset>
<canvas id="mycanvas"></canvas>
</div>

Le code source complet est disponible dans l'archive à télécharger...

Pour lancer le script, tapez:

node wsdemo.js

Puis chargez la page wsdemo.html avec l'explorateur de fichier ou la commande CTRL-O d'un navigateur.