Socket.IO n’est plus à présenter ; seulement je dois me confesser : je ne m’y étais jamais interessé auparavant puisque je partais du fait qu’il n’était compatible qu’avec les navigateurs “performants”. Exit donc Internet Explorer, les quelques autres fossiles et navigateurs mobiles.

En fait, ce sont bien sûr les Web Sockets qui posent les problèmes de compatibilité. Mais Socket.IO est beau : Il utilise certes les Web Sockets quand ceux-ci sont disponibles sur le navigateur du client mais il sait également faire sans, à tel point que la compatibilité est assurée jusqu’à Internet Explorer 5.5.

Je me rends compte aujourd’hui que ma bêtise m’a fait passer à côté d’une techno formidable. Il est temps de rattraper ça, alors profitons alors de cette édition de #NPotW !

En bref

Dans le monde réel, nous ne décrochons pas notre téléphone toutes les dix secondes pour savoir si quelqu’un souhaite nous parler, n’est-ce pas ? Alors pourquoi mettre en place ce genre de technique dans nos développements ? Simplement parce que le Web n’est pas fait pour ça.

L’exemple le plus parlant est sans nul doute le tchat, puisque dans un monde Web classique, la solution consisterait à interroger périodiquement le serveur pour récupérer les éventuels nouveaux messages. L’utilisateur connecté aura alors l’impression de recevoir les messages en instantané, mais il n’en serait rien. User de cette méthode est tout d’abord un gâchis de ressources et de bande passante. C’est aussi du ressort de la bidouille.

C’est là que Socket.IO intervient en permettant de maintenir une connexion bi-directionnelle entre le client et le serveur, ou, cas échéant, d’en donner l’illusion. Le serveur est alors capable de s’adresser à ses clients. On appelle ce principe le long-polling, ou le server push.

Et en pratique

En guise de démonstration, je vous propose d’utiliser ce qu’on a vu pour le premier #NPotW dans lequel il était question de SerialPort pour afficher une température en temps réel sur une page Web.

On utilisera pour cela un Arduino connecté au serveur Node.js via une liaison série. Une sonde de température de type CTN sera raccordée sur une entrée analogique de l’Arduino. Ce dernier convertira la tension image en température, l’enverra au serveur Node.js, qui à son tour diffusera l’information sur un socket auquel le navigateur Web client sera connecté.

Le serveur

On commence comme d’habitude par installer Socket.IO à l’aide de NPM :

1
$ npm install socket.io

Puis on créé un fichier app.js dans lequel il faudra faire apparaître les quelques éléments suivants afin de pouvoir utiliser Socket.IO au sein de notre programme et de le rendre disponible à l’aide d’Express. :

1
2
var io = require('socket.io');
var express = require('express');

Il faut maintenant créer le serveur et demander à Socket.IO d’écouter sur ce dernier :

1
2
3
4
5
var app = express();
var server = require('http').createServer(app);
var io = io.listen(server);

server.listen(4242);

On peut ensuite s’attacher à l’évènement nous indiquant une nouvelle connexion et envoyer des messages à nos clients :

1
2
3
io.sockets.on('connection', function (socket) {
socket.emit('message', 'Bonjour, client.');
});

Les clients

Le code à faire apparaître au sein de la page Web est très compact, puisqu’il se limite à inclure soket.io.js :

1
<script src="http://IP_DU_SERVEUR:4242/socket.io/socket.io.js"></script>

Puis à ces quelques lignes :

1
2
3
4
5
6
<script>
var socket = io.connect('http://IP_DU_SERVEUR:4242');
socket.on('message', function (data) {
console.log(data);
});
</script>

Attention à bien inclure socket.io.js en précisant l’adresse du serveur Node.js. Vous devez impérativement utiliser le même script des deux côtés, sans quoi vous obtiendrez le message suivant :

XMLHttpRequest cannot load http://IP_DU_SERVEUR:4242/socket.io/?EIO=2&transport=polling. Origin http://localhost:666 is not allowed by Access-Control-Allow-Origin.

Prenons la température

Il ne nous reste plus qu’à lire sur le port série et à transmettre les données à nos clients. Si vous avez manqué la première édition de #NPotW, je vous conseille de faire un tour ici pour tout savoir de SerialPort.

Côté serveur, nous devons retrouver le code suivant :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var io = require('socket.io');
var express = require('express');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var com = new SerialPort('/dev/tty.usbserial-A600eufu', {
baudrate: 9600,
parser: serialport.parsers.readline('\r\n')
}, false);

var app = express()
, server = require('http').createServer(app)
, io = io.listen(server);

com.open(function () {
server.listen(4242);
});

io.sockets.on('connection', function (socket) {
com.on('data', function(data) {
socket.emit('temperature', data);
});
});

Le code client, quant à lui, doit ressembler à ça :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="http://IP_DU_SERVEUR:4242/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://IP_DU_SERVEUR:4243');
socket.on('temperature', function (data) {
$('#dyn').text(data);
});
</script>

</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="text-center">
<h1><span id="dyn">0</span> °C</h1>
</div>
</div>
</div>
</body>
</html>

Et le résultat en vidéo :



En conlusion

Socket.IO est vraiment un package à essayer. Il offre une toute nouvelle perspective au Web et permet en quelques lignes à peine de créer des applications puissantes et dynamiques.

J’espère que cette édition de #NPotW vous a plu, et je vous souhaite de bien vous amuser avec ce module. En attendant la semaine prochaine, n’hésitez pas à abuser de ce cher NPM !


À très bientôt,