Débuter avec Node.js partie 3

nodejs.png

Première application Node.js et HTML5

Date de publication : 14 mars 2012.

ParRomain MatonSite personnel

Suite de la série de billets consacrés àNode.js. Après unepetite introductionde ce serveur JavaScript puis uneprésentation de Cloud9 IDE, nous allons enfin mettre les mains dedans !
L'article original peut être lu sur le blog deWeb Tambouille:Node.JS partie 3 - Première application Node.js et HTML5(date de publication : mars 2011).

Viadeo Twitter Google Bookmarks ! Facebook Digg del.icio.us MySpace Yahoo MyWeb Blinklist Netvouz Reddit Simpy StumbleUpon Bookmarks Windows Live Favorites 



Introduction 
Installation 
Arborescence 
Client 
Serveur 
Run baby ! 
Conclusion et remerciements 


Introduction
logo_socketio.jpg
Socket.IO
Pour ceQuick Start, je vous propose une application qui fera dupushsur tous les clients pour leur envoyer l'heure système ainsi que le nombre de clients actuellement connectés au serveur (avec gestion de la déconnexion). Ces clients pourront envoyer despokesaux autres clients, le tout tournera avec expressetSocket.IO.

L'idée n'est pas de développer une application de gestion complète (qui mériterait une bonne dizaine de billets) ni de faire un tour d'horizon de la centaine de bibliothèques existantes, mais juste de vous montrer à quoi ressemble le code d'une application Node avec deux bibliothèques très répandues dans la communauté.


Installation
Normalement, vous devriez avoir Node et NPM installés sur votre machine (Débuter avec Node.js partie 1 § installation). Pour rappel, selon votre OS et votrepackage managersi besoin (ici Mac OSX et Homebrew) :
Dès lors, vous n'avez plus que deux commandes à effectuer pour installer les modulesexpressetSocket.IOpour Node :
Vous voilà prêt, commençons tout de suite !


Arborescence
Le projet aura l'arborescence suivante :
Très simple donc avec un fichierserver.jset dans un dossierpublic, un fichierindex.html.


Client
Tout d'abord, voyons le squelette du fichier HTML :
Un fichier très standard donc, avec un import du dernier jQuery, l'import de Socket.IO (module chargé par Node) et quelquesdivqui me permettront d'afficher les retours du serveur.

À la suite des deux balisesscript déjà présentes, je rajoute le code JavaScript suivant :
Quelques explications :

  • tout d'abord, je crée un objectio.Socket (qui par défaut utilisera lehostd'entrée et le port 80) ;
  • lorsque le serveur m'envoie un message, je peux le récupérer côté client en utilisant le code suivant (API Socket.IO) :sock.on('message', function(data) {...});;
  • le serveur me renverra un objet JSON, je le parcours et récupère les propriétésmessageoutimestampetclientque je mets dans les champs associés ;
  • je connecte la socket immédiatement après ;
  • je définis un gestionnaire d'événement sur le bouton et lors d'un clic utilisateur, j'envoie un messagepoke.
Plutôt simple non ? Même si l'API standard est déjà très simple d'utilisation, Socket.IO nous simplifie encore plus l'utilisation deWeb Socketscôté client et côté serveur.

Voyons maintenant le code côté serveur.


Serveur
Et voici le fichierserver.js:
Dans le détail :

  • j'importe les modulesSocket.IOetexpress;
  • je crée le serveurexpress, je configure le dossierpublicen statique, jemappel'URL racine'/' vers le fichierindex.htmlet je démarre le serveur ; on voit ici queexpressnous simplifie grandement le mapping entre une URL et une action (mais il n'est pas le seul) avec une bonne gestion des paramètres, j'aime beaucoup cette bibliothèque car elle me rappelle le très puissantSpring MVC;
  • je crée ensuite l'objetsocketen spécifiant quelques transports et en supprimant leflash policy server(inutile pour notre exemple) ;
  • lorsqu'un client se connecte, je le stocke dans un objet JSON, j'augmente la variableidet j'augmente le nombre de clients connectés (variableallClients) ;
  • je lance unsetIntervalpour envoyer toutes les secondes l'heure courante du serveur ainsi que le nombre de clients connectés (le JSON qui sera récupéré dans mon client,cf.code du § client) ;
  • si un client envoie un message côté serveur, je le répercute à tous les autres avec un message générique mentionnant l'iddu client qui a envoyé le message ;
  • enfin, sur une déconnexion d'un client, je stoppe lesetIntervallié à ce client et je décrémente la variableallClients; celle-ci sera ensuite envoyée à tous les autres clients lors d'un prochain envoi de données dusetInterval.
Il y a bien sûr différentes manières de faire ce code, celui-ci ne sert qu'à vous montrer ce que l'on peut faire :

  • envoyer un message à un client spécifique ;
  • renvoyer un message d'un client vers tous les autres ;
  • mettre à jour des variables globales utilisées par tous les clients ;
D'ailleurs, si vous avez d'autres astuces concernant lesWeb Socketsdans Node, n'hésitez pas à les partager en commentaires !


Run baby !
Bon, il n'y a plus qu'à lancer le code et à vous rendre à l'URLhttp://localhost:8333/:
Et maintenant, amusez-vous à lancer plusieurs navigateurs à cette URL, à envoyer despokes, à vous déconnecter…

nodejs_3_clients.jpg
nodejs_2_clients.jpg

Ir Christian BAGALWA
  rmat0n:~$ brew install node rmat0n:~$ curl http://npmjs.org/install.sh | sudo sh  
  rmat0n:~$ npm install express rmat0n:~$ npm install socket.io  
  / project / public index.html server.js  
  <html> <head> <title>Socket IO Demo</title> <script src="http://code.jquery.com/jquery-1.5.min.js"></script> <script src="/socket.io/socket.io.js"></script> </head> <body> <div> <h2>Démo Node.js + Socket IO</h2> <label for="timestamp">Timestamp</label> <div id="timestamp"></div> <label for="clients">Clients</label> <div id="clients"></div> <label for="message">Message</label> <div id="message"></div> <p><button id="poke">Send poke !</button></p> </div> </body> </html>  
  <script type="text/javascript"> $(document).ready(function () { var sock = new io.Socket(); sock.on('message', function (data) { var obj = JSON.parse(data); if(obj.message) { $('#message').text(obj.message); } else { $('#timestamp').text(obj.timestamp); $('#clients').text(obj.clients); } }); sock.connect(); $("#poke").click(function() { sock.send("Poke !"); }); }); </script>  
  var io = require('socket.io'); var express = require('express'); var app = express.createServer(); app.configure(function(){ app.use(express.static(__dirname + '/public')); }); app.get('/', function(req, res, next){ res.render('./public/index.html'); }); app.listen(8333); var socket = io.listen(app, { flashPolicyServer: false, transports: ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'] }); var allClients = 0; var clientId = 1; socket.on('connection', function(client) { var my_timer; var my_client = { "id": clientId, "obj": client }; clientId += 1; allClients += 1; my_timer = setInterval(function () { my_client.obj.send(JSON.stringify({ "timestamp": (new Date()).getTime(), "clients": allClients })); }, 1000); client.on('message', function(data) { my_client.obj.broadcast(JSON.stringify({ message: "poke send by client "+my_client.id })); console.log(data); }); client.on('disconnect', function() { clearTimeout(my_timer); allClients -= 1; console.log('disconnect'); }); });  
  rmat0n:~/dev/node-example$ node server.js  
Retour à l'accueil