Dans le cadre de l’un de mes projets, je dois développer un logiciel backend Node.js capable de dialoguer avec un robot en utilisant le protocole UDP (User Datagram Protocol).
Nous allons donc voir dans cet article comment mettre en place cette communication en utilisant deux scripts JavaScript : l’un pour simuler l’envoi des données par le robot robot-simulator.js et l’autre pour recevoir ces données robot-udp-service.js. Nous allons détailler ces scripts et expliquer leur fonctionnement.
Cette solution permet de transmettre des données optimisées, minimisant ainsi la taille des paquets pour une communication efficace et rapide.
Le Protocole UDP
UDP est un protocole de communication rapide mais non fiable. Contrairement à TCP, il n’assure pas la livraison des paquets et ne garantit pas leur ordre. Cependant, sa rapidité en fait un excellent choix pour des applications temps réel ou où la vitesse est cruciale.
Diagramme Séquentiel de la Communication
Explication de la Structure des Données
Les données, au niveau du robot, sont optimisées pour minimiser la taille des paquets envoyés. Voici comment les données sont structurées sur deux octets :
Octet 1
Bits 0-1 : num1
Bits 2-7 : charCode (6 bits)
Octet 2
Bits 0-1 : charCode (suite, 2 bits)
Bits 2-7 : num2
num1 : un nombre entre 0 et 3, codé sur 2 bits. charCode : le code ASCII d’un caractère (a-z), codé sur 8 bits (6 bits dans le premier octet, 2 bits dans le second). num2 : un nombre entre 0 et 63, codé sur 6 bits dans le second octet.
Il va donc falloir restructurer ses données pour les exploiter dans le service de réception. Nous allons pour cela utiliser des techniques de décalage et de masquage de bits pour extraire les différentes parties des octets.
Script de Simulation du Robot : robot-simulator.js
Ce script simule le comportement du robot en envoyant des messages UDP structurés au service de réception.
// Importation du module 'dgram' pour créer des sockets UDP const dgram = require('dgram'); // Création d'un socket UDP const socket = dgram.createSocket('udp4');
// Adresse IP et port du service de réception constSERVICE_IP = '127.0.0.1'; constSERVICE_PORT = 5501;
let messageCount = 0; // Compteur pour les messages envoyés
// Fonction pour générer un entier aléatoire entre 'min' et 'max' functiongetRandomInt(min, max) { returnMath.floor(Math.random() * (max - min + 1)) + min; }
// Fonction pour créer un message structuré functioncreateStructuredMessage() { let buffer = Buffer.alloc(2);
// Génération des données let num1 = getRandomInt(0, 3); // Nombre entre 0 et 3 let charCode = getRandomInt(97, 122); // Code ASCII pour une lettre minuscule (a-z) let char = String.fromCharCode(charCode); // Conversion du code ASCII en caractère let num2 = getRandomInt(0, 63); // Nombre entre 0 et 63
// Premier octet : bits 0-1 pour 'num1', bits 2-7 pour 'charCode' (6 premiers bits) buffer[0] = (num & 0b11) | ((charCode & 0b111111) << 2);
// Deuxième octet : bits 0-1 pour 'charCode' (2 derniers bits), bits 2-7 pour 'num2' buffer[1] = ((charCode >> 6) & 0b11) | ((num2 & 0b111111) << 2);
return { buffer, num1, char, num2 }; }
// Fonction pour envoyer un message structuré au service functionsendMessageToService(buffer, serviceIp, servicePort, num1, char, num2) { messageCount++; socket.send(buffer, servicePort, serviceIp, (err) => { if (err) { console.error('Erreur lors de l\'envoi du message:', err); } else { console.log(`Message envoyé ${messageCount} - Num1: ${num1}, Char: ${char}, Num2: ${num2}`); } }); }
// Envoi périodique de messages structurés toutes les 500 millisecondes setInterval(() => { const { buffer, num1, char, num2 } = createStructuredMessage(); sendMessageToService(buffer, SERVICE_IP, SERVICE_PORT, num1, char, num2); }, 500);
// Gestion des erreurs du socket socket.on('error', (err) => { console.error('Erreur du socket:', err); socket.close(); });
// Gestion de la fermeture du socket socket.on('close', () => { console.log('Socket fermé'); });
Script de Réception des Données : robot-udp-service.js
Ce script écoute les messages UDP envoyés par le robot. Il décode les messages structurés et affiche les données reçues.
// Importation du module 'dgram' pour créer des sockets UDP const dgram = require('dgram'); // Création d'un socket UDP const socket = dgram.createSocket('udp4');
// Adresses IP et ports pour la communication avec le robot et le service local constROBOT_IP = '10.5.0.2'; constROBOT_PORT = 6501;
let messageCount = 0; // Compteur pour les messages reçus
// Fonction pour envoyer un message au robot functionsendMessageToRobot(message, robotIp, robotPort) { const messageBuffer = Buffer.from(message); socket.send(messageBuffer, robotPort, robotIp, (err) => { if (err) { console.error('Erreur lors de l\'envoi du message:', err); } else { console.log('Message envoyé au robot:', message); } }); }
// Fonction pour décoder un message structuré reçu functionparseStructuredMessage(buffer) { // Premier octet : extraction des 2 premiers bits pour 'num1' et des 6 suivants pour 'charCode' let num1 = buffer[0] & 0b11; let charCode = (buffer[0] >> 2) & 0b111111;
// Deuxième octet : extraction des 2 premiers bits restants de 'charCode' et des 6 bits suivants pour 'num2' charCode |= (buffer[1] & 0b11) << 6; let num2 = (buffer[1] >> 2) & 0b111111;
let char = String.fromCharCode(charCode);
return { num1, char, num2 }; }
// Fonction pour gérer la réception des messages functionhandleIncomingMessage(msg, rinfo) { const parsedMessage = parseStructuredMessage(msg); messageCount++; console.log(`Message reçu ${messageCount} - Num1: ${parsedMessage.num1}, Char: ${parsedMessage.char}, Num2: ${parsedMessage.num2}`); }
// Configuration de l'événement 'message' pour le socket socket.on('message', handleIncomingMessage);
// Liaison du socket à une adresse IP et un port locaux socket.bind(LOCAL_PORT, LOCAL_IP, () => { console.log(`Serveur UDP en écoute sur ${LOCAL_IP}:${LOCAL_PORT}`); });
// Envoi d'un message initial au robot sendMessageToRobot('Hello, Robot!', ROBOT_IP, ROBOT_PORT);
// Gestion des erreurs du socket socket.on('error', (err) => { console.error('Erreur du socket:', err); socket.close(); });
// Gestion de la fermeture du socket socket.on('close', () => { console.log('Socket fermé'); });
Exécution des Scripts
Conclusion
Ces scripts montrent comment envoyer et recevoir des messages UDP structurés en Node.js. Cette technique peut être adaptée pour divers types de communication en temps réel où la rapidité est cruciale. En suivant et adaptant ces exemples, vous pourrez implémenter des solutions similaires pour vos propres projets.