Application p5js avec serveur node

Dans cet article nous vous présentons un exemple d’application p5js en réseau.
Ici, les utilisateurs peuvent contribuer à un même dessin en direct.

p5jserver
Cet exemple expliqué en détail doit vous permettre de comprendre les bases d’un telle solution pour développer votre propre application.

Structure de notre application

Notre projet se compose des répertoires et fichiers suivants :

arborescence

Les fichiers server.js et package.js sont spécifiques au serveur tournant sous node.js.

Le répertoire public contient tous les fichiers utilisés par la partie client.
Ce sont les fichiers « servis » par le serveur node.js , accessibles depuis un navigateur.

 


Architecture du serveur

Notre serveur va « servir » via le module express le fichier index.html présent dans le répertoire public, et va permettre la communication avec le client grâce au module socket.io.
node


Comment cela fonctionne-t-il ?

Remarque : Pour bien comprendre le fonctionnement de cet application client/serveur, il est conseillé de regarder attentivement les programmes server.js et sketch.js et les commentaires associés en même temps que ces explications.

Sans rentrer dans le détail, la bibliothèque socket.io met à disposition un ‘module’ io qui se trouve au niveau supérieur et qui gère toutes les communications. On trouve ensuite les sockets (prises en anglais) qui permettent de créer un canal de communication entre le client et le serveur. Un socket défini un port (une « porte ») par lequel vont transiter les messages.On peut représenter ce système de communication à l’aide du schéma suivant:

io1

Le schéma ci-dessous donne une idée du fonctionnement de notre application client/serveur.

schema

C’est le client, avec l’instruction socket = io() présente dans sketch.js qui fait une demande de création d’un « canal de communication » au serveur. Il envoi en fait un paquet demande de ‘connection’ au serveur.

io2

L’instruction io.on(‘connection’,newConnectionProcess) présente au niveau du serveur (server.js) permet à celui-ci de créer un canal de communication avec le client suite à une demande de ‘connection’ mais également de lui indiquer comment gérer les messages arrivants sur le socket associé (function onMouseMsgReceived).

io3

Voilà ! la communication est établie via les sockets entre le client et le serveur.
Ces derniers vont pouvoir communiquer à l’aide de message. Ces messages qui vont transiter via le réseau se composent (en simplifiant) des éléments suivants :

paquet1

Dans la suite nous n’allons nous intéresser qu’à la partie :

paquet2

Notre application de dessin collaboratif doit permettre aux différents utilisateurs d’indiquer aux autres les tracés qu’ils font sur leur écran. Pour cela ils vont envoyer au serveur les coordonnées successives de leur souris.
Pour distinguer les messages des uns des autres, il est nécessaires de les caractérisés par un tag spécifiques.
Ici notre message sera défini comme étant de type « mouse » et les données seront composées des 2 valeurs correspondant aux coordonnées de la souris : var data = { x : mouseX, y : mouseY };

paquet3

Pour info, dans socket.io on ne parle pas de type mais plutôt d’évènement « mouse » car, en effet, à la réception du message celui-ci va être traité comme un évènement : ‘un message de type « mouse » vient d’arriver’.

Pour envoyer ce message, le client utilise l’instruction : socket.emit(‘mouse’,data);

io4

Au niveau du serveur rappelons nous que nous avons défini une fonction newConnectionProcess qui indique au serveur ce qu’il doit faire à la réception d’un message.
Dans cette fonction, nous trouvons l’instruction: socket.on(‘mouse’,function onMouseMsgReceived (data) {...});
qui indique via la fonction onMouseMsgReceived comment gérer la réception d’un message de type ‘mouse’.

function onMouseMsgReceived(data) {
  socket.broadcast.emit(‘mouse’,data);
};

A la réception d’un message : paquet3 le module socket.io appelle la fonction onMouseMsgReceived en lui passant en paramètre la partie donnée (data) du message. Celle-ci émet à nouveau le message à destination de tous les autres clients grâce à l’instruction socket.broadcast.emit(‘mouse’,data).
io5
Ici, le serveur sert uniquement de relai et renvoi le même message. On peut bien évidemment envoyer le type de message et les données de son choix.

Il ne nous reste plus qu’à détailler ce qui se passe côté client à la réception du message ‘mouse’ envoyé par le serveur. En fait, le client grâce à l’instruction socket.on(‘mouse’,function onMouseMsgReceived(data) {...}); exécute la fonction onMouseMsgReceived en lui passant en paramètre la partie donnée du message qui correspond aux cordonnées de la souris (data).
Ici, il s’agit d’un regroupement de données, la valeur de x et de y. Afin de pouvoir les distinguer elles sont stockées sous forme d’un objet composé de 2 propriétés x et y. Pour y accéder il suffit d’utiliser la notation data.x et data.y.


Serveur et envoi de messages

Il faut savoir que le serveur peut envoyer un message aux clients selon trois modes :

Ci-dessous les schémas illustrant chacun de ces 3 modes :

Envoi sur le socket du client courant et lui seul :
io6

Envoi à tous les clients y compris l’émetteur :
io7

Envoi à tous les clients sauf l’émetteur :
io8


Les fichiers principaux

fichers sketch.js

CC BY NC SA  ( Christophe Béasse - Octobre 2017 )