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端:
Client端(stack_p312a.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来实现异步请求
3. self.finish(),self.flush() 可以“简单的理解”为一种server端的push操作,但是实际实现中,建议使用self.finish(),tornado可以基于之前的cursor、session(secure cookie)来重用之前的connection。
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。
笔记先分享到这里,欢迎大家讨论,共同学习