WebSocket 101
WebSockets are a great and easy way to setup real-time communication in your (web)app/-site.
According to the ever-reliable-source Wikipedia, the definition of a WebSocket is the following:
WebSocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection.
This means as much that a WebSocket is a way for two or more computers to communicate with each other at the same time over a single network connection.
The WebSocket protocol was standardized by the Internet Engineering Task Force (IETF) as a mechanism for two-way communication that does not rely on opening multiple HTTP connections (like when using XMLHttpRequest or iframes and long polling).
Implementing WebSockets
The client has to create a WebSocket connection by performing what is called a handshake. The client sends a “regular” HTTP request to the server with a special Upgrade
header included to request the server for a WebSocket connection. If the server supports WebSockets it responds with another Upgrade
header.
The initial HTTP connection is replaced by a WebSocket connection that uses the same TCP/IP connection and the party is ready to start.
Implementing this handshake in a real-life project can be quite challenging to do by hand. MDN has a great in-depth article about creating this handshake on the server, but I recommend using one of the many available libraries.
Getting started in a Node.JS project
There are three main ways of implementing WebSockets in your application. You can setup the whole handshake and communications process yourself (but you probably shouldn’t want to), use a server-side only library, which allows you to setup a ws://
route, or use a full-fledged client- and server-library which handles everything for you from error-handling to fallbacks.
To setup an endpoint which uses the ws://
protocol you can use ws. WS is a thoroughly tested (and much used) WebSocket library which enables you to connect to and setup ws://
endpoints from within your Node.JS application.
Listening to all incoming WebSocket messages on a port can be done with a single line:
// server.js
const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 3000 });
With the server listening, you’re now ready to act on certain requests and messages like so:
// server.js
const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 3000 });wss.on('connection', ws => {
// Return received messages
ws.on('message', message => {
ws.send('Received: ' + message);
});
// Sends 'Hi there' as soon as someone connects
ws.send('Hi there');});
To connect to your WebSocket endpoint from a (web)client application, you can use the browser native WebSocket API like follows:
// client.js
const ws = new WebSocket('ws://localhost:3000');
Don’t forget to use the ws://
protocol instead of http
With the connection setup, you can now listen to events from the connection. There are four events that can happen during a WebSocket connection. Sending messages or closing the connection happens via a method:
// client.js
const ws = new WebSocket('ws://localhost:3000');// Events you can act on:
ws.addEventListener('open', doSomething);
ws.addEventListener('error', doSomething);
ws.addEventListener('message', doSomething);
ws.addEventListener('close', doSomething);ws.send('Hello server!');
ws.close();
Checkout this GitHub repo for the full sourcecode and a working demo: https://github.com/rijkvanzanten/websockets-101
Socket.io
Another popular option is the socket.io
library. Socket.io offers — just like ws—an easy way to get started with websockets. Socket.io provides an amazing amount of fallbacks which results in a great support for older browser which don’t support the WebSocket specification. Next to that, socket.io uses a custom layer on top of the default WebSocket spec to provide more stabillity.
There is one drawback to this though: you can’t connect to the WebSocket server without using a socket.io-client
package. Luckily, socket.io has a number of client libraries for a lot of popular languages ready for action but it’s something to keep in mind when you’re working with specific codebases.