WebSockets

Methods for Real-Time Data Streaming

Steve Schwartz / @jangosteve

WebSocket

Protocol
allows for a persistent, full-duplex communication between a client and remote host.
HTML5
defines a JavaScript API for the WebSocket protocol within the browser, allowing bi-directional communication between the browser and server.

Why?

Web apps need to communicate with the server in real-time

  • HTTP based on request/response cycle
  • Had no way to keep connections open until v1.1 (keep-alive)
  • Lots of overhead in request handshake, error checking, and delivery validation

Can't we already do that?

...sort of

Full credit for the following diagrams goes to Tieme from his post on StackOverflow

AJAX Polling

Client sends AJAX request to server, server responds

AJAX Polling

Works when:

  • client needs to request data occasionally
  • client needs to send data occasionally

Falls short when:

  • client needs to send data often
  • server needs to iniate and send data without client request

AJAX Long-polling

Client sends AJAX request to server, server keeps request open until response available

Client immediately sends another long-poll request after receiving response

(also see Comet)

AJAX Long-polling

Works when:

  • client needs to request one or a few pieces of data at a time
  • server needs to send one or a few pieces of data occastionally

Falls short when:

  • client needs to send data often
  • client needs initiate and send data when available
  • server needs to send data often

Server-Sent Events (SSE)

Client opens connection with server

Server sends data to client as it becomes available

Server-Sent Events (SSE)

Works when:

  • server needs to send data often
  • browser support for WebSockets can't be relied upon

Falls short when:

  • client needs to send any data

WebSockets

Client opens connection with server

Client and server send data to each other as data becomes available on either side

WebSockets

Works when:

  • server and/or client need to send data often
  • browser support for WebSockets can be relied upon or fallbacks can be used

Falls short when:

  • fallbacks can't be relied upon

Important components of the WebSocket spec

HTTP handshake

  • Initial handshake via HTTP
  • → upgrade to WebSocket connection

Request


GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com
            

Response


HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
            

*WebSocket protocol handshake via Wikipedia.

Full-duplex over TCP

Allows bi-directional communication over standard HTTP ports

(great for existing servers, proxies, and firewalls, which open 80 & 443)

URI structure

Defines new protocols, ws:// and wss:// for standard and secure WebSocket connections

Rest of WebSockets URI follows standard URI scheme


  var connection = new WebSocket('ws://subdomain.examnple.com/some-endpoint')
            

WebSocket events


connection.onopen = function(e) {
  console.log("Connected");
};

connection.onmessage = function(e) {
  console.log( "Received: " + e.data);
};

connection.onclose = function(e) {
  console.log("Connection closed");
};
          

Cross-domain

WebSockets is cross-domain by default

Up to you to optionally restrict domain access on server via Origin header

Request


GET ws://echo.websocket.org/?encoding=text HTTP/1.1
Origin: http://websocket.org
Cookie: __utma=99as
Connection: Upgrade
Host: echo.websocket.org
Sec-WebSocket-Key: uRovscZjNol/umbTt5uKmw==
Upgrade: websocket
Sec-WebSocket-Version: 13
            

Response


HTTP/1.1 101 WebSocket Protocol Handshake
Date: Fri, 10 Feb 2012 17:38:18 GMT
Connection: Upgrade
Server: Kaazing Gateway
Upgrade: WebSocket
Access-Control-Allow-Origin: http://websocket.org
Access-Control-Allow-Credentials: true
Sec-WebSocket-Accept: rLHCkw/SKsO9GAH/ZSFhBATDKrU=
Access-Control-Allow-Headers: content-type
            

*WebSocket protocol handshake via websocket.org.

Extensibility

Built-in method for defining WebSocket extensions via RFC

Current extensions include perframe-deflate and multiplexing

Optional subprotocol


var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
            

*via html5rocks.

(See currently defined subprotocols)

Message data types

Original WebSocket spec allowed for strings

Now also allows buffered arrays and blobs

Sending String


connection.send('your message');
            

*via html5rocks.

Sending ArrayBuffer


var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
  binary[i] = img.data[i];
}
connection.send(binary.buffer);
            

*via html5rocks.

Sending Blob


var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);
            

*via html5rocks.

In the real world

(brain-dump)

Typical WebSocket architecture

*via websocket.org.

Sending JSON

Doesn't support sending/receiving JSON (yet)

Can be accomplished by serializing/deserializing

Server


var WebSocketServer = require('ws').Server,
    wss = new WebSocketServer({port: 8080});

wss.on('connection', function(ws) {
  ws.send(JSON.stringify({
    attribute: 'connected'
  }));
});
            

Client


connection.onmessage = function (e) {
  var response = JSON.parse(e.data);
};
            

Browser-to-server

Not really meant for server-to-server communication; better off using UDP or some other low-overhead transfer protocol if you control both servers

Not meant for browser-to-browser communication; that's what WebRTC is for

Proxies

Using ws in production can cause WebSockets communication to fail due to invisible proxies that can't do WebSockets

Using wss forces browser to issue HTTP_CONNECT statement to proxy server, which sets up tunnel

So use wss in production

Server must support WebSocket

Initial HTTP handshake to server requests WebSocket upgrade

Server upgrades connection if it knows how

Support can be added to most servers (modules exist for Nginx, Apache, etc.)

Back-end app must support WebSocket

Server can be built in any language, which supports event loop

Libraries exist for many languages, including Node, Ruby, Python, PHP, etc. (see list of libraries via Wikipedia)

Browser must support WebSocket

All modern browsers (including IE10 support WebSockets)

Except Android Browser (but supported in Mobile Chrome, avail on Android >= 4.0, default on Android >= 4.2)

(See browser compatibility via Wikipedia)

Socket.IO is awesome

Server and client-side implementation (for Node on server side)

Abstracts WebSocket communications to automatically fall back to flash streaming or long-polling when necessary (on either server or client)

Adds features like heartbeats, timeouts, and disconnection support not provided in WebSocket API

(See Socket.IO)

Example real-world uses

  • real-time chat application
  • multi-player HTML5 game
  • event-based in-page analytics
  • more things

Build a basic WebSocket demo

HTML5 Boilerplate

Explore a cooler demo

WebSockets SEM.js Demo

Resources

FIN