11/3/2014 Python Tornado With WebSockets – Part I - Codestance

Codestance

PHP, Linux and Marketing Playground

Home Articles Resources Tips Tutorials

2013 Middax | Rainbow Newsletter Me gusta 28 Tw eet 37 34 September 7, 2013 16 Comments

Python Tornado Web Server With WebSockets – Part I

Today i will show you and give you some input how to make a web and websocket server with Tornado, which is currently my favorite when i need “mockup” service so i can show it to someone. Anyway this article will mostly cover websockets then “standard” web.

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 in 2009 and Tornado was open-sourced soon after.

For installing Tornado on our machine we need Python first, anyhow, Python is installed on most Linux distros possibly because most Gnome and KDE apps using Python 2.5+ interpreters. For installing Python on Windows machine you can check it out here.

After we have Python in place we should continue installing Tornado with easy_install tornado command which will install latest stable version. For running easy_install from Windows command prompt you can google a bit because this is covered on a lot of blogs. Also, i’ using Eclipse for Python development but you can use whatever you like.

Now let’s get to the real, simple example. Let’s create a file called server.py :

import tornado.ioloop import tornado.web

from tornado.options import define, options, parse_command_line

define("port", default=8888, help="run on the given port", type=int)

class IndexHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): self.write("This is your response") self.finish()

app = tornado.web.Application([ (r'/', IndexHandler), ])

if __name__ == '__main__': parse_command_line() http://www.codestance.com/tutorials-archive/python-tornado-web-server-with-websockets-part-i-441 1/6 11/3/2014 Python Tornado Web Server With WebSockets – Part I - Codestance app.listen(options.port) tornado.ioloop.IOLoop.instance().start()

We can see our example for simple response without rendering any html (this will be part II). Also, we can start this example with additional option port which is by default on 8888. For changing port we can start it by ./server.py --port=9999.

Notice that we put decorator @tornado.web.asynchronous before get method, and this will prevent the RequestHandler from automatically calling self.finish() eg. it means that server will hold connection until we execute finish.

Now, let’s go to our browser and write in address bar http://localhost:8888/ or eventually click on this link.

Because this is mostly websocket oriented post we should continue with modifying/extending our simple example:

import tornado.ioloop import tornado.web import tornado.websocket

from tornado.options import define, options, parse_command_line

define("port", default=8888, help="run on the given port", type=int)

# we gonna store clients in dictionary.. clients = dict()

class IndexHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): self.write("This is your response") self.finish()

class WebSocketHandler(tornado.websocket.WebSocketHandler): def open(self, *args): self.id = self.get_argument("Id") self.stream.set_nodelay(True) clients[self.id] = {"id": self.id, "object": self}

def on_message(self, message): """ when we receive some message we want some message handler.. for this example i will just print message to console """ print "Client %s received a message : %s" % (self.id, message)

def on_close(self): if self.id in clients: del clients[self.id]

app = tornado.web.Application([ (r'/', IndexHandler), (r'/', WebSocketHandler), ])

if __name__ == '__main__': parse_command_line() app.listen(options.port) tornado.ioloop.IOLoop.instance().start()

With upper extended simple example, we done nothing yet because we actually need some client to connect with. If we go again and refresh localhost link in our browser we should get same message as last time. Also we can see that we didn’t change route to websocket handler, they can both work on same route, but what is different is that when we want to connect to websocket there is ws:// insted http:// and Tornado knows how to handle those routes.

For simple client we can use index handler with html rendering so let’s change server.py a bit:

class IndexHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): #self.write("This is your response") self.render("index.html") http://www.codestance.com/tutorials-archive/python-tornado-web-server-with-websockets-part-i-441 2/6 11/3/2014 Python Tornado Web Server With WebSockets – Part I - Codestance #we don't need self.finish() because self.render() is fallowed by self.finish() inside tornado #self.finish()

Now we need index.html, so let’s create one..

Run WebSocket

And this is it.. we can now run our Tornado server and ho to http://localhost:8888/ we will see index.html rendered in browser, also if we click on link “Run WebSocket” it should start connecting on our websocket and we should see messages in container.

This is it for now, my next few post will hold few modification on server side and i will make small and simple client side library for handling websocket connections and messages.

Happy Hacking!

Tags: python, tornado, websockets

Newer Older

AROUND THE WEB ALSO ON CODESTANCE WHAT'S THIS?

The Secret Way to Save Hundreds of Dollars on 5-star Boosting PHP Apps Performance with APC 1 comment hotels TravelPony XCache v3.0.1, More Performance For PHP Apps Boy shows his father photos of his mother in bed with 2 comments another man YJNews Proxy Websockets To Socket.IO 5 comments VIDEO: STACK Fitness Weekly: 2 Exercises You Should Do Every Day Stack Nginx Download File Trigger 7 comments

16 Comments CodeStance Login

Sort by Best Share Favorite http://www.codestance.com/tutorials-archive/python-tornado-web-server-with-websockets-part-i-441 3/6 11/3/2014 Python Tornado Web Server With WebSockets – Part I - Codestance Sort by Best Share Favorite

Join the discussion…

Mike Morris • 3 months ago Thanks for this article. I think I have it rendering index.html but all I see is a large black box. Clicking on Run WebSocket seems to do nothing. What should I actually see? I have another python script reading OBDII from my truck and calculating 1-second MPG, and I' like to send that value every time I get it to the browser. From my research it seems your tutorial has got me most of the way there. How do I send messages to the browser from my script in the same folder? Again, thanks for getting me this far! 3 • Reply • Share ›

chuphay • 2 months ago Hi... it almost seems to work... but when I click on Run Websocket, it says "connection is closed..." 1 • Reply • Share ›

Mia • 9 days ago Did you ever get around to writing part 2? I can't seem to find it... :) • Reply • Share ›

Filip Curic Mod Mia • a day ago Hi, thanks for asking, tho i'm bit busy last few months and it's really hard for me to get some time to make part two, writing application, testing and writing article.

I hope i will have time this month :) • Reply • Share ›

Mia Filip Curic • a day ago Great! Actually part I was such a good start-off point, I figured out the rest after and went on to write a little 2d mmorpg (it was all just to practice learning websockets)! • Reply • Share ›

Filip Curic Mod Mia • 3 hours ago I'm glad you liked it, its shame because i don't have much of time because lot of work, but just for you to know, in next part i will focus mostly on client side and server side security for websocket. This will, i hope, give you some good ideas how to build secure ws/wss tasks and interfaces.

Also, i plan to make this on python and , java because i think its kind of better and more EE solution than python.

Br, Filip • Reply • Share ›

Racky Senapati • 3 months ago When are you going to upload the second part - Python Tornado Web Server With WebSockets – Part II • Reply • Share ›

alexvassel • 6 months ago Hello. Having a problems: FF says "Firefox can't establish a connection to the server at ws://localhost:8888/?Id=123456789."; Chrome says "WebSocket connection to 'ws://localhost:8080/?Id=123456789' failed: Unexpected response code: 200". • Reply • Share ›

Filip Curic Mod alexvassel • 6 months ago Hello, http://www.codestance.csoomm/tuet oFriFa lsv-earrscihoivnes/p ybthyo dne-tfoarnualtd od-iswaeb-lsee rwveerb-wsiothc-kwebtss obcekectsa-upsaret- pi-o44s1sible vulnerabilities so you need to check what version 4/6 11/3/2014 Python Tornado Web Server With WebSockets – Part I - Codestance some FF versions by default disable websockets because possible vulnerabilities so you need to check what version do you use and try to enable them. • Reply • Share ›

alexvassel Filip Curic • 6 months ago Figured out this thing. IndexHandler and WebSocketHandler have the same url. So ws request hits IndexHandler that returns normal 200 response. Changing WebSocketHandler url makes the trick. • Reply • Share ›

Filip Curic Mod alexvassel • 6 months ago Url should not be the problem, instead of new Websocket(..) you can try using MozWebSocket(..) so you can actually check first if its Mozilla then others.

You can also check browser compatibility from Mozilla site : https://developer.mozilla.org/... • Reply • Share ›

alexvassel Filip Curic • 6 months ago Only the changing of the url does work. I use last version of FF and Chrome. • Reply • Share ›

David Chamberlin alexvassel • 3 months ago − I just independently came to the same conclusion. I also changed the ws url to be contextual - maybe that's why the root URI didn't work?

Changes to javascript are:

var ws = new WebSocket("ws://" + window.location.host + "/ws?Id=123456789");

and to python:

app = tornado.web.Application([ (r'/', IndexHandler), (r'/ws', WebSocketHandler), ]) • Reply • Share ›

B Budd • 6 months ago Is this a debugging exercise? I just started using tornado, but with the index.html exercise (the other two work fine) I'm getting a "RuntimeError("finish() called twice. May be caused by using async operations without the @asynchronous decorator". ? I am not really sure what may be happening.... somehow my decorator isn't being recognized? But I'm not seeing any import errors.... • Reply • Share ›

Filip Curic Mod B Budd • 6 months ago Hello, thank you for your reply.

Why this is happening is because self.render() is fallowed by self.finish() inside tornado so you can just remove self.finish(). It's my mistake, sorry. • Reply • Share ›

B Budd Filip Curic • 6 months ago Ah! That's one thing I didn't try... thank you for your speedy reply, and for the basic info. Very helpful! • Reply • Share ›

Subscribe Add Disqus to your site http://www.codestance.com/tutorials-archive/python-tornado-web-server-with-websockets-part-i-441 5/6 11/3/2014 Python Tornado Web Server With WebSockets – Part I - Codestance

http://www.codestance.com/tutorials-archive/python-tornado-web-server-with-websockets-part-i-441 6/6