Sockets and Lies

The Why, What, and WTF of Websockets


  • I work at uStudio.
  • We make video easier to distribute.
  • We are always looking for a few good devs.

Why Websockets

When we had all finally stopped saying AJAX?

Push for Real

Websockets give us the ability to send data either way, whenever we want.

Life Before the New Hotness

def post(self):
    # gee, I hope someone refreshes...
var update = function() {
  $.get("/users/foo", function(users) {
    users.forEach(function(user) {
      // compare every user to see if anything has
      // changed, and update views accordingly
    setTimeout(update, 3000);

Life After

def post(self):
    socket.broadcast("updated_user", user.to_dict())
// after we've connected to the websocket...
var onmessage = function(message) {
  if (message.type == "updated_user") {
    updateUser(, new_user);

How do websockets work?

HTTP Request Primer

GET / HTTP/1.1
Cookie: user=20a356ec01054c0b902fd265b7b1f5f4
If-None-Match: wetVrDrsf423tVSefsffv43SEf
User-Agent: Mozilla/11.0 (like Mosaic) BeOS/10.04
Accept: */*

HTTP Response Primer

HTTP/1.1 200 OK
Date: Thu, 24 Jan 2013 04:25:23 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 18
Set-Cookie: user=20a356ec01054c0b902fd265b7b1f5f4
ETag: wetVrDrsf423tVSefsffv43SEf
Cache-Control: private, max-age=0


...and the request hangs up. Probably.

Websockets != HTTP

Websocket Initial Request

GET /websocket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Protocol: chat, uberchat
Sec-WebSocket-Version: 13

It looks like normal HTTP, but...

  • Upgrade: websocket
  • Connection: Upgrade
  • Sec-Websocket-Key
  • Sec-Websocket-Protocol
  • Sec-Websocket-Version

Server Response

(Assuming success)

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

... and stays open.

Handshake Details

  • dGhlIHNhbXBsZSBub25jZQ==
  • 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
  • hashlib.sha1(raw).digest()
  • base64.b64encode(hash_digest)


Upgrade Successful

...and you are powersliding down rainbows.

ws:// and wss://

  • ws://
  • wss:// uses SSL, like https://

(Simple) Messaging Overview

WebSockets send data across the wire in "frames"

Each frame conforms to a specific format

WebSocket Frame (Simplified)

...not that you'll have to implement this.

Let's See Some Code

...After More Talking

Blocking servers are bad for WebSockets.

Traditional HTTP Cycle

Alternate requests are handled in serial or by additional threads / processes

WebSocket Cycle

The server (or thread / process) can't ever release control.

So We Need Alternatives

  • Gevent - Asynchronous Monkey Patching
  • Tornado - Asynchronous via IOLoop

Gevent - "blocking" style

from gevent import monkey
import socket

sock = socket.socket()
sock.connect(("", 80))
# will block current process until finished

sock = socket.socket()
sock.connect(("", 80))
# releases control to other I/O operations

Tornado - "callback" style

from tornado.iostream import IOStream
from tornado.ioloop import IOLoop
import socket

def on_connect():
  stream.read_bytes(4096, on_read)

def on_read(data):
  # handle data

sock = socket.socket()
stream = IOStream(s)
stream.connect(("", 80), on_connect)

Psy - Gangnam Style

Just for reference.

Chat Demo

Right Here


We can only send one direction at a time.


while True:
    # we are going to wait until a message comes
    packet = websocket.receive()
    # now we can actually send a message

In the blocking style, it's easier to limit yourself to half-duplex.

Twitter Demo

Right Here


def monitor_source():
  while True:
    # source can be twitter, redis, whatever
    message = source.receive()
    for subscriber in _SUBSCRIBERS:

def monitor_subscriber(websocket):
  while True:
    message = websocket.receive()
    # perform user action (update settings, broadcast, etc.)


Message Queue Architecture

Same as your database, you want a central, shared message queue.

Tornado Demo

Use the phone, Josh.

(if there is time)

Caveat Central

Shooting Unicorns in the Face

Production Notes

  • Most HTTP proxies (nginx, Apache) don't natively respect websockets.
  • You'll need TCP proxying in a production environment.
  • There is an NGINX TCP proxy module, and an Apache one.
  • These require recompiling the servers.
  • Alternatively, just use HAProxy.

Matrix of Despair

IE Chrome Firefox iOS Android
hixi-76 6 4 :( 5
hybi-07 6
hybi-10 14 7
RFC 6455 10 16 11 6

This depressing data brought to by Wikipedia.

Fallback Options

  • Flash Socket (gross)
  • EventSource
  • Long-polling
  • Forever iFrame

You Don't Have to Go It Alone

  • Socket.IO (gevent-socketio)
  • SockJS (tornado-sockjs)
  • nginx-push-stream module
  • Pusher (service)


@joshmarshall on the Twitters.

@joshmarshall on the GitHub.