1、tornado概述
Tornado就是我们在 FriendFeed 的 Web 服务器及其常用工具的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里每一个活动用户都会保持着一个服务器连接。(关于如何扩容 服务器,以处理数以千计的客户端的连接的问题,请参阅The C10K problem)
Tornado代表嵌入实时应用中最新一代的开发和执行环境。 Tornado 包含三个完整的部分:
(1)、Tornado系列工具, 一套位于主机或目标机上强大的交互式开发工具和使用程序;
(2)、VxWorks 系统, 目标板上高性能可扩展的实时操作系统;
(3)、可选用的连接主机和目标机的通讯软件包 如以太网、串行线、在线仿真器或ROM仿真器。
2、tornado特点
Tornado的独特之处在于其所有开发工具能够使用在应用开发的任意阶段以及任何档次的硬件资源上。而且,完整集的Tornado工具可以使开发人员完全不用考虑与目标连接的策略或目标存储区大小。Tornado 结构的专门设计为开发人员和第三方工具厂商提供了一个开放环境。已有部分应用程序接口可以利用并附带参考书目,内容从开发环境接口到连接实现。Tornado包括强大的开发和调试工具,尤其适用于面对大量问题的嵌入式开发人员。这些工具包括C和C++源码级别的调试器,目标和工具管理,系统目标跟踪,内存使用分析和自动配置. 另外,所有工具能很方便地同时运行,很容易增加和交互式开发。
3、tornado模块索引
最重要的一个模块是web, 它就是包含了 Tornado 的大部分主要功能的 Web 框架。其它的模块都是工具性质的, 以便让 web 模块更加有用 后面的 Tornado 攻略 详细讲解了 web 模块的使用方法。
主要模块
-
web- FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能 -
escape- XHTML, JSON, URL 的编码/解码方法 -
database- 对MySQLdb的简单封装,使其更容易使用 -
template- 基于 Python 的 web 模板系统 -
httpclient- 非阻塞式 HTTP 客户端,它被设计用来和web及httpserver协同工作 -
auth- 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth) -
locale- 针对本地化和翻译的支持 -
options- 命令行和配置文件解析工具,针对服务器环境做了优化
底层模块
-
httpserver- 服务于web模块的一个非常简单的 HTTP 服务器的实现 -
iostream- 对非阻塞式的 socket 的简单封装,以方便常用读写操作 -
ioloop- 核心的 I/O 循环
tornado框架使用
1、安装tornado
pip install tornado 源码安装:https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz
2、先写一个入门级的代码吧,相信大家都能看懂,声明:tornado内部已经帮我们实现socket。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop
class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write("Hello World, My name is 张岩林")
application = tornado.web.Application([
(r'/index',IndexHandler),
])
if __name__ == "__main__":
application.listen(8080)
tornado.ioloop.IOLoop.instance().start()
第一步:执行脚本,监听 8080 端口
第二步:浏览器客户端访问 /index --> http://127.0.0.1:8080/index
第三步:服务器接受请求,并交由对应的类处理该请求
第四步:类接受到请求之后,根据请求方式(post / get / delete ...)的不同调用并执行相应的方法
第五步:然后将类的方法返回给浏览器
tornado路由系统
在tornado web框架中,路由表中的任意一项是一个元组,每个元组包含pattern(模式)和handler(处理器)。当httpserver接收到一个http请求,server从接收到的请求中解析出url path(http协议start line中),然后顺序遍历路由表,如果发现url path可以匹配某个pattern,则将此http request交给web应用中对应的handler去处理。
由于有了url路由机制,web应用开发者不必和复杂的http server层代码打交道,只需要写好web应用层的逻辑(handler)即可。Tornado中每个url对应的是一个类。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__auth__ = "zhangyanlin"
import tornado.web
import tornado.ioloop
class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write("Hello World, My name is 张岩林")
class LoginHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write("<input type = 'text'>")
class RegisterHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.write("<input type = 'password'>")
application = tornado.web.Application([
(r'/index/(?P<page>\d*)',IndexHandler), # 基础正则路由
(r'/login',LoginHandler),
(r'/register',RegisterHandler),
])
# 二级路由映射
application.add_handlers('buy.zhangyanlin.com$',[
(r'/login', LoginHandler),
])
if __name__ == "__main__":
application.listen(8080)
tornado.ioloop.IOLoop.instance().start()
观察所有的网页的内容,下面都有分页,当点击下一页后面的数字也就跟着变了,这种就可以用基础正则路由来做,下面我来给大家下一个网页分页的案例吧
#!/usr/bin/env python # -*- coding:utf-8 -*- __auth__ = "zhangyanlin" import tornado.web import tornado.ioloop LIST_INFO = [ {'username':'zhangyanlin','email':'133@164.com'} ] for i in range(200): temp = {'username':str(i)+"zhang",'email':str(i)+"@163.com"} LIST_INFO.append(temp) class Pagenation: def __init__(self,current_page,all_item,base_url): #当前页 内容总数 目录 try: page = int(current_page) except: page = 1 if page < 1: page = 1 all_page,c = divmod(all_item,5) if c > 0: all_page +=1 self.current_page = page self.all_page = all_page self.base_url = base_url @property def start(self): return (self.current_page - 1) * 5 @property def end(self): return self.current_page * 5 def string_pager(self): list_page = [] if self.all_page < 11: s = 1 t = self.all_page + 1 else: if self.current_page < 6: s = 1 t = 12 else: if (self.current_page + 5) < self.all_page: s = self.current_page-5 t = self.current_page + 6 else: s = self.all_page - 11 t = self.all_page +1 first = '<a href = "/index/1">首页</a>' list_page.append(first) # 当前页 if self.current_page == 1: prev = '<a href = "javascript:void(0):">上一页</a>' else: prev = '<a href = "/index/%s">上一页</a>'%(self.current_page-1,) list_page.append(prev) #页码 for p in range(s,t): if p== self.current_page: temp = '<a class = "active" href = "/index/%s">%s</a>'%(p,p) else: temp = '<a href = "/index/%s">%s</a>' % (p, p) list_page.append(temp) # 尾页 if self.current_page == self.all_page: nex = '<a href = "javascript:void(0):">下一页</a>' else: nex = '<a href = "/index/%s">下一页</a>' % (self.current_page + 1,) list_page.append(nex) last = '<a href = "/index/%s">尾页</a>'%(self.all_page) list_page.append(last) #跳转 jump = '''<input type="text"><a onclick = "Jump('%s',this);">GO</a>'''%('/index/') script = ''' <script> function Jump(baseUrl,ths){ var val = ths.previousElementSibling.value; if (val.trim().length > 0){ location.href = baseUrl + val; } } </script> ''' list_page.append(jump) list_page.append(script) str_page = "".join(list_page) return str_page class IndexHandler(tornado.web.RequestHandler): def get(self, page): obj = Pagenation(page,len(LIST_INFO),'/index/') current_list = LIST_INFO[obj.start:obj.end] str_page = obj.string_pager() self.render('index.html', list_info=current_list, current_page=obj.current_page, str_page=str_page) application = tornado.web.Application([ (r'/index/(?P<page>\d*)',IndexHandler) ]) if __name__ == "__main__": application.listen(8080) tornado.ioloop.IOLoop.instance().start()