๐Ÿ“ฆ socketio / engine.io-protocol

Engine.IO protocol

โ˜… 248 stars โ‘‚ 46 forks ๐Ÿ‘ 248 watching
javascriptnodejswebsocket
๐Ÿ“ฅ Clone https://github.com/socketio/engine.io-protocol.git
HTTPS git clone https://github.com/socketio/engine.io-protocol.git
SSH git clone git@github.com:socketio/engine.io-protocol.git
CLI gh repo clone socketio/engine.io-protocol
Guillermo Rauch Guillermo Rauch README: point to reference implementation 4f391be 11 years ago ๐Ÿ“ History
๐Ÿ“‚ 4f391be65d3fd7957f8198c4400eb6b2a2399193 View all commits โ†’
๐Ÿ“„ .gitignore
๐Ÿ“„ README.md
๐Ÿ“„ README.md

Engine.IO Protocol

This document describes the Engine.IO protocol. For a reference JavaScript implementation, take a look at engine.io-parser, engine.io-client and engine.io.

Revision

This is revision 3 of the Engine.IO protocol.

Anatomy of an Engine.IO session

  • Transport establishes a connection to the Engine.IO URL .
  • Server responds with an open packet with JSON-encoded handshake data:
  • sid session id (String)
  • upgrades possible transport upgrades (Array of String)
  • pingTimeout server configured ping timeout, used for the client
to detect that the server is unresponsive (Number)
  • Client must respond to periodic ping packets sent by the server
with pong packets.
  • Client and server can exchange message packets at will.
  • Polling transports can send a close packet to close the socket, since
they're expected to be "opening" and "closing" all the time.

URLs

An Engine.IO url is composed as follows:

/engine.io/ [ ? ]

  • The engine.io pathname should only be changed by higher-level
frameworks whose protocol sits on top of engine's.

  • The query string is optional and has four reserved keys:
  • transport: indicates the transport name. Supported ones by default are
polling, flashsocket, websocket.
  • j: if the transport is polling but a JSONP response is required, j
must be set with the JSONP response index.
  • sid: if the client has been given a session id, it must be included
in the querystring.
  • b64: if the client doesn't support XHR2, b64=1 is sent in the query string
to signal the server that all binary data should be sent base64 encoded.

FAQ: Is the /engine.io portion modifiable?

Provided the server is customized to intercept requests under a different path segment, yes.

FAQ: What determines whether an option is going to be part of the path versus being encoded as part of the query string? In other words, why is the transport not part of the URL?

It's convention that the path segments remain only that which allows to disambiguate whether a request should be handled by a given Engine.IO server instance or not. As it stands, it's only the Engine.IO prefix (/engine.io) and the resource (default by default).

Encoding

There's two distinct types of encodings

  • packet
  • payload

Packet

An encoded packet can be UTF-8 string or binary data. The packet encoding format for a string is as follows

<packet type id>[<data>]
example:
2probe
For binary data the encoding is identical. When sending binary data, the packet type id is sent in the first byte of the binary contents, followed by the actual packet data. Example:

4|0|1|2|3|4|5

In the above example each byte is separated by a pipe character and shown as an integer. So the above packet is of type message (see below), and contains binary data that corresponds to an array of integers with values 0, 1, 2, 3, 4 and 5.

The packet type id is an integer. The following are the accepted packet types.

0 open

Sent from the server when a new transport is opened (recheck)

1 close

Request the close of this transport but does not shutdown the connection itself.

2 ping

send by the server. Client should answer with a pong packets, containing the same data

example

  • server sends: ``2probe%%CODEBLOCK3%%3probe%%CODEBLOCK4%%4HelloWorld%%CODEBLOCK5%%socket.on('message', function (data) { console.log(data); });%%CODEBLOCK6%%4HelloWorld%%CODEBLOCK7%%socket.on('message', function (data) { console.log(data); });%%CODEBLOCK8%%2probe%%CODEBLOCK9%%3probe%%CODEBLOCK10%%5%%CODEBLOCK11%% <length1>:<packet1>[<length2>:<packet2>[...]] %%CODEBLOCK12%% <length of base64 representation of the data + 1 (for packet type)>:b<packet1 type><packet1 data in b64>[...] %%CODEBLOCK13%% ___eio <encoded payload> "" rel="noopener"> <j> ; %%CODEBLOCK14%% ___eio[4]("packet data"); %%CODEBLOCK15%% d=<escaped packet payload> ` In addition to the regular qs escaping, in order to prevent inconsistencies with \n handling by browsers, \n gets escaped as \\n prior to being POSTd. ### WebSocket Encoding payloads _should not_ be used for WebSocket, as the protocol already has a lightweight framing mechanism. In order to send a payload of messages, encode packets individually and send() them in succession. ## Transport upgrading A connection always starts with polling (either XHR or JSONP). WebSocket gets tested on the side by sending a probe. If the probe is responded from the server, an upgrade packet is sent. To ensure no messages are lost, the upgrade packet will only be sent once all the buffers of the existing transport are flushed and the transport is considered _paused_. When the server receives the upgrade packet, it must assume this is the new transport channel and send all existing buffers (if any) to it. The probe sent by the client is a ping packet with probe sent as data. The probe sent by the server is a pong packet with probe sent as data. Moving forward, upgrades other than just polling -> x are being considered. ## Timeouts The client must use the pingTimeout sent as part of the handshake (with the open packet) to determine whether the server is unresponsive. If no packet type is received withing pingTimeout`, the client considers
the socket disconnected.