A moins que vous ne viviez dans un grotte depuis plus d'un an, vous avez probablement entendu parler de node.js. Node est un outil qui permet, en ligne de commande, d'exécuter des applications javascript en utilisant V8, le moteur de Chrome.
Node permet ainsi de développer des applications en javascript. Ce n'est pas la technologie révolutionnaire qui va tout nous faire arrêter de développer en Ruby, Python ou autre. C'est simplement une technologie supplémentaire qui a ses avantages et ses inconvénients.
Installer Node
Node n'est qu'une ligne de commande. Quelques librairies sont disponibles avec celle-ci cependant. Le projet est disponible en open source sur github.
Installer Node est simple. Commencez par télécharger le projet, puis ouvrez la ligne de commande et rendez-vous dans le dossier de celui-ci. La, en une ligne :
./configure && make && make install
Node est maintenant installé ! Vous pouvez exécuter n'importe quel script avec avec la commande suivante :
node <nom du fichier.js>
Comment ça fonctionne ?
Testons une application simple qui va se contenter de lire et d'écrire dans un fichier.
var fs = require('fs');
var sys = require('sys');
fs.readFile('todolist.txt', function(list) {
sys.puts("Liste des choses à faire aujourd'hui: " + list);
});
fs.writeFile('todolist.txt', "Ecrire l'article introduction à node.js");
Ici, notre script node fait deux actions. Tout d'abord, il lit le fichier "todolist.txt" et nous affiche son contenu. Puis il modifie ce fichier en lui donnant une tâche comme contenu.
Et sur le web ?
Si vous avez entendu parler de node.js jusqu'à maintenant, c'est probablement grâce aux facilités qu'il apporte pour développer des applications asynchrones et notamment pour utiliser les WebSockets.
Prenons tout de suite pour exemple une application très basique :
var sys = require('sys');
var net = require('net');
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
var clients = [];
function Client(socket) {
this.socket = socket;
}
var server = net.createServer(function (socket) {
var client = new Client(socket);
clients.push(client);
socket.addListener("connect", function () {
clients.forEach(function(c) {
c.socket.write("One people more ! We are now " + clients.length + " connected.\r\n");
});
});
socket.addListener("data", function(data) {
socket.write(data);
});
socket.addListener("end", function () {
clients.remove(client);
clients.forEach(function(c) {
c.socket.write("We now are one less\n");
});
socket.end();
});
});
server.listen(7000, "localhost");
Ce que fait cette application est assez simple. A chaque client qui se connecte, elle transmet un message à tous ceux qui le sont et leur annonce la venue d'un nouvel arrivant ainsi que le nombre de personnes actuellement connectées. Et à chaque personne qui se déconnecte, elle enlève celle-ci de sa liste.
Vous pouvez tester cela par vous même en local en chargeant la page dans chrome et dans firefox.
Analysons ce code plus en détail.
var sys = require('sys');
var net = require('net');
Ici, nous incluons les deux librairies que nous utiliserons dans notre application. La librairie sys est celle de base de node. Vous en aurez probablement besoin dans chacune de vos applications. La librairie net nous permet de démarrer le serveur. Vous pouvez visualiser la liste de toutes les librairies natives dans le dossier lib/ de node.
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
Nativement, javascript ne possède aucune fonction nous permettant de supprimer un élément d'un tableau autrement que par son identifiant. Nous surchargeons donc l'objet natif javascript Array en lui ajoutant cette méthode remove que nous utiliserons plus tard.
var clients = [];
Ceci est ce qui fait la magie de node ! Il est single thread. Et ce n'est pas un bug, c'est une feature ! Ainsi, le tableau clients que nous déclarons ici sera disponible pour toutes les personnes utilisant notre application en même temps. En conséquent, lorsque nous ajoutons un élément dans ce tableau, cet élément est disponible à tout le monde.
Cela va ainsi nous permettre de savoir, en permanence, combien de personnes sont connectées à notre application et de communiquer avec tous ceux ci.
function Client(socket) {
this.socket = socket;
}
Chaque élément de notre tableau clients contiendra une instance de ces objets Client. La variable socket est le pointeur vers le socket relatif au client. Ainsi, nous pourrons lui transmettre un nouveau message à n'importe quel moment.
var server = net.createServer(function (socket) {
...
}
server.listen(7000, "localhost");
Nous en arrivons maintenant à la partie serveur à proprement parler. Nous créons ici un objet de type serveur que nous exécutons ensuite pour écouter le port 7000 sur localhost.
A chaque client se connectant, la fonction anonyme que nous créons ici sera appellée et le paramètre socket correspondra au pointeur vers le socket du client dont nous parlions plus haut. Ici, nous allons donc pouvoir réellement interagir avec le client en détectant lorsqu'il se connecte, se déconnecte ou nous transmet un message.
var client = new Client(socket);
clients.push(client);
La liste de tous les clients connectés ne va pas se remettre à jour toute seule. En conséquent, nous devons, dès que le client charge l'application, ajouter celui-ci à ceux qui sont actuellement connectés.
socket.addListener("connect", function () {
clients.forEach(function(c) {
c.socket.write("One people more ! We are now " + clients.length + " connected.\r\n");
});
});
Un socket de client peut recevoir plusieurs listeners. Il s'agit d'une fonction qui sera exécutée lorsqu'un évènement précis se produit. Ici, il s'agit de l'évènement "connect". C'est à dire lorsque l'utilisateur se connecte.
Dans cet évènement, nous parcourons le tableau de tous les clients. Et pour chacun d'eux, nous écrivons à l'écran qu'un nouvel utilisateur vient de se connecter et nous signalons combien nous sommes à présent.
socket.addListener("data", function(data) {
socket.write(data);
});
De la même manière que avec Cramp lorsque nous utilisions les WebSockets, le client peut transmettre des messages au serveur. Ici, nous nous contentons d'afficher au client les messages qu'il nous envoie. Ainsi, lorsque vous chargerez l'application, vous pourrez voir s'afficher sur la page tous les headers que vous transmettre au serveur.
socket.addListener("end", function () {
clients.remove(client);
clients.forEach(function(c) {
c.socket.write("We now are one less\n");
});
socket.end();
});
Enfin, nous ajoutons un dernier évènement : lorsque l'utilisateur ferme sa connexion avec le serveur (ou qu'elle est fermée automatiquement car celui-ci est inactif), nous supprimons ce client du tableau (c'est ici que nous utilisons la fonction "remove" ajoutée à l'objet Array précédemment).
Puis nous transmettons à chacun des clients encore connectés que nous sommes désormais une personne en moins. Enfin nous finalisons la fermeture du socket afin d'éviter toute fuite de mémoire.
Conclusion
Nous avons vu dans cet article une rapide introduction à node.js. De nombreuses fonctionnalités supplémentaires sont cependant présentes. Et je vous invite fortement à consulter la documentation du projet pour plus d'informations.
D'autres articles viendront peut-être sur le sujet de node.js. En attendant, n'hésitez pas à me signaler si cet article vous a donné envie de vous mettre à cette technologie. Et indiquez mois quels sont les projets qui en ont découlé ;)


Commentaires
J'habite dans une grotte depuis deux ans (voir le lien), mais j'avais déjà entendu parler de node.js :-)
Merci pour cette belle introduction.
Bonjour,
Je sais que je déterre un très vieux sujet, mais je suis en train de m'intéresser de très près à node.js pour faire un tchat propre sans sql sur mon site. J'ai installé node.js sur mon ordinateur, et lancé le test : aucun souci, tout fonctionne.
J'ai testé votre introduction... et là, ça foire.
1) Tout d'abord, la sortie affichée par mon premier navigateur (par exemple FF) me donne One people more ! We are now 1 connected. GET / HTTP/1.1 [... le reste des entêtes HTTP ...] Cookie: SESS894db45d2315bda1c47d5b502cfa9523=r_3eRxakD0yl187Xjjly3oEH5bUEWmhT8d1-dDbDp48 Cache-Control: max-age=0
2) Ensuite, quand je lance la même page (http://127.0.0.1:7000/) avec Chrome, ça mouline dans le vide. Si j'actualise, j'ai le droit à une belle erreur dans la console de lancement de node :
node.js:63
Error: ECONNRESET, Connection reset by peer
Pourriez-vous me dire si ça vient de la config de mon serveur, si ça vient du fichier, si ça vient d'autre chose ? Je suis pas assez formé à node.js pour comprendre ce qui peut ne pas aller...
Merci en tout cas pour cet article très intéressant.
Meme probleme que olibé