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/

posted @ 2013-01-21 16:21  Chris Lee  阅读(955)  评论(0编辑  收藏  举报