Websocket is a feature of HTML5 that allow for asynchronous communication between the web server and the client. WebSocket is a naturally full-duplex, bidirectional, single-socket connection. With WebSocket, your HTTP request becomes a single request to open a WebSocket connection and reuses the same connection from the client to the server, and the server to the client.
WebSocket reduces latency because once the WebSocket connection is established, the server can send messages as they become available. For example, unlike polling, WebSocket makes a single request. The server does not need to wait for a request from the client. Similarly, the client can send messages to the server at any time. This single request greatly reduces latency over polling, which sends a request at intervals, regardless of whether messages are available.
A WebSocket connection is established by upgrading from the HTTP protocol to the WebSocket Protocol during the initial handshake between the client and the server, over the same underlying TCP connection.
The WebSocket API is purely (and truly) event driven. Once the full-duplex connection is established, when the server has data to send to the client, or if resources that you care about change their state, it automatically sends the data or notifications.
Following is comparison between the polling and WebSocket applications
Server
Tornado is a scalable, non-blocking web server and web application framework written in Python. It was developed for use by FriendFeed; the company was acquired by Facebook in 2009 and Tornado was open-sourced soon after.
Install Tornado
pip install tornado
Simple server
import tornado.ioloop import tornado.web import tornado.websocket from tornado.options import define, options, parse_command_line define("port", default=8888, type=int) class IndexHandler(tornado.web.RequestHandler): def get(self): self.render("index.html") class WebSocketHandler(tornado.websocket.WebSocketHandler): def open(self, *args): print "New connection" self.write_message("Welcome!") def on_message(self, message): print "New message {}".format(message) self.write_message(message.upper()) def on_close(self): print "Connection closed" app = tornado.web.Application([ (r'/', IndexHandler), (r'/ws/', WebSocketHandler), ]) if __name__ == '__main__': app.listen(options.port) tornado.ioloop.IOLoop.instance().start()
index.html template you can find here.
Run server
python tornado_ws.py
Open in browser http://127.0.0.1:8888.
Client
Lets install websocket-client (websocket client for python) and test our WebSocket server.
pip install websocket-client
Simple client on python
from websocket import create_connection ws = create_connection("ws://localhost:8888/ws/") print "Sending 'Hello, World'..." ws.send("Hello, World") print "Sent" print "Reeiving..." result = ws.recv() print "Received '%s'" % result ws.close()
Simple client on javascript (you can find full code in index.html above)
if ("WebSocket" in window) { log("WebSocket is supported by your browser."); var ws = new WebSocket("ws://127.0.0.1:8888/ws/"); ws.onopen = function() { log("Connection is opened ..."); ws.send("Hello there!"); }; ws.onmessage = function (evt) { var msg = evt.data; log("Message is received: " + msg); }; ws.onclose = function() { log("Connection is closed ..."); }; } else { log("WebSocket not supported by your browser."); }
Nginx in front
The usual strategy when building a Python app is to put Nginx in front of Python as a reverse proxy that serves any static content. This was a problem if you wanted to use WebSockets though, as Nginx didn’t know how to proxy those requests. Until version 1.3.13 of Nginx.
Now you can set this directives
location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
The proxy_http_version
directive tells Nginx to use HTTP/1.1 when communicating to the Python backend, which is required for WebSockets. The next two tell Nginx to respond to the Upgrade request which is initiated over HTTP by the browser when it wants to use a WebSocket.
Useful links