Tornado是使用Python编写的一个强大的、可扩展的Web服务器。它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中。
Tornado与现代主流的Web服务器框架有着明显的区别:它是多进程非阻塞式的服务器,速度相当快。这得益于其非阻塞的方式和对epoll的运用。Tornado每秒可以处理数以千计的连接,对于实时Web服务来说Tornado确实是一个理想的Web框架。
优势:
轻量级web框架
异步非阻塞IO处理方式
出色的抗负载能力
优异的处理性能,不依赖多进程/多线程,一定程度上解决C10K问题
WSGI全栈替代产品,推荐同时使用其web框架和HTTP服务器
结构:
Web框架
主要包括RequestHandler用于创建Web应用程序和各种支持类的子类
HTTP服务器与客户端
主要包括HTTPServer和AsyncHTTPClient
异步网络库
主要包括IOLoop和IOStream作为HTTP组件的构建块
协程库
模块:
核心Web框架tornado.web包括Web框架大部分主要功能,包括RequestHandler和Application类。
tornado.httpserver一个无阻塞HTTP服务器的实现
tornado.template模板系统
tornado.escapeHTML、JSON、URLs等编码解码和字符串操作
tornado.locale国际化支持
异步网络底层模块tornado.ioloop核心IO循环
tornado.iostream对非阻塞的Socket的简单封装以方便常用读写操作
tornado.httpclient无阻塞的HTTP服务器实现
tornado.netutil网络应用的实现主要是TCPServer类
系统集成服务tornado.auth使用OpenId和OAuth进行第三方登录
tornado.databaseMySQL服务端封装
tornado.platform.twisted在Tornado上运行Twisted实现的代码
tornado.websocket实现和浏览器的双向通信
tornado.wsgi其他Python网络框架或服务器的相互操作
应用模块tornado.autoload产生环境中自动检查代码更新
tornado.gen基于生成器的接口,使用该模块保证代码异步运行。
tornado.httputil分析HTTP请求内容
tornado.options解析终端参数
tornado.process多进程实现的封装
tornado.stack_context异步环境中对回调函数上下文保存、异常处理
tornado.testing单元测试
Tornado服务器的三个底层核心模块
1、httpserver服务于web模块的一个简单的HTTP服务器的实现
Tornado的HTTPConnection类用来处理HTTP请求,包括读取HTTP请求头、读取POST传递的数据,调用用户自定义的处理方法,以及把响应数据写给客户端的socket。
2、iostream对非阻塞式的socket的封装以便于常见读写操作
为了在处理请求时实现对socket的异步读写,Tornado实现了IOStream类用来处理socket的异步读写。
3、ioloop核心的I/O循环
Tornado为了实现高并发和高性能,使用了一个IOLoop事件循环来处理socket的读写事件,IOLoop事件循环是基于Linux的epoll模型,可以高效地响应网络事件,这是Tornado高效的基础保证。
核心模块关系与请求流程
设计模型:
Tornado不仅仅是一个Web框架,它完整地实现了HTTP服务器和客户端,在此基础上提供了Web服务,它可分为四层:
1、Web框架:最上层,包括处理器、模板、数据库连接、认证、本地化等Web框架所需功能。
2、HTTP/HTTPS层:基于HTTP协议实现了HTTP服务器和客户端
3、TCP层:实现TCP服务器负责数据传输
4、Event层:最底层、处理IO事件
设计模型
Tornado是一个编写对HTTP请求响应的框架。作为程序员,你的工作是编写响应特定条件HTTP请求的响应的handler。下面是一个全功能的Tornado应用的基础示例:
wcp_tornado.py
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define('port', default=8000, help='run on the given port', type=int)
class Indexfun(tornado.web.RequestHandler):
def get(self):
name = self.get_argument('v1','v2')
self.write('hello, ' + name)
if __name__ == '__main__':
tornado.options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", Indexfun)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
让我们把这个例子分成小块,逐步分析它们:
importtornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define('port', default=8000, help='run on the given port', type=int)
程序顶部导入了tornado下的模块,而且使用了tornado.options从命令行读取设置,如果执行命令行没有设置port参数,则使用默认值进行替代,而且格式要与type设置的格式相同。
classIndexfun(tornado.web.RequestHandler):
def get(self):
定义了一个tornado的请求处理函数类Indexfun,当处理一个请求时,Tornado将这个类实例化,并调用与HTTP请求方法所对应的方法。在这个例子中,我们只定义了一个get方法,也就是说这个处理函数将对HTTP的GET请求作出响应。我们稍后将看到实现不止一个HTTP方法的处理函数。
name = self.get_argument('v1','v2')
Tornado的RequestHandler类有一系列有用的内建方法,包括get_argument,我们在这里从一个查询字符串中取得参数greeting的值。如果这个参数没有出现在get请求的url中,Tornado将使用get_argument的第二个参数作为默认值。
self.write('hello, ' + name)
RequestHandler的另一个有用的方法是write,它以一个字符串作为函数的参数,并将其写入到HTTP响应中。在这里,我们使用请求中greeting参数提供的值插入到greeting中,并写回到响应中。
if __name__ == '__main__':
tornado.options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", Indexfun)])
这是真正使得Tornado运转起来的语句。首先,我们使用Tornado的options模块来解析命令行。然后我们创建了一个Tornado的Application类的实例。传递给Application类init方法的最重要的参数是handlers。它告诉Tornado应该用哪个类来响应请求。
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
从这里开始的代码将会被反复使用:一旦Application对象app被创建,我们可以将其传递给Tornado的HTTPServer对象,然后使用我们在命令行指定的端口进行监听(通过options.port取出。)最后,在程序准备好接收HTTP请求后,我们创建一个Tornado的IOLoop的实例。
注意:tornado5.0之后的版本,instance()已经成为current()的别称,即就是调用instance方法时,实际上调用的是current方法。
再看一眼wcp_tornado.py中的这一行:
app = tornado.web.Application(handlers=[(r"/", Indexfun)])
这个handlers参数很重要,它应该是一个元组组成的列表,其中每个元组的第一个元素是一个匹配HTTP请求的路径的正则表达式,这个路径是URL中主机名后面的部分,不包括查询的参数。,第二个元素是一个RequestHanlder类,也就是我们编写的响应请求的视图函数类。在wcp_tornado.py中,我们只指定了一个正则表达式-RequestHanlder对,但你可以按你的需要指定任意多个。