浏览 3561 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-15
最后修改:2011-03-15
Tornado支持long-polling,在其提供的demo中推荐参考的例子就是那个chat demo,我这里参考chat demo,提供一个简单的long-polling测试应用“用于统计当前在线人数,并保持最新数据至各个客户端的同步更新”。 1. 通过URL加一个参数name来模拟在线用户。 2. Ajax long polling 不只是server端的轮询,client端也需要保持一种请求轮询状态,因为当前的大多数web server都不支持基于单向的HTTP链接的双向通信,我们可以通过websockets,但是这个将HTTP转换成其他形式的协议的操作,目前大多数的浏览器并没有广泛支持,我们可以联想到HTML5 Websockets。我们可以用一种long-lived 链接方式(tornado支持的),用于server和client端之间的数据传输, 类似push-pull的方式,我觉得。 3. 这次的测试,暂没有提供基于重写on_connection_close来处理offline的用户(直接关闭浏览器),所以用户统计的数量只会随着访问数量的增加而增加 Comet 我的测试代码,目前使用的是tornado 1.2.1 Server端: import os import string import time import logging from datetime import datetime import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web import tornado.httpclient from tornado.options import define, options define("port", default=8888, help="run on the given port", type=int) online = [] count = 0 class MainHandler(tornado.web.RequestHandler): def get(self): self.user = self.get_argument("name", None) self.render("templates/stack_p312a.html", title="Online number testing", c_time=datetime.now(), user=self.user) class LongPollingHandler(tornado.web.RequestHandler): @tornado.web.asynchronous def get(self): global online, count self.user = self.get_argument("name", None) if self.user not in online: logging.info("user : " + self.user) online.append(self.user) http = tornado.httpclient.AsyncHTTPClient() appURL = self.request.protocol + "://" + self.request.host http.fetch(appURL + "/internal-polling", self._on_finish) '''push to the client''' def _on_finish(self, response): if self.request.connection.stream.closed(): return self.write("welcome %s, current online number(s) %s" % (self.user, response.body)) self.finish() ''' def on_connection_close(self): TODO, testing ''' class InternalPollingHandler(tornado.web.RequestHandler): ''' The internal polling for the new online member which will be counted into the global online list, and then asynchronously push the latest data to the connected client,keep in a long-polling status. ''' def get(self): global online, count logging.info("count : " + str(count)) logging.info("online : " + str(len(online))) if count != len(online): count += 1 self.get() else: self.write(str(count)) def main(): tornado.options.parse_command_line() settings = { "static_path": os.path.join(os.path.dirname(__file__), "static"), } application = tornado.web.Application([ (r"/", MainHandler), (r"/long-polling", LongPollingHandler), (r"/internal-polling", InternalPollingHandler), ], **settings ) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main() Client端(stack_p312a.html): <html> <head> <title>{{ title }}</title> <script type="text/javascript" language="JavaScript" src="{{ static_url("jquery-1.5.1.min.js")}}"></script> <script type='text/javascript' language='JavaScript'> function test(){ window.setTimeout(function(){ $.ajax({ url : '/long-polling?name={{ user }}', success : function(data){ $("#num").text(data); } }); test(); }, 5000); } </script> </head> <body> Current time is {{c_time}} <br> <input type="button" value="Test" onclick="test();"/> <div id="num"></div> </body> </html> 简单说明: 1. 通过简单的提供 global online = [] global count = 0 用于用户在线用户的统计 2. http://localhost:8888/?name=a http://localhost:8888/?name=b 通过不同的name来模拟各个用户 ----------------------------------------------- 对于on_connection_close,the select()-base implements of IOLoop (non-Linux systems) 相关的实现是在tornado 1.2下有修补一些问题,详细可以参考 changelist : https://github.com/facebook/tornado/commit/1221865747ecfde69a0463b9a0d77b3c5b87f320 但是根据Ben Darnell的建议,并没有在windows下测试过,目前还在学习、讨论中。 ----------------------------------------------- 在使用tornado async时一些体验: 1. self.render(), self.redirect()其中已经包含了self.finish()操作,我们在写相关的async callback时候,需要注意这个,不应重复使用self.finish() 2. RequestHandler.async_callback 这个方法从1.1版本开始已经废除,类似代码(下面)应该不再使用,可以通过AsyncHTTPClient来实现异步请求 @tornado.web.asynchronous def get(self): ... self.check_for_last_numbers(callback=self.async_callback(self.on_finish)) ... def check_for_last_numbers(self, callback): ... 3. self.finish(),self.flush() 可以“简单的理解”为一种server端的push操作,但是实际实现中,建议使用self.finish(),tornado可以基于之前的cursor、session(secure cookie)来重用之前的connection。 笔记先分享到这里,欢迎大家讨论,共同学习 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |