+
The WebSocket protocol is an extension to the HTTP ecosystem which allows to create live connections between a
+web server and a web browser, enabling web applications to efficiently exchange data in real-time without the overhead
+of conventional HTTP connections. Node.js is perfectly suited for writing WebSocket applications, and this tutorial
+explains how it all works.
+
+
Where WebSocket connections beat HTTP connections
+
+
The HTTP protocol obviously does a great job at enabling data exchange between a webserver and a browser, hence the
+extraordinary success of the World Wide Web. So why does the Web need another protocol? It’s two aspects that are
+relevant here: bi-directionality and real-time.
+
+
HTTP connections: neither bi-directional nor real-time
+
+
The “conventional” Web, built on HTTP, is based on a client-server model with the client (the web browser) in the lead.
+
+
Conventional HTTP web servers do nothing on their own without being explicitly asked by a client. Getting some kind
+of information - for example, the current price of a stock, in the form of a web page with stock market information -
+requires the browser to actively ask the server for that information, e.g. by issueing a GET request to the web page
+at, say, http://stocks.example.com/company/apple-inc.
+
+
This is only triggered by a human user who decides to visit this page. If this user wants to learn the most recent stock
+price again at a later point in time, he or she has to reload the page.
+
+
If the webpage wants to supply the most recent stock price to the user regularly without requiring the user to manually
+reload the page, then workarounds exist. The most common workaround is to run some JavaScript code in the webpage which
+regularly “polls” a webservice from the server which responds with the current stock price, via AJAX. If the new stock
+price is different from the one on the page, then the client-side JavaScript code can update the webpage content and
+present the new price to the user.
+
+
This improves the interactivity of the site, but it is not optimal: If stock price updates need to be reported to the
+user as soon as possible, the JavaScript code needs to query the webservice with high frequency - for example, every
+5 seconds. And if the requirement is to inform the user about a stock price change no later than 1 second after the
+change occured, then a new request must be send to the server every second.
+
+
But that’s not a real solution to the requirement of getting the info from the server proactively - you are just asking
+very often, which isn’t exactly efficient. Imagine that there is no stock price change for 10 minutes. That’s 600 HTTP
+requests from the client to the webserver with no useful results at all. That is wasting a lot of traffic and computing
+resources on both the client and the server.
+
+
Also, there’s a limit to the frequency at which the client can ask the server for new content. Using AJAX, you can get
+near-time updates from the server to the client, but doing real-time updates efficiently is out of the question.
+
+
This is why until now, complex applications which update many different information on the screen fluidly and in
+real-time are seldom seen on the web and are usually implemented as full-fledged desktop applications. But the WebSocket
+protocol is about to change this.
+
+
WebSocket connections: putting the webserver in the lead
+
+
The important conceptual change that the WebSocket protocol brings to the table is that it allows the client
+to establish a connection with the web server which a) stays open as long as the web page is opened in the browser, and
+which b) the web server can actively use to send data to the client whenever the server wants to, without being asked by
+the client to do so.
+
+
Thus, in addition to the client-server model of HTTP, we now have a model of a truly bi-directional connection, with
+both partners of the connection being equal.
+
+
As a result, this allows for data exchange that is much more efficient and happens real-time. In our stock price
+example, the server can “push” a stock price update over the connection as soon as it occurs, and only if and when it
+occurs. If there is no stock price update for 10 minutes, then the exchanged data during these 10 minutes is zero. And
+when the update finally occurs, the client learns about it immediately, and not when it happens to ask.
+
+
How WebSocket connections work
+
+
Conceptually, the WebSocket protocol is an extension to HTTP which allows clients to “upgrade” an HTTP connection with
+an additional bi-directional connection which remains established, like this:
+
+
+- Client opens HTTP connection to server and asks for document
+- Server responds with an HTML document
+- HTTP connection is closed
+- JavaScript code in the HTML document opens another HTTP connection in which it asks the server to upgrade this
+connection to a WebSocket connection
+- A WebSocket connection between client and server is established and remains open for sending and receiving data in
+both directions
+
+
+
Technically, a WebSocket connection is simply a TCP connection on port 80, just like normal HTTP connections are -
+with the difference that client and server treat the connection in a special way.
+
+
Creating a WebSocket connection from an HTTP connection requires knowledge about the details of the HTTP and WebSocket
+protocols, but luckily, easy-to-use libraries exist which provide a nice and straightforward abstraction of these
+details both on the server and the client side. We will look at how to use these in Node.js now.
+
+
How to use WebSocket connections in your web application
+
+
By now we learned that the client-side JavaScript code on a webpage needs to intitiate a WebSocket connection, and
+the server-side code needs to handle such a request accordingly. Thus, specialised client and server code is neccessary.
+
+
How do we get there?
+
+
When working with Node.js, it’s not difficult at all. The most straightforward and
+efficient approach is to use a JavaScript library which provides the neccessary methods for both sides - a client part
+which is executed by the user’s web browser, and a server part which runs within an existing Node.js HTTP server.
+
+
The most mature and most popular library for this is Socket.io. Let’s use this to write a simple
+WebSocket stock price ticker application.
+
+
As said, we need to take care of both the client side and the server side to get a WebSocket application up and running.
+We start with the server side, which we’ll of course implement using Node.js.
+
+
From a Node.js perspective, Socket.io is simply an NPM library. However, we are not going to install it just yet.
+Socket.io doesn’t work on it’s own - it is not a full-fledged Node.js webserver or web application framework. It needs
+a webserver or framework to integrate with, and we’ll set that up first, using the popular Node.js web framework
+Express.js.
+
+
To do so, create a new project folder called websocket-test, and create the following package.json inside:
+
+
{
+ "name": "websocket-stock-ticker",
+ "version": "0.0.1",
+ "description": "WebSocket Stock Ticker",
+ "dependencies": {}
+}
+
+
+
Then, pull in Express.js via NPM: npm install --save express.
+
+
You can now create a very basic Express.js based HTTP webserver, in file index.js:
+
+
var app = require('express')();
+var http = require('http').Server(app);
+
+app.get('/', function(req, res) {
+ res.sendFile(__dirname + '/index.html');
+});
+
+http.listen(8000, function() {
+ console.log('Listening on *:8000');
+});
+
+
+
This creates an HTTP webserver listening on port 8000, which serves file index.html through the Express.js route
+handler when requested at path /.
+
+
However, file index.html does not yet exist, so let’s create that in the same folder:
+
+
<!doctype html>
+<html>
+ <head>
+ <title>Live stock price ticker</title>
+ </head>
+ <body>
+ Stock price: <span id="stockprice">no data yet</span>
+ </body>
+</html>
+
+
+
If you start the application with node index.js and open address http://localhost:8000 in your browser, you are
+going to see a very basic web page which shows Stock price: no data yet as its content.
+
+
We have laid the foundation for our live stock price ticker application, but that no data yet part of the web page
+needs to be updated regularly with the most current stock price, and this of course will be done through a WebSocket
+connection between the page on the client side and our Node.js server.
+
+
As stated above, it is the client that has to initiate a WebSocket connection. Right now, we do not yet have any
+JavaScript in our web page which could do that, so let’s change that.
+
+
To do so, we need to integrate the client-side part of Socket.io into our page. For a real and production-ready
+environment, we would probably want to download and integrate this library - called socket.io-client - ourselves, but
+for getting a quick prototype of our application up and running, it’s sufficient to let our server-side code serve the
+client-side library automatically.
+
+
This is achieved by installing and integrating the server-side part of Socket.io into our Node.js application.
+
+
Installation is done by running npm install --save socket.io, and afterwards, we can integrate it with our Express.js
+server:
+
+
var app = require('express')();
+var http = require('http').Server(app);
+var io = require('socket.io')(http);
+
+app.get('/', function(req, res) {
+ res.sendFile(__dirname + '/index.html');
+});
+
+io.on('connection', function(socket){
+ console.log('A new WebSocket connection has been established');
+});
+
+http.listen(8000, function() {
+ console.log('Listening on *:8000');
+});
+
+
+
This pulls a Socket.io object into our code in variable io. It is immediately integrated with our Express http
+server object - Socket.io knows how to hook into an Express.js server out of the box, so we don’t need to do any
+integration work ourselves.
+
+
This integration also results in the creation of a new Express.js route - when our webserver is requested at
+http://localhost:8000/socket.io/socket.io.js, it serves the client-side Socket.io library. Again, this is nothing we
+have to do ourselves in our own code. The line var io = require('socket.io')(http); takes care of this automatically
+and behind the scenes.
+
+
What we do have to code ourselves is to add an event listener which handles events from the WebSocket connection.
+
+
For now, we only react to the event that is triggered when a new client establishes a WebSocket connection. To do so,
+we attach an anonymous function to the connection event emitted my the io object. We use it to generate log output.
+
+
+Learn all about Event Listeners and Event Emitters from my new book,
+The Node Craftsman Book. It comes
+bundled with The Node Beginner Book, and both together are
+now available via Leanpub for only $9.
+
+
+
If you restart the Node.js server and again load page http://localhost:8000 in your browser, nothing new happens.
+
+
This is because our web page does not yet open up a WebSocket connection. We need to code this now, in file
+index.html:
+
+
<!doctype html>
+<html>
+ <head>
+ <title>Live stock price ticker</title>
+
+ <script src="/socket.io/socket.io.js"></script>
+ <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
+
+ <script>
+ $(function () {
+ var socket = io();
+ });
+ </script>
+
+ </head>
+ <body>
+ Stock price: <span id="stockprice">no data yet</span>
+ </body>
+</html>
+
+
+
As you can see, we load the Socket.io client library which is now provided by the Socket.io server library. Note that we
+also pull in jQuery - this is not strictly neccessary, but it makes it easier to manipulate the web page content.
+
+
If again you reload the web page (no need to restart the server here), you will now see
+“A new WebSocket connection has been established” being outputted by the server.
+
+
With this, everything is in place to actively push data from the server to the web page. Let’s do this now.
+
+
Again, we start on the server side. We do not have real stock prices, so we will just generate a new random stock price
+value every second for each client that connects, and push it out to all connected clients:
+
+
var app = require('express')();
+var http = require('http').Server(app);
+var io = require('socket.io')(http);
+
+app.get('/', function(req, res) {
+ res.sendFile(__dirname + '/index.html');
+});
+
+io.on('connection', function(socket) {
+ console.log('A new WebSocket connection has been established');
+});
+
+setInterval(function() {
+ var stockprice = Math.floor(Math.random() * 1000);
+ io.emit('stock price update', stockprice);
+}, 1000);
+
+http.listen(8000, function() {
+ console.log('Listening on *:8000');
+});
+
+
+
The key function here is io.emit - Socket.io tracks all client connections internally, and emit sends out a message
+to all these clients. This is the most simple way to get data from the WebSocket server to the WebSocket clients, but
+for our demo application it’s good enough.
+
+
Each message sent via emit has an event name - in our case, that’s stock price update - and a value, which is the
+new stock price we calculated. We can make up event names on the fly - we just need to make sure that clients work with
+the same event names to make them useful. And we can send any basic JavaScript values, like strings, booleans, numbers,
+arrays, objects etc.
+
+
We don’t need to do anything on the client side to make the WebSocket client receive these messages, but we need to
+extend our code if we want to make the client do anything useful with it. In this case, let’s update the stock price
+display whenever a new message arrives. By combining Socket.io and jQuery, this is difficult:
+
+
<!doctype html>
+<html>
+ <head>
+ <title>Live stock price ticker</title>
+
+ <script src="/socket.io/socket.io.js"></script>
+ <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
+
+ <script>
+ $(function () {
+ var socket = io();
+
+ socket.on('stock price update', function(stockprice) {
+ $('#stockprice').text(stockprice);
+ });
+
+ });
+ </script>
+
+ </head>
+ <body>
+ Stock price: <span id="stockprice">no data yet</span>
+ </body>
+</html>
+
+
+
As you can see, we have added an event listener on the socket object right after we created it. This listener reacts
+to all received messages whose event name is stock price update. Attached to the event listener is an anonymous
+function which receives the value part of the message whenever the listener triggers it - in our case, we know that this
+value is the latest stock price.
+
+
We then use this value to update the text content of the <span> element with id stockprice, using jQuery.
+
+
If you reload the updated page, you still see the no data yet text for a moment, but then the stock price updates are
+reflected on the page each seconds. If you open multiple browser windows or tabs, you should see the same stock price
+value being displayed and updated at the same time.
+
+
An update cycle of 1000 ms still feels very “normal HTTP-ish” - let’s prove how WebSocket connections can really make
+server-side updates to web page contents feel much smoother, by changing our server code to this:
+
+
var app = require('express')();
+var http = require('http').Server(app);
+var io = require('socket.io')(http);
+
+app.get('/', function(req, res) {
+ res.sendFile(__dirname + '/index.html');
+});
+
+io.on('connection', function(socket) {
+ console.log('A new WebSocket connection has been established');
+});
+
+setInterval(function() {
+ var stockprice = Math.floor(Math.random() * 1000);
+ io.emit('stock price update', stockprice);
+}, 50);
+
+http.listen(8000, function() {
+ console.log('Listening on *:8000');
+});
+
+
+
The only change is the setInterval timing, from 1000 ms to 50 ms. When you restart the server and again open the web
+page in multiple browser windows, you can see the efficiency and performance of WebSocket applications in action.
+
+
+
+
+Learn more about writing web applications using Node.js
+with The Node Beginner Book - the first part of this step-by-step Node.js tutorial
+is available for free!
+
+