Ajax+Tornado模拟长、短轮询
一、短轮询
在传统的短轮询中,浏览器每隔一段时间向服务器发送请求,看服务器有无更新。缺点是效率低,因为服务器不是总有更新数据;再者,如果大量用户不停的请求服务器,会造成较大的负载压力。
浏览器端,利用jQuery.ajax发送请求
1 <html> 2 <head> 3 <title>Short Polling</title> 4 <script type="text/javascript" src="lib/jquery.min.js"></script> 5 </head> 6 <body> 7 <p>Short Polling - Unsorted list...</p> 8 <ul></ul> 9 <script> 10 (function($) { 11 var polling = function() { 12 $.get('/polling', function(data){ 13 $("ul").append("<li>"+data+"</li>"); 14 }); 15 }; 16 interval = setInterval(polling, 3000); 17 })(jQuery); 18 </script> 19 </body> 20 </html>
服务器端,tornado.httpserver响应请求(同步)
1 import os 2 import random 3 import tornado.httpserver 4 import tornado.ioloop 5 import tornado.options 6 import tornado.web 7 8 from tornado.options import define, options 9 10 define("port", default=8088, help="run on the given port", type=int) 11 12 class MainHandler(tornado.web.RequestHandler): 13 def get(self): 14 self.write("Main page...") 15 16 class ShortPollingHandler(tornado.web.RequestHandler): 17 def get(self): 18 num = random.randint(1,100) 19 self.write(str(num)) 20 21 def main(): 22 tornado.options.parse_command_line() 23 settings = { 24 "static_path" : os.path.join(os.getcwd(), "public"), 25 } 26 application = tornado.web.Application([ 27 (r"/", MainHandler), 28 (r"/polling", ShortPollingHandler), 29 ], **settings) 30 http_server = tornado.httpserver.HTTPServer(application) 31 http_server.listen(options.port) 32 print "server listening on port %d" % options.port 33 tornado.ioloop.IOLoop.instance().start() 34 35 if __name__ == "__main__": 36 main()
连接的平均时长0.5ms左右:由于浏览器端定时发送请求,如果连接在服务器端发生阻塞,则会造成服务器端负载压力上升;当服务器端无阻塞且无更新时,连接立即断掉,浏览器端的大量请求未能取得有效数据,效率低下。
二、长轮询
用户发出请求建立连接,当服务器端有数据返回后连接才会断掉,接着用户端发送一个新的连接请求。
浏览器端,在jQuery.get的callback中重新发出连接请求
1 <html> 2 <head> 3 <title>Long Polling</title> 4 <script type="text/javascript" src="lib/jquery.min.js"></script> 5 </head> 6 <body> 7 <p>Long Polling - Unsorted list...</p> 8 <ul></ul> 9 <script> 10 (function($) { 11 var polling = function() { 12 $.get('/polling', function(data){ 13 $("ul").append("<li>"+data+"</li>"); 14 polling(); 15 }); 16 }; 17 polling(); 18 })(jQuery); 19 </script> 20 </body> 21 </html>
服务器端,tornado.httpserver响应请求(异步)
1 import os 2 import time 3 import random 4 import tornado.httpserver 5 import tornado.ioloop 6 import tornado.options 7 import tornado.web 8 9 from tornado.options import define, options 10 11 define("port", default=8088, help="run on the given port", type=int) 12 13 14 class MainHandler(tornado.web.RequestHandler): 15 def get(self): 16 self.write("Main page...") 17 18 class PollHandler(tornado.web.RequestHandler): 19 @tornado.web.asynchronous 20 def get(self): 21 if self.request.connection.stream.closed(): 22 return 23 num = random.randint(1, 100) 24 tornado.ioloop.IOLoop.instance().add_timeout( 25 time.time()+3, 26 lambda: self.send(data=num, callback=self.get) 27 ) 28 29 def send(self, data, callback): 30 try: 31 self.write(str(data)) 32 self.finish() 33 except: 34 pass 35 36 def main(): 37 tornado.options.parse_command_line() 38 settings = { 39 "static_path" : os.path.join(os.getcwd(), "public"), 40 } 41 application = tornado.web.Application([ 42 (r"/", MainHandler), 43 (r"/polling", PollHandler), 44 ], **settings) 45 http_server = tornado.httpserver.HTTPServer(application) 46 http_server.listen(options.port) 47 print "server listening on port %d" % options.port 48 tornado.ioloop.IOLoop.instance().start() 49 50 51 if __name__ == "__main__": 52 main()
连接的平均时长3s左右。
三、参考
1 - Browser 与Server 持续同步的作法介绍(Polling, Comet, Long Polling, WebSocket)
http://www.josephj.com/entry.php?id=358
2 - Browser和Server持续同步的几种方式(jQuery+tornado演示)
http://qinxuye.me/article/ways-to-continual-sync-browser-and-server/