An important part of backend services is the ability to communicate with each other over sockets. Sockets allow one process to communicate with another process through an IP address and port. This can be useful when implementing interprocess communication (IPC) for two different processes running on the same server or accessing a service running on a completely different server. Node.js provides the net
module that allows you to create both socket servers and clients that can connect to socket servers. For secure connections, Node.js provides the tls
module that allows you to implement secure TLS socket servers and clients.
Network sockets are endpoints of communication that flow across a computer network. Sockets live below the HTTP layer and provide the actual point-to-point communication between servers. Virtually all Internet communication is based on Internet sockets that flow data between two points on the Internet.
A socket works using a socket address, which is a combination of an IP address and port. There are two types of points in a socket connection: a server that listens for connections and a client that opens a connection to the server. Both the server and the client require a unique IP address and port combination.
The Node.js net
module sockets communicate by sending raw data using the Transmission Control Protocol (TCP). This protocol is responsible for packaging the data and guaranteeing that it is sent from point to point successfully. Node.js sockets implement the Duplex
stream, which allows you to read and write streamed data between the server and client.
Sockets are the underlying structure for the http
module. If you do not need the functionality for handling web requests like GET
and POST
and you just need to stream data from point to point, then using sockets gives you a lighter weight solution and a bit more control.
Sockets are also handy when communicating with other processes running on the same computer. Processes cannot share memory directly, so if you want to access the data in one process from another process, you can open up the same socket in each process and read and write data between the two processes.
Socket
ObjectsTo use the net
module in Node.js applications, you first need to understand the TCP Server
and Socket
objects. These objects provide all the framework for starting a TCP server to handle requests and implementing TCP socket clients to make requests to the socket servers. Once you understand the events, properties, methods, and behavior of these objects, it will be simple to implement your own TCP socket servers and clients.
The following sections cover the purpose and behavior of the net.Socket
and net.Server
objects. The most important events, properties, and methods that each provides are also covered.
net.Socket
ObjectSocket
objects are created on both the socket server and the socket client and allow data to be written and read back and forth between them. The Socket
object implements a Duplex
stream, so it provides all the functionality that Writable
and Readable
streams provide. For example, you can use the write()
method to stream writes of data to the server or client and a data
event handler to stream data from the server or client.
On the socket client, the Socket
object is created internally when you call net.connect()
or net.createConnection()
. This object is intended to represent the socket connection to the server. You use the Socket
object to monitor the connection, send data to the server, and handle the response back from the server. There is no explicit client object in the Node.js net
module because the Socket
object acts as the full client allowing you to send/receive data and terminate the connection.
On the socket server, the Socket
object is created when a client connects to the server and is passed to the connection event handler. This object is intended to represent the socket connection to the client. On the server, you use the Socket
object to monitor the client connection as well as send and receive data to and from the client.
To create a Socket
object, you use one of the following methods. All the calls return a Socket
object. The only difference is the first parameters that they accept. The final parameter for all of them is a callback function that is executed when a connection is opened to the server. Notice that for each method there is a net.connect()
and a net.createConnection()
form. These work exactly the same way:
net.connect(options, [connectionListener]) net.createConnection(options, [connectionListener]) net.connect(port, [host], [connectListener]) net.createConnection(port, [host], [connectListener]) net.connect(path, [connectListener]) net.createConnection(path, [connectListener])
The first method to create a Socket
object is to pass an options
parameter, which is an object that contains properties that define the socket connection. Table 8.1 lists the properties that can be specified when creating the Socket
object. The second method accepts port
and host
values, described in Table 8.1, as direct parameters. The third option accepts a path
parameter that specifies a file system location that is a Unix socket to use when creating the Socket
object.
Table 8.1 Options that can be specified when creating a Socket
Property |
Description |
|
Port number the client should connect to. This option is required. |
|
Domain name or IP address of the server that the client should connect to. Defaults to |
|
Local IP address the client should bind to for network connections. |
|
The local port that it binds to for network connections. |
|
Version of IP stack. (default: 4) |
|
Custom lookup. (default: dns.lookup) |
Once the Socket
object is created, it provides several events that are emitted during the life cycle of the connection to the server. For example, the connect
event is triggered when the socket connects, the data
event is emitted when there is data in the Readable
stream ready to be read, and the close
event is emitted when connection to the server is closed. As you implement your socket server, you can register callbacks to be executed when these events are emitted to handle opening and closing the socket, reading and writing data, and so on. Table 8.2 lists the events that can be triggered on the Socket
object.
Table 8.2 Events that can be triggered on Socket
objects
Event |
Description |
|
Emitted when a connection is successfully established with the server. The callback function does not accept any parameters. |
|
Emitted when data is received on the socket. If no data event handler is attached, then data can be lost. The callback function must accept a parameter, which is a function(chunk){} |
|
Emitted when the server terminates the connection by sending a FIN. The callback function does not accept any parameters. |
|
Emitted when the connection to the server times out due to inactivity. |
Emitted when the write buffer becomes empty. You can use this event to throttle back the data stream being written to the socket. The callback function does not accept any parameters. |
|
|
Emitted when an error occurs on the socket connection. The callback function should accept the error as the only argument. For example: function(error){} |
|
Emitted when the socket has fully closed, either because it was closed by an |
The Socket
object also includes several methods that allow you to do things like read from and write to the socket as well as pause or end data flow. Many of these are inherited from the Duplex
stream objects and should be familiar to you. Table 8.3 lists the methods available on the Socket
object.
Table 8.3 Methods that can be called on Socket
Objects
Method |
Description |
|
When this function is called, data returned from the socket’s streams is an encoded |
|
Writes a data |
|
Writes a data |
|
This forces the socket connection to shut down. You should only need to use this in the case of failures. |
|
Pauses a |
|
Resumes |
Specifies a |
|
|
Disables/enables the Nagle algorithm that buffers data before sending it. Setting this to |
|
Enables/disables the keep-alive functionality on the connection. The optional |
|
Returns the bound address, the address family name, and the port of the socket as reported by the operating system. The return value is an object that contains the port, family, and address properties. For example: { port: 8107, family: 'IPv4', address: '127.0.0.1' } |
|
Calling this method allows the Node.js application to terminate if this socket is the only event on the event queue. |
|
References this socket so that if this socket is the only thing on the event queue, the Node.js application will not terminate. |
The Socket
object also provides several properties that you can access to get information about the object. For example, the address and port the socket is communicating on, the amount of data being written, and the buffer size. Table 8.4 lists the properties available on the Socket
object.
Table 8.4 Properties that can be accessed on Socket
Objects
Method |
Description |
|
Returns the number of bytes currently buffered waiting to be written to the socket’s stream |
|
IP address of the remote server that the socket is connected to |
|
Port of the remote server that the socket is connected to |
|
IP of the remote family the socket is connected to |
|
Local IP address the remote client is using for the socket connection |
Local port the remote client is using for the socket connection |
|
|
Number of bytes read by the socket |
|
Number of bytes written by the socket |
To illustrate flowing data across a Socket
object, the following code shows the basics of implementing the Socket
object on a client. Notice that the net.connect()
method is called using an options
object containing a port
and a host
attribute. The connect
callback function logs a message and then writes some data out to the server. To handle data coming back from the server, the on.data()
event handler is implemented. To handle the closure of the socket, the on('end')
event handler is implemented:
var net = require('net'); var client = net.connect({port: 8107, host:'localhost'}, function() { console.log('Client connected'); client.write('Some Data '); }); client.on('data', function(data) { console.log(data.toString()); client.end(); }); client.on('end', function() { console.log('Client disconnected'); });
net.Server
ObjectThe net.Server
object is used to create a TCP socket server and begin listening for connections to which you will be able to read and write data. The Server
object is created internally when you call net.createServer()
. This object represents the socket server and handles listening for connections and then sending and receiving data on those connections to the server.
When the server receives a connection, the Server
creates a Socket
object and passes it to any connection event handlers that are listening. Because the Socket
object implements a Duplex
stream, you can use the write()
method to stream writes of data back to the client and a data
event handler to stream data from the client.
To create a Server
object, you use the net.createServer()
method shown here:
net.createServer([options], [connectionListener])
The options
parameter is an object that specifies options to use when creating the socket Server
object. Table 8.5 lists the properties of the options
object. The second parameter is the connection
event callback function, which is executed when a connection is received. This connectionListener
callback function is passed to the Socket
object for the connecting client.
Table 8.5 Options that can be specified when creating a net.Server
Property |
Description |
|
A Boolean; when |
|
A Boolean; when |
Once the Server
object is created, it provides several events that are triggered during the life cycle of the server. For example, the connection
event is triggered when a socket client connects, and the close
event is triggered when the server shuts down. As you implement your socket server, you can register callbacks to be executed when these events are triggered to handle connections, errors, and shutdown. Table 8.6 lists the events that can be triggered on the Socket
object.
Table 8.6 Events that can be triggered on Socket
objects
Event |
Description |
|
Emitted when the server begins listening on a port by calling the |
|
Emitted when a connection is received from a socket client. The callback function must accept a parameter that is a function(client){} |
|
Emitted when the server closes either normally or on error. This event is emitted until all client connections have ended. |
|
Emitted when an error occurs. The |
The Server
object also includes several methods that allow you to do things like read from and write to the socket as well as pause or end data flow. Many of these are inherited from the Duplex
stream objects and should be familiar to you. Table 8.7 lists the methods available on the Socket
object.
Table 8.7 Methods that can be called on Socket
objects
Method |
Description |
|
Opens up a port on the server and begins listening for connections. The callback function is called when the server has opened the port and begins listening. |
|
Same as the preceding method except that a Unix socket server is started to listen for connections on the file system |
|
Same as the preceding method except that a handle to a |
|
Returns the number of connections currently connected to the server. The function(error, count) |
|
Stops the server from accepting new connections. Current connections are allowed to remain until they complete. The server does not truly stop until all current connections have been closed. |
|
Returns the bound address, the address family name, and the port of the socket as reported by the operating system. The return value is an object that contains the port, family, and address properties. For example: { port: 8107, family: 'IPv4', address: '127.0.0.1' } |
|
Calling this method allows the Node.js application to terminate if this server is the only event on the event queue. |
|
References this socket so that if this server is the only thing on the event queue the Node.js application will not terminate. |
The Server
object also provides the maxConnections
attribute, which allows you to set the maximum number of connections that the server will accept before rejecting them. If a process has been forked to a child for processing using child_process.fork()
, you should not use this option.
The following code shows the basics of implementing the Server
object. Notice that the net.createServer()
method is called and implements a callback that accepts the client Socket
object. To handle data coming back from the client, the on.data()
event handler is implemented. To handle the closure of the socket, the on('end')
event handler is implemented. To begin listening for connections, the listen()
method is called on port 8107
:
var net = require('net'); var server = net.createServer(function(client) { console.log(Client connected'); client.on('data', function(data) { console.log('Client sent ' + data.toString()); }); client.on('end', function() { console.log('Client disconnected'); }); client.write('Hello'); }); server.listen(8107, function() { console.log('Server listening for connections'); });
Now that you understand the net.Server
and net.Socket
objects, you are ready to implement some Node.js TCP clients and servers. This section guides you through the process of implementing basic TCP clients and servers in Node.js.
The examples in the following sections are basic to make it easy for you to grasp the concepts of starting the TCP server listening on a port, and then implementing clients that can connect. The examples are designed to help you see the interactions and event handling that need to be implemented.
At the most basic level, implementing a TCP socket client involves the process of creating a Socket
object that connects to the server, writing data to the server, and then handling the data that comes back. Additionally, you should build the socket so that it can also handle errors, the buffer being full, and timeouts. This section discusses each of the steps to implement a socket client using the Socket
object. Listing 8.1 presents the full code for the following discussion.
The first step is to create the socket client by calling net.connect()
as shown below. Pass in the port
and host
that you want to connect to as well and implement a callback
function to handle the connect
event:
net.connect({port: 8107, host:'localhost'}, function() { //handle connection });
Then inside the callback you should set up the connection behavior. For example, you may want to add a timeout or set the encoding as shown here:
this.setTimeout(500); this.setEncoding('utf8');
You also need to add handlers for the data
, end
, error
, timeout
, and close
events that you want to handle. For example, to handle the data
event so that you can read data coming back from the server, you might add the following handler once the connection has been established:
this.on('data', function(data) { console.log("Read from server: " + data.toString()); //process the data this.end(); });
To write data to the server, you implement a write()
command. If you are writing a lot of data to the server and the write fails, then you may also want to implement a drain
event handler that begins writing again when the buffer is empty. The following shows an example of implementing a drain handler because of a write failure. Notice that a closure is used to preserve the values of the socket and data
variables once the function has ended.
function writeData(socket, data){ var success = !socket.write(data); if (!success){ (function(socket, data){ socket.once('drain', function(){ writeData(socket, data); }); })(socket, data); } }
Listing 8.1 shows the full implementation of a basic TCP socket client. All the client does is send a bit of data to the server and receive a bit of data back; however, the example could easily be expanded to support more complex data handling across the socket. Notice that three separate sockets are opened to the server and are communicating at the same time. Notice that each client created gets a different random port number, as shown in Listing 8.1 Output.
Listing 8.1 socket_client.js
: Implementing basic TCP socket clients
01 var net = require('net'); 02 function getConnection(connName){ 03 var client = net.connect({port: 8107, host:'localhost'}, function() { 04 console.log(connName + ' Connected: '); 05 console.log(' local = %s:%s', this.localAddress, this.localPort); 06 console.log(' remote = %s:%s', this.remoteAddress, this.remotePort); 07 this.setTimeout(500); 08 this.setEncoding('utf8'); 09 this.on('data', function(data) { 10 console.log(connName + " From Server: " + data.toString()); 11 this.end(); 12 }); 13 this.on('end', function() { 14 console.log(connName + ' Client disconnected'); 15 }); 16 this.on('error', function(err) { 17 console.log('Socket Error: ', JSON.stringify(err)); 18 }); 19 this.on('timeout', function() { 20 console.log('Socket Timed Out'); 21 }); 22 this.on('close', function() { 23 console.log('Socket Closed'); 24 }); 25 }); 26 return client; 27 } 28 function writeData(socket, data){ 29 var success = !socket.write(data); 30 if (!success){ 31 (function(socket, data){ 32 socket.once('drain', function(){ 33 writeData(socket, data); 34 }); 35 })(socket, data); 36 } 37 } 38 var Dwarves = getConnection("Dwarves"); 39 var Elves = getConnection("Elves"); 40 var Hobbits = getConnection("Hobbits"); 41 writeData(Dwarves, "More Axes"); 42 writeData(Elves, "More Arrows"); 43 writeData(Hobbits, "More Pipe Weed");<Listing First>
Listing 8.1 Output socket_client.js
: Implementing basic TCP socket clients
Elves Connected: local = 127.0.0.1:62616 remote = 127.0.0.1:8107 Dwarves Connected: local = 127.0.0.1:62617 remote = 127.0.0.1:8107 Hobbits Connected: local = 127.0.0.1:62618 remote = 127.0.0.1:8107 Elves From Server: Sending: More Arrows Dwarves From Server: Sending: More Axes Hobbits From Server: Sending: More Pipe Weed Dwarves Client disconnected Socket Closed Elves Client disconnected Socket Closed Hobbits Client disconnected Socket Closed
At the most basic level, implementing a TCP server client involves the process of creating a Server
object, listening on a port, and then handling incoming connections, including reading and writing data to and from the connections. Additionally, the socket server should handle the close
and error
events on the Server
object as well as the events that occur in the incoming client connection Socket
object. This section discusses each of the steps to implement a socket server using the Server
object. Listing 8.2 presents the full code for the following discussion.
The first step is to create the socket server by calling net.createServer()
as shown below. You also need to provide a connection callback handler and then call listen()
to begin listening on the port:
var server = net.createServer(function(client) { //implement the connection callback handler code here. }); server.listen(8107, function() { //implement the listen callback handler here. });
Inside the listen
callback handler, you should also add handlers to support the close
and error
events on the Server
object. These may just be log statements, or you may also want to add additional code that is executed when these events occur. The follow shows the basic examples:
server.on('close', function(){ console.log('Server Terminated'); }); server.on('error', function(err){ });
Inside the connection
event callback, you need to set up the connection behavior. For example, you might want to add a timeout or set the encoding as shown here:
this.setTimeout
(500);
this.setEncoding('utf8');
You also need to add handlers for the data
, end
, error
, timeout
, and close
events that you want to handle on the client connection. For example, to handle the data
event so that you can read data coming from the client, you might add the following handler once the connection is established:
this.on('data', function(data) { console.log("Received from client: " + data.toString()); //process the data });
To write data to the server, you implement a write()
command somewhere in your code. If you are writing a lot of data to the client, then you may also want to implement a drain
event handler that begins writing again when the buffer is empty. This can help if the write()
returns a failure because the buffer is full, or if you want to throttle back writing to the socket. The following shows an example of implementing a drain handler because of a write failure. Notice that a closure is used to preserve the values of the socket and data variables once the function has ended:
function writeData(socket, data){ var success = !socket.write(data); if (!success){ (function(socket, data){ socket.once('drain', function(){ writeData(socket, data); }); })(socket, data); } }
The code in Listing 8.2 shows the full implementation of a basic TCP socket server. The socket server accepts connections on port 8107
, reads the data in, and then writes a string back to the client. Although the implementation is basic, it illustrates handling the events as well as reading and writing data in the client connection.
Listing 8.2 socket_server.js
: Implementing a basic TCP socket server
01 var net = require('net'); 02 var server = net.createServer(function(client) { 03 console.log('Client connection: '); 04 console.log(' local = %s:%s', client.localAddress, client.localPort); 05 console.log(' remote = %s:%s', client.remoteAddress, client.remotePort); 06 client.setTimeout(500); 07 client.setEncoding('utf8'); 08 client.on('data', function(data) { 09 console.log('Received data from client on port %d: %s', 10 client.remotePort, data.toString()); 11 console.log(' Bytes received: ' + client.bytesRead); 12 writeData(client, 'Sending: ' + data.toString()); 13 console.log(' Bytes sent: ' + client.bytesWritten); 14 }); 15 client.on('end', function() { 16 console.log('Client disconnected'); 17 server.getConnections(function(err, count){ 18 console.log('Remaining Connections: ' + count); 19 }); 20 }); 21 client.on('error', function(err) { 22 console.log('Socket Error: ', JSON.stringify(err)); 23 }); 24 client.on('timeout', function() { 25 console.log('Socket Timed Out'); 26 }); 27 }); 28 server.listen(8107, function() { 29 console.log('Server listening: ' + JSON.stringify(server.address())); 30 server.on('close', function(){ 31 console.log('Server Terminated'); 32 }); 33 server.on('error', function(err){ 34 console.log('Server Error: ', JSON.stringify(err)); 35 }); 36 }); 37 function writeData(socket, data){ 38 var success = !socket.write(data); 39 if (!success){ 40 (function(socket, data){ 41 socket.once('drain', function(){ 42 writeData(socket, data); 43 }); 44 })(socket, data); 45 } 46 }
Transport Layer Security/Secure Socket Layer (TLS/SSL) is a cryptographic protocol designed to provide secure communications on the Internet. They use X.509 certificates along with session keys to verify whether the socket server you are communicating with is the one that you want to communicate with. TLS provides security in two main ways. First, it uses long-term public and secret keys to exchange a short-term session key so that data can be encrypted between client and server. Second, it provides authentication so that you can ensure that the webserver you are connecting to is the one you actually think it is, thus preventing man-in-the-middle attacks where requests are rerouted through a third party.
The following sections discuss implementing TLS socket servers and clients in your Node.js environment using the tls
module. Before getting started using TLS, you need to generate a private key and public certificate for both your clients and your server. There are several ways to do this depending on your platform. One of the simplest methods is to use the OpenSSL library for your platform.
To generate the private key, first execute the following OpenSSL command:
openssl genrsa -out server.pem 2048
Next, use the following command to create a certificate signing request file:
openssl req -new -key server.pem -out server.csr
Note
When creating the certificate signing request file, you are asked several questions. When prompted for the Common Name, you should put in the domain name of the server you want to connect to. Otherwise, the certificate will not work. Also you can put in additional domain names and IP addresses in the Subject Alternative Names field.
Then to create a self-signed certificate that you can use for your own purpose or testing, use the following command:
openssl x509 -req -days 365 -in server.csr -signkey server.pem -out server.crt
Note
The self-signed certificate is fine for testing purposes or internal use. However, if you are implementing an external web service that needs to be protected on the Internet, you may want to get a certificate signed by a certificate authority. If you want to create a certificate that is signed by a third-party certificate authority, you need to take additional steps.
Creating a TLS client is almost exactly like the process of creating a socket client discussed earlier in this chapter. The only difference is that there are additional options, shown in Table 8.8, that allow you to specify the security options for the client. The most important options you need to worry about are key
, cert
, and ca
.
The key
option specifies the private key used for SSL. The cert
value specifies the x509 public key to use. If you are using a self-signed certificate, you need to point the ca
property at the certificate for the server:
var options = { key: fs.readFileSync('test/keys/client.pem'), cert: fs.readFileSync('test/keys/client.crt'), ca: fs.readFileSync('test/keys/server.crt') };
Once you have defined the options with the cert
, key
, and ca
settings, then you can call the tls.connect(options, [responseCallback])
, and it will work exactly the same as the net.connect()
call. The only difference is that the data between the client and server is encrypted.
var options = { hostname: 'encrypted.mysite.com', port: 8108, path: '/', method: 'GET', key: fs.readFileSync('test/keys/client.pem'), cert: fs.readFileSync('test/keys/client.crt'), ca: fs.readFileSync('test/keys/server.crt') }; var req = tls.connect(options, function(res) { <handle the connection the same as an net.connect> })
Table 8.8 Additional options for tls.connect()
Event |
Description |
|
A string or |
|
A string or |
|
A string containing the passphrase for the private key or |
|
A string or |
|
An array of strings or buffers of trusted certificates in PEM format to check the remote host against. |
|
A Boolean; when true, the server certificate is verified against the list of supplied CAs. An error event is emitted if verification fails. Verification happens at the connection level, before the HTTP request is sent. Defaults to |
|
Specifies the server name for the Server Name Indication SNI TLS extension. |
|
Specifies the SSL method to use. For example, |
Creating a TLS socket server is almost exactly like the process of creating a socket server discussed earlier in this chapter. The only differences are that there are additional options
parameters that you must pass into https.createServer()
, and there are some additional events that can be triggered on the tls.Server
object. The options, listed in Table 8.9, allow you to specify the security options for the server. Table 8.10 lists the additional events for the TLS socket server. The most important options you need to worry about are key
, cert
, and ca
.
The key
option specifies the private key used for SSL. The cert
value specifies the x509 public key to use. If you are using a self-signed certificate, you need to point the ca
property at the certificate for the client.
Table 8.9 Additional options for tls.createServer()
Event |
Description |
|
A string or |
|
A string or |
|
A string containing the passphrase for the private key or |
|
A string or |
|
An array of strings or buffers of trusted certificates in PEM format to check the remote host against. |
|
Either a string or list of strings of PEM encoded CRLs (Certificate Revocation Lists). |
|
A string describing the ciphers to use or exclude. Using this in conjunction with the |
|
Specifies the number of milliseconds to wait before aborting the connection if the SSL/TLS handshake does not finish. If the timeout is hit, a |
|
A Boolean; when |
|
When |
|
When |
|
An |
|
A function that is called if the client supports the SNI TLS extension. The server name is the only argument passed to the callback. |
|
A string containing an opaque identifier for session resumption. If |
|
Specifies the SSL method to use. For example, |
The following shows an example of creating a TLS socket server in Node.js:
var options = { key: fs.readFileSync('test/keys/server.pem'), cert: fs.readFileSync('test/keys/server.crt'), ca: fs.readFileSync('test/keys/client.crt') }; tls.createServer(options, function (client) { client.write("Hello Secure World "); client.end(); }).listen(8108);
Once the TLS socket server has been created, the request/response handling works basically the same way that the TCP socket servers described earlier in this chapter work. The server can accept connections and read and write data back to the client.
Table 8.10 Additional events on TLS Server
objects
Event |
Description |
|
Emitted when a new secure connection has been successfully established. The callback accepts a single instance of a function (clearStream) |
|
Emitted when a client connection emits an error. The parameters to the callback are the error and a function (error, securePair) |
|
Emitted when a new TLS session is created. The callback is passed the function ( |
|
Emitted when the client tries to resume a previous TLS session. You can store the session in an external storage so that you can look it up when receiving this event. The callback handler receives two parameters. The first is a function ( |
Sockets are useful when implementing backend services in a Node.js application. They allow a service on one system to communicate with a service on another system through an IP address and port. They also provide the ability to implement an IPC between two different processes running on the same server. The net
module allows you to create Server
objects that act as socket servers and Socket
objects that act as socket clients. Since the Socket
object extends Duplex
streams, you can read and write data from both the server and the client. For secure connections, Node.js provides the tls
module that allows you to implement secure TLS socket servers and clients.
18.223.206.69