Skip to main content
Version: 3.x

Custom parser

Since Socket.IO v2.0.0, it is now possible to provide your own parser, in order to control the marshalling / unmarshalling of packets.

Server

const httpServer = require("http").createServer();const io = require("socket.io")(httpServer, {  parser: myParser});

Client

const socket = io({  parser: myParser});

Implementing your own parser#

Here is a basic example with a parser that uses the JSON.stringify() and JSON.parse() methods:

const Emitter = require("component-emitter"); // polyfill of Node.js EventEmitter in the browser 
class Encoder {  /**   * Encode a packet into a list of strings/buffers   */  encode(packet) {    return [JSON.stringify(packet)];  }}
class Decoder extends Emitter {  /**   * Receive a chunk (string or buffer) and optionally emit a "decoded" event with the reconstructed packet   */  add(chunk) {    const packet = JSON.parse(chunk);    if (this.isPacketValid(packet)) {      this.emit("decoded", packet);    } else {      throw new Error("invalid format");    }  }  isPacketValid({ type, data, nsp, id }) {    const isNamespaceValid = typeof nsp === "string";    const isAckIdValid = id === undefined || Number.isInteger(id);    if (!isNamespaceValid || !isAckIdValid) {      return false;    }    switch (type) {      case 0: // CONNECT        return data === undefined || typeof data === "object";      case 1: // DISCONNECT        return data === undefined;      case 2: // EVENT        return Array.isArray(data) && data.length > 0;      case 3: // ACK        return Array.isArray(data);      case 4: // CONNECT_ERROR        return typeof data === "object";      default:        return false;    }  }  /**   * Clean up internal buffers   */  destroy() {}}
module.exports = { Encoder, Decoder };

The default parser#

The source code of the default parser (the socket.io-parser package) can be found here: https://github.com/socketio/socket.io-parser

Example of output:

  • basic emit
socket.emit("test", 42);

will be encoded as:

2["test",42]|||โ””โ”€ JSON-encoded payloadโ””โ”€ packet type (2 => EVENT)
  • emit with binary, acknowledgement and custom namespace
socket.emit("test", Uint8Array.from([42]), () => {  console.log("ack received");});

will be encoded as:

51-/admin,13["test",{"_placeholder":true,"num":0}]||||     || โ””โ”€ JSON-encoded payload with placeholders for binary attachments||||     |โ””โ”€ acknowledgement id||||     โ””โ”€ separator|||โ””โ”€ namespace (not included when it's the main namespace)||โ””โ”€ separator|โ””โ”€ number of binary attachmentsโ””โ”€ packet type (5 => BINARY EVENT)
and an additional attachment (the extracted Uint8Array)

Pros:

Cons:

  • packets with binary content are sent as two distinct WebSocket frames (if the WebSocket connection is established)

The msgpack parser#

This parser uses the MessagePack serialization format.

The source code of this parser can be found here: https://github.com/socketio/socket.io-msgpack-parser

Sample usage:

Server

const httpServer = require("http").createServer();const io = require("socket.io")(httpServer, {  parser: require("socket.io-msgpack-parser")});

Client (Node.js)

const socket = require("socket.io-client")("https://example.com", {  parser: require("socket.io-msgpack-parser")});

In the browser, there is now an official bundle which includes this parser:

In that case, you don't need to specify the parser option.

Pros:

  • packets with binary content are sent as one single WebSocket frame (if the WebSocket connection is established)
  • may results in smaller payloads (especially when using a lot of numbers)

Cons:

Please note that socket.io-msgpack-parser relies on the notepack.io MessagePack implementation. This implementation mainly focuses on performance and minimal bundle size, and thus does not support features like extension types. For a parser based on the official JavaScript implementation, please check this package.