Socket.js: real-time communication with WebSockets
January 21, 2016
I just released socket.js, a real-time communication framework for Node.js powered by WebSockets. It has no dependencies.
Introduction
Socket.js is lightweight. The minified client is under 5kb. Contrast this with socket.io, which is 95kb minified.
But it’s not a fair comparison. Socket.js relies on WebSockets and does not include any fallback transport mechanisms. So only use it when you can assume WebSocket support in your audience’s browsers. Most modern browsers support WebSockets; check here for a compatibility chart.
Socket.js is a well-behaved library. Unlike most event-based communication engines, socket.js will not:
- ...deliver messages out of order.
- ...deliver duplicate messages.
- ...deliver messages after the application thinks the socket has been closed.
- ...deliver queued up messages before the “reconnect” event is fired in the case of a temporary network failure.
- ...leak memory in the server or client.
- ...have undefined or insecure behavior if it receives a malformed or malicious message from a client.
Socket.js will:
- ...automatically reconnect if the connection is lost, unless it was intentionally closed by the application.
- ...validate inputs to all methods and fail fast.
- ...drop messages (and not resend them) if there is a network interruption.
That last point may be surprising to you. If you want messages to be resent in the case of failure, you must build that functionality into your application. The server has no idea if or when the client will come back, so it would have to keep queued messages for some arbitrary TTL and then subsequently vacuum them if the client never reconnects. Then, if the client finally does connect after the queue has been deleted, those messages would be dropped anyway. Socket.js is honest about its behavior: it will start dropping messages immediately if there is a network interruption, and it will start sending new messages once the connection is reestablished.
Socket.js was designed to support many simultaneous connections. If a connection is dropped, the server will not hold references to any queued messages or other data structures for that client. It is up to the client to provide any context needed by the server (e.g., a session ID for some session store) when reconnecting.
Installation
Server
Install socket.js with npm.
npm install socket.js
Client
The minified JavaScript can be found in the root directory of the repository.
<script src="socket.min.js"></script>
Server API
Socket.js exposes a single function:
var socketjs = require('socket.js'); socketjs(httpServer, handler);
httpServer
is an instance of http.Server
from the Node.js standard library. For example:var http = require('http'); var server = http.createServer(); server.listen(3000, function() { console.log('Listening on port 3000.'); });
handler
is a callback that takes two parameters, socket
and reconnectData
. socket
is an object with the following methods:socket.send(type, message)
sends a message to the client.type
is a string indicating the type of message.message
is any value that can be converted to JSON.socket.receive(type, handler)
registers a handler for a particular type of message.type
is a string, andhandler
is a function which takes the message as an argument. Ifhandler === null
, any existing handler for this message type is removed.socket.close(handler)
registers a callback to be invoked when the connection is closed, either intentionally or because of a network interruption. Ifhandler === null
, any existing handler for this event is removed. Ifhandler
is not provided (orhandler === undefined
), this method closes the socket.
reconnectData
is an optional value provided by the client when it reconnects in the case of a network interruption. If the client does not provide this value, it will be null
.Example server
var http = require('http'); var socketjs = require('socket.js'); // start an http server var server = http.createServer(); server.listen(3000, function() { console.log('Listening on port 3000.'); }); socketjs(server, function(socket, reconnectData) { // if we get disconnected and subsequently reconnect, the client can pass data here if (reconnectData === null) { console.log('A user connected.'); } else { console.log('A user reconnected with: ' + JSON.stringify(reconnectData) + '.'); } // log messages as they arrive socket.receive('greeting', function(message) { console.log('Received: ' + JSON.stringify(message)); }); // periodically send messages to the client var interval = setInterval(function() { socket.send('greeting', 'Hello from the server!'); }, 1000); // if the client disconnects, stop sending messages to it socket.close(function() { console.log('A user disconnected.'); clearInterval(interval); }); });
Client API
Socket.js exposes a top-level object named
socketjs
with two methods:socketjs.isSupported()
returns a boolean indicating whether the browser supports WebSockets.socketjs.connect(host, secure)
returns an object representing the connection to the server.host
is the name of the host and optionally the port, separated by a colon.secure
is a boolean indicating whether to use theWS
or theWSS
protocol. If these parameters are missing, Socket.js will attempt to connect to the host that served the page, using the same port and security level.
The object returned by
socketjs.connect()
supports the following methods:send(type, message)
sends a message to the server.type
is a string indicating the type of message.message
is any value that can be converted to JSON.socket.receive(type, handler)
registers a handler for a particular type of message.type
is a string, andhandler
is a function which takes the message as an argument. Ifhandler === null
, any existing handler for this message type is removed.socket.disconnect(handler)
registers a callback to be invoked when the network is interrupted. Ifhandler === null
, any existing handler for this event is removed.socket.reconnect(handler)
registers a callback to be invoked when the connection is restored after a network interruption. The value returned by the callback will be sent to the server (seereconnectData
above). Ifhandler === null
, any existing handler for this event is removed.socket.close(handler)
registers a callback to be invoked when the connection is closed by either the server or the client. Ifhandler === null
, any existing handler for this event is removed. Ifhandler
is not provided (orhandler === undefined
), this method closes the socket.
Example client
// make sure socket.js is supported if (socketjs.isSupported()) { // connect to the server var socket = socketjs.connect(); // log messages as they arrive socket.receive('greeting', console.log); // log a message if we get disconnected socket.disconnect(function() { console.log('Temporarily disconnected.'); }); // log a message when we reconnect socket.reconnect(function() { console.log('Reconnected.'); // whatever we return here is sent back to the server return 'reconnected'; }); // periodically send messages the server var interval = setInterval(function() { socket.send('greeting', 'Hello from the client!'); }, 1000); // if the server disconnects, stop sending messages to it socket.close(function() { console.log('Connection closed.'); clearInterval(interval); }); } else { // let the user know that socket.js is not supported console.log('Your browser does not support WebSockets.'); }