Comet -- 基于 HTTP 长连接、无须在浏览器端安装插件的“服务器推”技术为“Comet”,这里介绍用Tornado 构建一个 Comet 应用的经验。
关于 Comet
Comet 指的是一种 Web 应用程序的架构。在这种架构中,客户端程序(通常是浏览器)不需要显式的向服务器端发出请求,服务器端会在其数据发生变化的时候主动的将数据异步的发送给客户端,从而使得客户端能够及时的更新用户界面以反映服务器端数据的变化。
这种架构既不同于传统的 Web 应用,也不同于新兴的 Ajax 应用。在传统的 Web 应用中,通常是客户端主动的发出请求,服务器端生成整个 HTML 页面交给客户端去处理。在 Ajax 应用中,同样是客户端主动的发出请求,只是服务器通常返回的是 XML 或是 JSON 格式的数据,然后客户端使用这些数据来对页面进行局部更新。Comet 架构非常适合事件驱动的 Web 应用和对交互性和实时性要求很强的应用。这样的应用的例子包括股票交易行情分析、聊天室和 Web 版在线游戏等。
用 Tornado 构建
说明1:使用此decorator即可以把get方法non-blocking化
说明2:non-blocking化的请求必须调用self.finish()完成请求
说明3:如果需要sleep等待,应该使用Tornado的IOLoop的add_timeout方法。使用其他休眠方法如time.sleep会block住当前线程,而Tornado是一个单线程Server,会导致其他请求无法执行的问题。
此时执行comet.py,一个non-blocking的server端已经搭建成功。
要注意的问题是,如果不加超时机制,服务端会不断执行,即使客户端已经断开。因此还需自己实现超时机制。
构建代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
import tornado.httpserver
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
@tornado.web.asynchronous #说明1
def get(self):
some_async_func(callback=self.wait)
def wait(self, result):
if result:
self.write(result)
self.finish() #说明2
else:
tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 0.5,lambda: some_async_func(callback=self.wait))
#说明3
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8999)
tornado.ioloop.IOLoop.instance().start()
超时设置
在Nginx 配置里添加超时机制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream frontends {
server 127.0.0.1:8999;
}
server {
listen 8888;
location / {
proxy_read_timeout 1800;
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://frontends;
}
}
注意问题
需要特别指出的是,要根据上述应用的超时机制,设置proxy_read_timeout,proxy_read_timeout 必须大于应用的超时。否则将会有504请求返回。 它说明由 nginx 向tornado请求了长连接以后,等到1800秒之后,如果tornado还没有返回。则nginx返回504 Gateway Timeout给客户端浏览器。
本文网址: https://pylist.com/topic/45.html 转摘请注明来源