From 20cbdeef8d3da7e621420258d953120c2c6ff37b Mon Sep 17 00:00:00 2001 From: William Petit Date: Sat, 13 Jan 2018 16:53:31 +0100 Subject: [PATCH] CESI: Architecture N tiers, exercice --- .../presentation/slides.md | 14 +-- .../ressources/exercices/ex_2_tiers/README.md | 30 ++++++ .../ressources/exercices/ex_2_tiers/client.js | 78 ++++++++++++++ .../ressources/exercices/ex_2_tiers/seq.msc | 34 ++++++ .../ressources/exercices/ex_2_tiers/seq.png | Bin 0 -> 40477 bytes .../ressources/exercices/ex_2_tiers/server.js | 48 +++++++++ .../exercices/ex_2_tiers_solution/client.js | 80 ++++++++++++++ .../exercices/ex_2_tiers_solution/modd.conf | 6 ++ .../exercices/ex_2_tiers_solution/server.js | 102 ++++++++++++++++++ 9 files changed, 380 insertions(+), 12 deletions(-) create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/README.md create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/client.js create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.msc create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.png create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/server.js create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/client.js create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/modd.conf create mode 100644 cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/server.js diff --git a/cesi/architecture_n_tiers/presentation/slides.md b/cesi/architecture_n_tiers/presentation/slides.md index e2d5873..2741327 100644 --- a/cesi/architecture_n_tiers/presentation/slides.md +++ b/cesi/architecture_n_tiers/presentation/slides.md @@ -130,19 +130,9 @@ La conception d'une application distribuée nécessite d'établir une répartiti --- -## Exercice (1) - -Implémenter en NodeJS une application distribuée permettant d'effectuer les opérations arithmétiques simples (addition, soustraction, multiplication et division). Cette application devra répondre aux contraintes suivantes: - -- Elle devra être suivre une architecture 2 tiers de classe 4. -- Le client devra utiliser le transport TCP/IP pour communiquer avec le serveur. -- Elle n'aura pas à supporter de multiples clients. -- Toutes les implémentations de la classe devront être compatibles, i.e. vous devez vous mettre d'accord sur un protocole de sérialisation/désérialisation des messages commun. - ---- - -## Exercice (2) +## Exercice +### Implémentation d'une calculatrice à état distribuée en NodeJS --- diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/README.md b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/README.md new file mode 100644 index 0000000..9230289 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/README.md @@ -0,0 +1,30 @@ +# Exercice: implémentation d'une calculatrice à état distribuée + +## Consignes + +Implémenter en NodeJS une application distribuée permettant d'effectuer les opérations arithmétiques simples. Cette application devra répondre aux contraintes suivantes: + +- Elle devra être suivre une architecture 2 tiers de classe 4. +- Le client devra utiliser le transport TCP/IP pour communiquer avec le serveur. +- Elle n'aura pas à supporter de multiples clients. +- Toutes les implémentations de la classe devront être compatibles, i.e. vous devez vous mettre d'accord sur un protocole de sérialisation/désérialisation des messages commun. + +Le client/serveur devront gérer les instructions suivantes: + +- `add` Requête d'addition +- `sub` Requête de soustraction +- `div` Requête de division +- `mul` Requête de multiplication +- `status` Requête de récupération de la valeur de l'accumulateur sur le serveur +- `reset` Requête de réinitialisation de la valeur de l'accumulateur sur le serveur. + +Vous pouvez vous baser sur les fichiers `client.js` et `server.js` présent dans ce répertoire pour amorcer votre projet. + +## Exemple de séquence d'échange + +![center](./seq.png) + +## Ressources + +- [Télécharger/installer NodeJS](https://nodejs.org/en/download/) +- [Le module `net` de NodeJS](https://nodejs.org/api/net.html) diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/client.js b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/client.js new file mode 100644 index 0000000..4e2b66a --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/client.js @@ -0,0 +1,78 @@ +var net = require('net'); + +// Notre client se connecte sur le serveur local +var SERVER_HOST = '127.0.0.1'; +var SERVER_PORT = 3333; + +// Création du "socket" de connexion TCP/IP +var client = new net.Socket(); + +// Notre objet "client" est une instance d'EventEmitter +// (voir https://nodejs.org/api/events.html) +// On peut donc lui attacher des fonctions, +// appelées "callback" ou "handler", afin de réagir +// à certains évènements liés au cycle de vie de l'objet + +// On attache un callback à notre client pour +// l'évènement "connect". En passant une référence +// à la fonction "onConnect" on indique que l'on +// souhaite que celle ci soit automatiquement +// invoquée lorsque le client sera connecté. +client.on('connect', onConnect); + +// Les données transmises par le serveur au client sont +// automatiquement transformées sous forme d'évènement +// par NodeJS. On peut récupérer ces données en ajoutant +// un callback sur notre objet "client" pour l'évènement +// "data" +client.on('data', onData); + +// L'évènement "close" est émis lorsque la connexion +// avec le serveur est close. +client.on('close', onClose); + +// L'évènement "error" est émis lorsque une erreur +// est soulevée. (exemple: perte de connexion) +client.on('error', onError); + + +// On initialise la connexion au serveur +console.log('Tentative de connexion au serveur: %s:%s', SERVER_HOST, SERVER_PORT); +client.connect(SERVER_PORT, SERVER_HOST); + +function onConnect() { + + // Nous sommes connecté au serveur ! + console.log('Connecté sur ' + SERVER_HOST + ':' + SERVER_PORT); + + // TODO envoyer les commandes au serveur ici + + // On peut envoyer des données au serveur via la méthode + // write() du client + // Exemple + client.write('add 1'); + + // Si on le souhaite, on peut clore la connexion + // au serveur via la méthode destroy() + client.destroy(); + +} + +function onData(data) { + + // Les données sont reçues sous forme de bytes. On les transforme + // en chaine de caractères UTF-8 pour faciliter leur manipulation + var str = data.toString('utf8'); + + console.log('Données reçues du serveur: %s', str); + +} + +function onClose() { + console.log('La connexion au serveur a été close.') +} + +function onError(err) { + console.log('Une erreur a été soulevée: %s', err); + process.exit(1); +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.msc b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.msc new file mode 100644 index 0000000..1336608 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.msc @@ -0,0 +1,34 @@ +msc { + + wordwraparcs=true, hscale=2; + + Client,Server; + + ... [ label = "Lancement du serveur et du client" ]; + + Server box Server [ label="acc = 0" ]; + + Client->Server [ label="status" ]; + Server->Client [ label="0" ]; + + Client->Server [ label="add 10" ]; + Server->Server [ label="acc = acc + 10" ]; + Server->Client [ label="10" ]; + + Client->Server [ label="sub 2" ]; + Server->Server [ label="acc = acc - 2" ]; + Server->Client [ label="8" ]; + + Client->Server [ label="div 2" ]; + Server->Server [ label="acc = acc / 2" ]; + Server->Client [ label="4" ]; + + Client->Server [ label="mul 5" ]; + Server->Server [ label="acc = acc * 5" ]; + Server->Client [ label="20" ]; + + Client->Server [ label="reset" ]; + Server->Server [ label="acc = 0" ]; + Server->Client [ label="0" ]; + +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.png b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/seq.png new file mode 100644 index 0000000000000000000000000000000000000000..88b1e2a70bd478c9b53bae6a8cf047a1af8a7c98 GIT binary patch literal 40477 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 literal 0 HcmV?d00001 diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/server.js b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/server.js new file mode 100644 index 0000000..160a9fc --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers/server.js @@ -0,0 +1,48 @@ +var net = require('net'); + +var HOST = '127.0.0.1'; // On écoute sur toutes les interfaces +var PORT = 3333; + +var server = net.createServer(); + +server.on('connection', onClientConnection); +server.on('listening', onListening); +server.on('error', onError); + +server.listen(PORT, HOST); + +function onClientConnection(client) { + + console.log('Nouveau client depuis %s:%s', client.remoteAddress, client.remotePort); + + // On souhaite commencer à récupérer les données + // provenant de ce nouveau client + client.on('data', onClientData); + client.on('close', onClientClose); + + function onClientData(data) { + + // Les données sont reçues sous forme de bytes. On les transforme + // en chaine de caractères UTF-8 pour faciliter leur manipulation + var str = data.toString('utf8'); + + console.log('Données reçues de %s:%s: "%s"', client.remoteAddress, client.remotePort, str); + + // TODO désérialiser les données reçues et traiter les opérations. + + } + + function onClientClose() { + console.log('Le client %s:%s s\'est déconnecté.', client.remoteAddress, client.remotePort); + } + +} + +function onListening() { + console.log("Serveur en écoute sur %s:%s", HOST, PORT) +} + +function onError(err) { + console.log('Une erreur a été soulevée: %s', err); + process.exit(1); +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/client.js b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/client.js new file mode 100644 index 0000000..3f4fc74 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/client.js @@ -0,0 +1,80 @@ +var net = require('net'); + +// Notre client se connecte sur le serveur local +var SERVER_HOST = '127.0.0.1'; +var SERVER_PORT = 3333; + +// Création du "socket" de connexion TCP/IP +var client = new net.Socket(); + +// Notre objet "client" est une instance d'EventEmitter +// (voir https://nodejs.org/api/events.html) +// On peut donc lui attacher des fonctions, +// appelées "callback" ou "handler", afin de réagir +// à certains évènements liés au cycle de vie de l'objet + +// On attache un callback à notre client pour +// l'évènement "connect". En passant une référence +// à la fonction "onConnect" on indique que l'on +// souhaite que celle ci soit automatiquement +// invoquée lorsque le client sera connecté. +client.on('connect', onConnect); + +// Les données transmises par le serveur au client sont +// automatiquement transformées sous forme d'évènement +// par NodeJS. On peut récupérer ces données en ajoutant +// un callback sur notre objet "client" pour l'évènement +// "data" +client.on('data', onData); + +// L'évènement "close" est émis lorsque la connexion +// avec le serveur est close. +client.on('close', onClose); + +// L'évènement "error" est émis lorsque une erreur +// est soulevée. (exemple: perte de connexion) +client.on('error', onError); + + +// On initialise la connexion au serveur +console.log('Tentative de connexion au serveur: %s:%s', SERVER_HOST, SERVER_PORT); +client.connect(SERVER_PORT, SERVER_HOST); + +function onConnect() { + + // Nous sommes connecté au serveur ! + console.log('Connecté sur ' + SERVER_HOST + ':' + SERVER_PORT); + + // TODO envoyer les commandes au serveur ici + + // On peut envoyer des données au serveur via la méthode + // write() du client + // Exemple + client.write('add 100\n'); + client.write('sub 10\n'); + client.write('div 9\n'); + client.write('mul 5\n'); + + client.write('status\n'); + + client.write('reset\n'); + client.write('status\n'); + + // Si on le souhaite, on peut clore la connexion + // au serveur via la méthode destroy() + // client.destroy(); + +} + +function onData(data) { + console.log('Données récupérée du serveur: %s', data); +} + +function onClose() { + console.log('La connexion au serveur a été close.') +} + +function onError(err) { + console.log('Une erreur a été soulevée: %s', err); + process.exit(1); +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/modd.conf b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/modd.conf new file mode 100644 index 0000000..c7a242b --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/modd.conf @@ -0,0 +1,6 @@ +server.js { + daemon: node server.js +} +client.js server.js { + prep: node client.js +} diff --git a/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/server.js b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/server.js new file mode 100644 index 0000000..ef3ef35 --- /dev/null +++ b/cesi/architecture_n_tiers/ressources/exercices/ex_2_tiers_solution/server.js @@ -0,0 +1,102 @@ +var net = require('net'); + +var HOST = '127.0.0.1'; // On écoute sur toutes les interfaces +var PORT = 3333; + +var server = net.createServer(); + +server.on('connection', onClientConnection); +server.on('listening', onListening); +server.on('error', onError); + +server.listen(PORT, HOST); + +function onClientConnection(client) { + + var accumulator = 0; + + console.log('Nouveau client depuis %s:%s', client.remoteAddress, client.remotePort); + + // On souhaite commencer à récupérer les données + // provenant de ce nouveau client + client.on('data', onClientData); + client.on('close', onClientClose); + + function onClientData(data) { + + console.log('Données reçues de %s:%s: "%s"', client.remoteAddress, client.remotePort, data); + + var messages = data.toString('utf8').split('\n'); + + for(var i = 0; i < messages.length; i++) { + + var line = messages[i]; + var tokens = line.split(' '); + + if (tokens.length !== 1 && tokens.length !== 2) { + client.write('invalid message'); + continue + } + + var command = tokens[0]; + + var arg; + if (tokens.length === 2) { + try { + arg = parseFloat(tokens[1]); + } catch(err) { + client.write('invalid message\n'); + continue + } + } + + console.log("Tokens", tokens); + + switch(command) { + case "add": + accumulator = accumulator + arg; + client.write(accumulator+'\n'); + break; + case "sub": + accumulator = accumulator - arg; + client.write(accumulator+'\n'); + break; + case "div": + accumulator = accumulator / arg; + client.write(accumulator+'\n'); + break; + case "mul": + accumulator = accumulator * arg; + client.write(accumulator+'\n'); + break; + case "status": + client.write(accumulator+'\n'); + break; + case "reset": + accumulator = 0; + client.write(accumulator+'\n'); + break; + } + + + + } + + + + } + + function onClientClose() { + console.log('Le client %s:%s s\'est déconnecté.', client.remoteAddress, client.remotePort); + } + +} + +function onListening() { + console.log("Serveur en écoute sur %s:%s", HOST, PORT) +} + +function onError(err) { + console.log('Une erreur a été soulevée: %s', err); + process.exit(1); +}