Async networking in python
With
gevent,concurrence,twisted,eventlet(and node.js)
Presentation by Uriel Katz
Lecture Topics
Async networking in a nutshell
Overview of python frameworks
Twisted
Gevent
Concurrence
Eventlet
Something extra - Node.js
Comet chat examples
Comet chat - client side code
<html>� <head>� <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>� <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.2/jquery-ui.min.js"></script>� <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/base/jquery-ui.css" rel="stylesheet"/>� <script>� $(function()� {� $("#dialog-form").dialog({� autoOpen: false,� height: 300,� width: 350,� modal: true,� buttons: {� 'OK': function() {� $(this).dialog('close');� waitForMessage();� },� }� });�� function newMessage()� {� $.get('/new_message?msg=' + $("#txtMsg").val() + '&name=' + $("#dialog-form input").val(),function(){});� $("#txtMsg").val("");� }�
Comet chat - client side code(cont.)
� function waitForMessage() {� $.get('/wait',function(msg){� var div = $("<div>" + msg + "</div>");� $("#messages").append(div);� div.effect("highlight", {}, 1000);� waitForMessage();� });� }�� $("input[type=button]").click(newMessage);� $("#dialog-form").dialog('open');� });� </script>� </head>� <body>� <div id="messages" style="border:1px solid #C0C0C0;width:600px;height:300px;overflow-y: scroll;">� � </div>� <input type="text" id="txtMsg"/>� <input type="button" value="post"/>� <div id="dialog-form">� Enter your name:<input type="text"/>� </div>� </body>�</html>
Twisted example
from twisted.internet import reactor,defer�from twisted.web.resource import Resource�from twisted.web.static import File�from twisted.web.server import NOT_DONE_YET,Site��clients = []��class WaitForMessages(Resource):� def render_GET(self, request):� clients.append(request)� return NOT_DONE_YET� �class NewMessage(Resource):� def render_GET(self,request):� global clients� for client in clients:� try:� client.write(request.args["name"][0] + ":" + request.args["msg"][0])� client.finish()� except:#disconnected� pass� clients = []� request.write("1")� request.finish()��resource = Resource()�resource.putChild("",File("index.html"))�resource.putChild("wait",WaitForMessages())�resource.putChild("new_message",NewMessage())��factory = Site(resource)�reactor.listenTCP(8080, factory)�reactor.run()��
Concurrence example
import urlparse�from concurrence import dispatch, Tasklet, Message�from concurrence.http import WSGIServer��class MSG(Message): pass�connected_clients = set()��def chat(env, start_response):� start_response('200 OK', [('Content-Type', 'text/html')])� if env['PATH_INFO'] == '/':� return [open("index.html","rb").read()]� elif env['PATH_INFO'] == '/wait':� connected_clients.add(Tasklet.current())� try:� for msg,args,kargs in Tasklet.receive():� return [args[0]]� except Exception,e:� return [str(e)]� elif env['PATH_INFO'].startswith('/new_message'):� qs = urlparse.parse_qs(env['QUERY_STRING'])� for client in connected_clients:� try:� MSG.send(client)(qs["name"][0] + ":" + qs["msg"][0])� except:#disconnected� pass� return ["1"]� else:� return ["Not Found"]�def main():� server = WSGIServer(chat)� server.serve(('localhost', 8084))�if __name__ == '__main__':� dispatch(main)�
Gevent example
import urlparse�from gevent import event,pywsgi��new_message = event.AsyncResult()��def chat(env, start_response):� global new_message� start_response('200 OK', [('Content-Type', 'text/html')])� if env['PATH_INFO'] == '/':� return [open("index.html","rb").read()]� elif env['PATH_INFO'] == '/wait':� result = new_message.wait()� return [result]� elif env['PATH_INFO'].startswith('/new_message'):� qs = urlparse.parse_qs(env['QUERY_STRING'])� new_message.set(qs["name"][0] + ":" + qs["msg"][0])� new_message = event.AsyncResult()� return ["1"]� else:� return ["Not Found"]� �server = pywsgi.WSGIServer(('', 8083), chat)�server.serve_forever()
Eventlet example
import eventlet,urlparse�from eventlet import wsgi,event��new_message = event.Event()��def chat(env, start_response):� start_response('200 OK', [('Content-Type', 'text/html')])� if env['PATH_INFO'] == '/':� return [open("index.html","rb").read()]� elif env['PATH_INFO'] == '/wait':� result = new_message.wait()� return [result]� elif env['PATH_INFO'].startswith('/new_message'):� global new_message� qs = urlparse.parse_qs(env['QUERY_STRING'])� new_message.send(qs["name"][0] + ":" + qs["msg"][0])� new_message = event.Event()� return ["1"]� else:� return ["Not Found"]� �wsgi.server(eventlet.listen(('', 8081)), chat)�
Node.js example
var http = require('http'),fs=require('fs');�var clients = [];�http.createServer(function (request, response) {� var parts = require('url').parse(request.url,true);� response.writeHead(200, {'Content-Type': 'text/html'});� if(parts.pathname == "/")� {� var data = fs.readFileSync("index.html");� response.end(data);� }� else if(parts.pathname == "/wait")� {� clients.push(response);� }� else if(parts.pathname == "/new_message")� {� for(var i=0;i<clients.length;i++)� clients[i].end(parts.query.name + ":" + parts.query.msg);� clients = [];� response.end("1");� }� else� {� response.end('Not Found');� }�}).listen(8082);
My work on and with gevent
Stuff done at work:
Thanks!
Slides and code available at:�http://www.urielkatz.com