Getting started with Websockets
Websockets were standardized back in 2011 (RFC 6455). Since then support has been added to most major browsers.
Background
Websockets allow full duplex communication between a browser and a server. This is particularly useful for applications which need to frequently send and receive small messages because it avoids HTTP overhead.
In Javascript, new Websocket connections are made with code similar to the following:
var ws = new WebSocket('ws://example.com/socket')
When a connection is established the client will send a request with an HTTP/1.1 upgrade header similar to the following:
GET /socket HTTP/1.1
Host: example.com
Upgrade: websocket
Origin: http://example.com
Connection: keep-alive, Upgrade
Sec-WebSocket-Key: PdspSkfns9qGxGTNajm+Tw==
Sec-WebSocket-Version: 13
If the server supports Websockets, it will reply with a message similar to the following:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: eO+uwdEEfbO7q68DAzeDjM4Gs8c=
From this point on, the connection will look more like a standard TCP connection. As well as not requiring any HTTP headers for subsequent messages, messages can be sent by either the client or the server (bidirectional) and messages can be sent at the same time (full-duplex).
Setting up a server
There is a pretty wide range of libraries which can be used to implement a
Websocket server. This post is going to use the Tornado Python
web framework. On CentOS 7 it can either be installed with yum
:
yum install -y python-tornado
Alternatively if you need a more up-to-date version, it can be installed using
pip
:
pip install tornado
Once Tornado is installed, a very simple Websocket application could look something like the following:
#!/usr/bin/env python
"""A simple Websocket server which just echos messages"""
import tornado.web
import tornado.websocket
import tornado.ioloop
class EchoWebSocket(tornado.websocket.WebSocketHandler):
""" A very simple websocket handler"""
def on_message(self, message):
"""Echo message back to the client"""
self.write_message('server: %s' % message)
if __name__ == '__main__':
APP = tornado.web.Application([(r'/socket', EchoWebSocket)])
APP.listen(8888)
tornado.ioloop.IOLoop.instance().start(
In the code above the key method is the on_message
method. This is called
every time a client sends a new message and replies with the clients message
prefixed withserver:
. Starting the server is just a case of running the
script with Python:
$ python websocket_echo_server.py
Note: unlike other Python web frameworks, Tornado isn't normally use with a WSGI server, however this is possible. For more info, refer to the Tornado deployment docs.
Connecting to a Websocket
Once the Websocket server is up and running Javascript similar to the following can be used to connect to the server:
var ws = new WebSocket('ws://localhost:8888/socket');
A call-back function can then be defined to handle messages:
ws.onmessage = function(evt){
console.log(evt.data);
};
And finally a test message can be sent to the server:
ws.send("Hello world");
If everything works as expected, the server should reply with
server: Hello world
, which should be logged to the console. Normally the
Javascript above would be included in a web page, however a quick way to test
the code is to open the Firefox Web Console ( ctrl +
shift + k ) and type directly into the console: