In questa lezione della nostra guida a Node.js vedremo come usare il modulo net per creare una semplicissima chat da usare nel terminale. Per far ciò creeremo un banale server e useremo un programma come telnet per collegarci al server creato. Inoltre, utilizzeremo alcuni package esterni che scaricheremo con l’aiuto di NPM.
Per prima cosa creiamo una nuova cartella, ci spostiamo al suo interno e inizializziamo il progetto col comando npm init. Dopo aver completato i campi necessari, verrà creato un file package.json.
Installiamo poi alcuni package con l’aiuto di NPM.
- chalk per stampare dei messaggi con diversa formattazione e colore;
- figlet per creare arte ascii;
- uniqid per generare identificativi univoci per ogni client che desidera collegarsi al server;
- nodemon per evitare di dover riavviare il server ad ogni modifica effettuata;
Installiamo con il seguente comando tutti i package tranne nodemon. In questo modo abbiamo aggiunto tutti i moduli installati alla lista delle dipendenze.
npm install chalk figlet uniqid --save
A questo punto installiamo nodemon che aggiungeremo all’elenco delle dipendenze necessarie solo in fase di sviluppo.
npm install nodemon --save-dev
Modifichiamo il file package.json come mostrato in basso.
{
"name": "semplice_chat",
"version": "1.0.0",
"description": "Una semplice chat tcp",
"main": "server.js",
"scripts": {
"dev": "nodemon server.js",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"chalk": "^2.1.0",
"figlet": "^1.2.0",
"uniqid": "^4.1.1"
},
"devDependencies": {
"nodemon": "^1.12.1"
}
}
Grazie a nodemon, in fase di sviluppo, non dobbiamo riavviare manualmente il server ogni volta che effettuiamo una modifica.
Possiamo iniziare a scrivere il nostro semplice server utilizzando il modulo net. Creiamo un file server.js come quello mostrato in basso. Si tratta di un’implementazione elementare con diversi limiti, realizzata con il solo scopo di mostrare come iniziare a usare le funzioni fornite dal modulo net.
const chalk = require('chalk');
const uniqid = require('uniqid');
const figlet = require('figlet');
const net = require('net');
const server = net.createServer();
let sockets = {};
const PORT = 3000 || process.env.PORT;
const ADDRESS = '127.0.0.1' || process.env.ADDRESS;
const FULL_ADDRESS = `${ADDRESS}:${PORT}`;
server.on('connection', (socket) => {
socket.id = uniqid();
console.log(`Utente con id=${socket.id} connesso`);
socket.write(chalk.yellow(figlet.textSync('Simple Chat')) + 'nn');
socket.write('? Inserisci il tuo nome: ');
socket.on('data', (data) => {
if (!sockets[socket.id]) {
socket.name = data.toString().trim();
if (socket.name) {
// aggiungi l'utente all'elenco degli utenti collegati
sockets[socket.id] = socket;
socket.write(chalk.green(`Benvenuto ${socket.name}n`));
// Mostra nel terminale dell'utente un prompt personalizzato
socket.write(`[ ${socket.name} ] > `);
} else {
// se il nome inserito non è valido, il client visualizzerà un messaggio
// e verrà chiusa la connessione
socket.end(chalk.red.bold('ERRORE! Nome non valido!n'));
}
} else {
Object.keys(sockets).forEach((id) => {
const otherUser = sockets[id];
// invia il messaggio spedito da un utente a tutti gli altri
if (socket.id !== id) {
otherUser.write(`n${socket.name}: ${data}`);
otherUser.write(`[ ${otherUser.name} ] > `);
} else {
// aggiorna il prompt dell'utente che ha inviato il messaggio
socket.write(`[ ${socket.name} ] > `);
}
});
}
});
socket.on('end', () => {
delete sockets[socket.id];
console.log(`${socket.name} ha lasciato la chat.`);
})
});
server.listen(
PORT,
ADDRESS,
() => console.log(`
=============================
+++ Server in funzione +++
Indirizzo: ${chalk.green(FULL_ADDRESS)}
=============================
`)
);
Per prima cosa, abbiamo importato i moduli esterni che ci aiuteranno a realizzare il server TCP. Inizializziamo quindi un oggetto sockets che useremo per tener traccia di tutti i client che si collegheranno al server. Dichiariamo alcune costanti che utilizziamo poi all’interno della funzione server.listen() con la quale mettiamo in ascolto il server all’indirizzo e porta specificati come argomenti. La prima volta che un nuovo utente si collega, sarà emesso l’evento ‘connection’ che useremo per assegnargli un nuovo codice identificativo (socket.id). All’utente sarà inoltre chiesto di inserire il proprio nome. Quando un client invia un messaggio al server, se non è ancora presente nell’elenco degli utenti collegati, (ovvero se è il primo messaggio inviato) viene aggiunto all’oggetto sockets. (sockets è un oggetto avente come proprietà i codici identificativi univoci degli utenti) In caso contrario, il server invia il messaggio spedito da un client a tutti gli altri utenti.
Per per avviare il server appena creato, lanciamo il seguente comando nel terminale.
npm start
Ora possiamo aprire due nuove finestre del terminale e collegarci al server usando un programma come telnet. Lanciamo quindi il seguente comando nelle due finestre appena aperte per collegarci all’indirizzo 127.0.0.1 specificando il numero di porta. (3000)
telnet 127.0.0.1 3000
Come potete vedere dall’immagine, il client si collega al server e visualizza l’ascii art (Simple Chat). Gli viene quindi chiesto di inserire il proprio nome. A questo punto è pronto per iniziare a inviare dei messaggi agli altri utenti collegati.
Possiamo quindi provare a inviare un messaggio da un client all’altro.
Per terminare una sessione, possiamo digitare la sequenza di escape (^]), cioè digitare il carattere ‘]’ mentre teniamo premuto il tasto CTRL.
Conclusioni
Abbiamo visto come creare un semplicissimo server TCP usando il modulo net e alcuni moduli ausiliari che abbiamo aggiunto al nostro progetto attraverso NPM. Nella prossima lezione vedremo come realizzare un banale server HTTP usando l’omonimo modulo.