In this topic, we are going to understand and implement the network API for creating stream-based on TCP and TLS servers. Will also implement the corresponding client to consume and interact with the server. Node.js provides two modules to create server and client to establish and maintain a network conversation.
Net - https://nodejs.org/api/net.html [TCP]
TSL - https://nodejs.org/api/tls.html [TLS]
Let’s start with the net module for implementing TCP server and client.
TCP Server
var net = require(‘net’);
var server = net.createServer();
server.listen(port, host, () => { console.log(`TCP server listening on ${host}:${port}`); });
For now, we can configure host as local host and port as some arbitrary number 1234
server.on(‘connection’, (socket) => { var clientAddress = `${socket.remoteAddress}:${socket.remotePort}`; console.log(`new client connected: ${clientAddress}`); });
socket.on('data', (data) => { console.log(`${clientAddress}: ${data}`); }); socket.on('close', () => { console.log(`connection closed: ${clientAddress}`); }); socket.on('error', (err) => { console.log(`Error occurred in ${clientAddress}: ${err.message}`); });
(socket) => { var clientAddress = `${sock.remoteAddress}:${sock.remotePort}`; console.log(`new client connected: ${clientAddress}`); sockets.push(socket); … }
socket.on('data', (data) => { console.log(`${clientAddress}: ${data}`); sockets.forEach((sock) => { sock.write(`${sock.remoteAddress}:${sock.remotePort} said ${data}\n`); }); });
socket.on('close', (data) => { const index = sockets.findIndex( (o) => { return (o.remoteAddress===socket.remoteAddress) && (o.remotePort === socket.remotePort); }); if (index !== -1) sockets.splice(index, 1); sockets.forEach((sock) => { sock.write(`${clientAddress} disconnected\n`); }); console.log(`connection closed: ${clientAddress}`); });
constnet = require('net'); constport = 1234; consthost = 'localhost'; constserver = net.createServer(); server.listen(port, host, () => { console.log(`TCP server listening on ${host}:${port}`); }); letsockets = []; server.on('connection', (socket) => { varclientAddress = `${socket.remoteAddress}:${socket.remotePort}`; console.log(`new client connected: ${clientAddress}`); sockets.push(socket); socket.on('data', (data) => { console.log(`Client ${clientAddress}: ${data}`); // Write the data back to all the connected, the client will receive it as data from the server sockets.forEach((sock) => { sock.write(socket.remoteAddress + ':' + socket.remotePort + " said " + data + '\n'); }); }); // Add a 'close' event handler to this instance of socket socket.on('close', (data) => { letindex = sockets.findIndex((o) => { returno.remoteAddress === socket.remoteAddress && o.remotePort === socket.remotePort; }) if (index !== -1) sockets.splice(index, 1); sockets.forEach((sock) => { sock.write(`${clientAddress} disconnected\n`); }); console.log(`connection closed: ${clientAddress}`); }); // Add a 'error' event handler to this instance of socket socket.on('error', (err) => { console.log(`Error occurred in ${clientAddress}: ${err.message}`); }); });
TCP Client: For TCP client creation, we use the same module i.e. ‘net’.
var net = require(‘net’);
var client = new net.Socket();
client.connect( port, host, () => { console.log(`client connected to ${host}:${port}`); client.write(‘Hello, I am ${client.address().address}’); });
client.on('data', (data) => { console.log(`Client received: ${data}`); }); // Add a 'close' event handler for the client socket client.on('close', () => { console.log('Client closed'); }); client.on('error', (err) => { console.error(err); });
client.on(‘data’, (data) => { … if (data.toString().endsWith('exit')) { client.destroy(); } });
varnet = require('net'); constHOST = 'localhost'; constPORT = 1234; varclient = newnet.Socket(); client.connect(PORT, HOST, () => { console.log(`client connected to ${HOST}:${PORT}`); // Write a message to the socket as soon as the client is connected, the server will receive it as message from the client client.write(`Hello, I am ${client.address().address}`); }); client.on('data', (data) => { console.log(`Client received: ${data}`); if (data.toString().endsWith('exit')) { client.destroy(); } }); // Add a 'close' event handler for the client socket client.on('close', () => { console.log('Client closed'); }); client.on('error', (err) => { console.error(err); });
Sometimes the interaction with the server might be asynchronous and we may want to use the promise object. Let’s extend the above client in those lines by creating a class object.
const net = require('net'); const PORT = 1234, HOST = 'localhost'; class Client { … }
constructor() { this.socket = new new.socket(); this.port = PORT; this.address = HOST; this.init(); }
init() { var client = this; client.socket.connect(client.port, client.address, () => { console.log(`Client connected to: ${client.address} : ${client.port}`); }); client.socket.on('close', () => { console.log('Client closed'); }); }
sendMessage(message) { var client = this; return new Promise((resolve, reject) => { client.socket.write(message); client.socket.on('data', (data) => { resolve(data); if (data.toString().endsWith('exit')) { client.socket.destroy(); } }); client.socket.on('error', (err) => { reject(err); }); }); }
constnet = require('net'); constPORT = 1234, HOST = 'localhost'; classClient { constructor(port, address) { this.socket = newnet.Socket(); this.address = address || HOST; this.port = port || PORT; this.init(); } init() { varclient = this; client.socket.connect(client.port, client.address, () => { console.log(`Client connected to: ${client.address} : ${client.port}`); }); client.socket.on('close', () => { console.log('Client closed'); }); } sendMessage(message) { varclient = this; returnnewPromise((resolve, reject) => { client.socket.write(message); client.socket.on('data', (data) => { resolve(data); if (data.toString().endsWith('exit')) { client.socket.destroy(); } }); client.socket.on('error', (err) => { reject(err); }); }); } } module.exports = Client;
const Client = require(‘./client’); const promisifyClient = new Client();
promisifyClient.sendMessage(‘Hi’) .then((data) => { console.log(`Received: ${data}`); return promisifyClient.sendMessage('How are you'); }).then((data) => { console.log(`Received: ${data}`); return promisifyClient.sendMessage('Bye'); }).then((data) => { console.log(`Received: ${data}`); return promisifyClient.sendMessage('exit'); }).catch((err) => console.error(err));
constClient = require('./Client'); constpromisifyClient = newClient(); promisifyClient.sendMessage('Hi') .then((data) => { console.log(`Received: ${data}`); returnpromisifyClient.sendMessage('How are you'); }).then((data) => { console.log(`Received: ${data}`); returnpromisifyClient.sendMessage('Bye'); }).then((data) => { console.log(`Received: ${data}`); returnpromisifyClient.sendMessage('exit'); }).catch((err) =>console.error(err));
TLS(SSL) :
The ‘TLS’ module provides an implementation of Transport Layer Security (TLS) and Secure Socket Layer (SSL) protocols that are built on top of OpenSSL.
Understanding the Concepts: The TLS/SSL is a public/private key infrastructure (PKI). Each client and server must have a private key. A private key can be generated using the OpenSSL command-line interface.
With TLS/SSL, all server (and some clients) must have a certificate. Certificates are public keys that correspond to a private key, and that are digitally signed either by a Certificate Authority or by the owner of the private key (such certificates are referred to as "self-signed").
The only major differences between this and regular TCP connection are the private key and public certificate that you’ll have to set into an options object.
Before going further let's create the key and certificate (self-signed) using OpenSSL.
Key: openssl genrsa -out private-key.pem 1024
Certificate: openssl req -new -key private-key.pem -out csr.pem
Self-signed: openssl x509 -req -in csr.pem -signkey private-key.pem -out public-cert.pem
TLS Socket Server:
var tls = require(‘tls’); var fs = require(‘fs’);
var options = { key: fs.readFileSync(‘private-key.pem’), cert: fs.readFileSync(‘public-cert.pem’) };
var server = tls.createServer(options, function(socket) { socket.write("I am the server sending you a message."); // Print the data that we received socket.on('data', function(data) { console.log(`Received:${data.toString()}`); }); // Let us know when the transmission is over socket.on('end', function() { console.log('EOT (End Of Transmission)'); }); });
server.listen(PORT, HOST, () => console.log(‘TLS Server started listening’) );
// When an error occurs, show it. server.on('error', function(error) { console.error(error); // Close the connection after the error occurred. server.destroy(); });
vartls = require('tls'); varfs = require('fs'); constPORT = 1234; constHOST = 'localhost' varoptions = { key:fs.readFileSync('private-key.pem'), cert:fs.readFileSync('public-cert.pem') }; varserver = tls.createServer(options, function(socket) { // Send a friendly message socket.write("I am the server sending you a message."); // Print the data that we received socket.on('data', (data) => { console.log(`Received:${data.toString()}`) }); // Let us know when the transmission is over socket.on('end', function() { console.log('EOT (End Of Transmission)'); }); }); // Start listening on a specific port and address server.listen(PORT, HOST, function() { console.log("I'm listening at %s, on port %s", HOST, PORT); }); // When an error occurs, show it. server.on('error', function(error) { console.error(error); // Close the connection after the error occurred. server.destroy(); });
TLS Socket Client: Lets create a TLS client.
var tls = require('tls'); var fs = require('fs');
// Pass the certs to the server and let it know to process even unauthorized certs. var options = { key: fs.readFileSync('private-key.pem'), cert: fs.readFileSync('public-cert.pem'), rejectUnauthorized: false };
var client = tls.connect(PORT, HOST, options, function() { // Check if the authorization worked if (client.authorized) { console.log("Connection authorized by a Certificate Authority."); } else { console.log(`Connection not authorized: ${client.authorizationError}`); } // Send a friendly message client.write(`client connected to ${HOST}:${PORT}`); });
client.on("data", (data) => { console.log(`Received:${data}`); }); client.on('close', () => console.log("Connection closed")); // When an error occurs, show it. client.on('error', (error) => { console.error(error); // Close the connection after the error occurred. client.destroy(); });
vartls = require('tls'); varfs = require('fs'); constPORT = 1234; constHOST = 'localhost' // Pass the certs to the server and let it know to process even unauthorized certs. varoptions = { key:fs.readFileSync('private-key.pem'), cert:fs.readFileSync('public-cert.pem'), rejectUnauthorized:false }; varclient = tls.connect(PORT, HOST, options, function() { // Check if the authorization worked if (client.authorized) { console.log("Connection authorized by a Certificate Authority."); } else { console.log(`Connection not authorized: ${client.authorizationError}`); } // Send a friendly message client.write(`client connected to ${HOST}:${PORT}`); }); client.on("data", (data) => { console.log(`Received: ${data}`); }); client.on('close', () => { console.log("Connection closed"); }); // When an error ocoures, show it. client.on('error', (error) => { console.error(error); // Close the connection after the error occurred. client.destroy(); });
JavaScript is a dynamic computer programming language for the web. Jav...
Introduction: Angular (What is Angular?)Angular was formerly introdu...
Leave a Reply
Your email address will not be published. Required fields are marked *