Tornado入门

一、概述

       Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本。这个 Web 框架看起来有些像是一个py文件,不过为了能有效利用非阻塞式服务器环境,这个 Web 框架还包含了一些相关的有用工具和优化。
       Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。

 

       首先将带着大家一起来剖析基于python编写的Web框架 tornado ,本着易读易懂的目标来写这一系列,寄希让小白也能明白其中的道理。

在了解Tornado之前,让我们来看一下Tornado框架背后的原理,其实就是运用了socket。

运行start.py脚本并在浏览器上访问http://127.0.0.1:8080 , 你会看到页面输出 Hello, Seven

#!/usr/bin/env python
#coding:utf-8
 
import socket
 
def handle_request(client):
    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n")
    client.send("Hello, Seven")
 
def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8080))
    sock.listen(5)
 
    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()
 
if __name__ == '__main__':
    main()
start.py

分析:

  ① 浏览器其实就是一个socket客户端,而web应用其实就是一个socket服务端,并且web应用在服务器上一直在监听某个端口。
  ② 当浏览器请求某个web应用时,需要指定服务器的IP(DNS解析)和端口建立一个socket连接。
  ③ 建立链接后,web应用根据请求的不同,给用户返回相应的数据。
  ④ 断开socket连接。(之所以说http是短链接,其实就是因为每次请求完成后,服务器就会断开socket链接)


  对于Web框架来说,一般分为两类:

  ① 其中一类则是包含上述 4部分 内容的框架,② 另外一类就是只包含第3部分功能的框架。

       Tornado就是一中属于前者的框架。Tornado 是一个基于 Python 开发的web框架,较其他 Web 框架的区别是:采用了非阻塞的方式和对epoll的应用。这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。

 

二、Tornado的简单应用

下载安装:

pip3 install tornado

源码安装:
https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz

简单的hello world 案例,在浏览器输入http://127.0.0.1:8888/index :

import tornado.ioloop
import tornado.web
 
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
 
application = tornado.web.Application([
    (r"/index", MainHandler),
])
 
if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

运行该脚本,依次执行:
       ① 创建一个Application对象,并把一个正则表达式'/'和类名MainHandler传入构造函数:tornado.web.Application(...)  
       ② 执行Application对象的listen(...)方法,即:application.listen(8888)
       ③ 执行IOLoop类的类的 start() 方法,即:tornado.ioloop.IOLoop.instance().start()
       ④ 整个过程其实就是在创建一个socket服务端并监听8888端口,当请求到来时,根据请求中的url和请求方式(post、get或put等)来指定相应的类中的方法来处理本次请求

 

ps:

 #!/usr/bin/env python
 # -*- coding:utf-8 -*-
 #!/usr/bin/env python
 # -*- coding:utf-8 -*-
 
 import tornado.ioloop
 import tornado.web
 from tornado import httpclient
 from tornado.web import asynchronous
 from tornado import gen
 
 import uimodules as md
 import uimethods as mt
 
 class MainHandler(tornado.web.RequestHandler):
         @asynchronous
         @gen.coroutine
         def get(self):
             print 'start get '
             http = httpclient.AsyncHTTPClient()
             http.fetch("http://127.0.0.1:8008/post/", self.callback)
             self.write('end')
 
         def callback(self, response):
             print response.body
 
 settings = {
     'template_path': 'template',    # 前端页面
     'static_path': 'static',              
     'static_url_prefix': '/static/',
     'ui_methods': mt,                  # 自定制模板
     'ui_modules': md,                 # 自定制模板
 }
 
 application = tornado.web.Application([
     (r"/index", MainHandler),
 ], **settings)
 
 
 if __name__ == "__main__":
     application.listen(8009)
     tornado.ioloop.IOLoop.instance().start()
异步非阻塞示例

 

三、流程介绍

(1)路由系统

路由系统其实就是 url 和 类 的对应关系,这里不同于其他框架,其他很多框架均是 url 对应 函数,Tornado中每个url对应的是一个类。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
import tornado.ioloop
import tornado.web
   
   
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
   
class StoryHandler(tornado.web.RequestHandler):
    def get(self, story_id):
        self.write("You requested the story " + story_id)
   
class BuyHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("buy.wupeiqi.com/index")
   
application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/story/([0-9]+)", StoryHandler),
])
   
application.add_handlers('ray.com$', [
    (r'/index',BuyHandler),       # 二级
])
   
if __name__ == "__main__":
    application.listen(80)
    tornado.ioloop.IOLoop.instance().start()
View Code

 

(2)模板引擎

  1) 默认

Tornao中的模板语言和django中类似,模板引擎将模板文件载入内存,然后将数据嵌入其中,最终获取到一个完整的字符串,再将字符串返回给请求者。
Tornado 的模板支持“控制语句”和“表达语句”,控制语句是使用 {% 和 %} 包起来的 例如 {% for item in demo %}。表达语句是使用 {{   }} 包起来的,例如 {{ items[0] }}。
通过 extends 和 block 语句实现了模板继承。

注意:

         在使用模板前需要在setting中设置模板路径:"template_path" : "views"    --> (别名不规定)

         这里跟Django有点不太一样,Django获取是直接用 点 来获取值的,Tornado要使用列表形式获取,如{{ items[0] }}

         控制语句要用{% end %} 结束

 

  2) 自定义UIMethod和UIModule

import tornado.ioloop
import tornado.web
from controllers.account import LoginHandler
from controllers.home import HomeHandler

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # self.write("Hello, world")
        self.render("main.html")
        # self.redirect('http://www.baidu.com')

import uimethods as ut
import uimodules as mm

settings = {
    "template_path": 'views',           # 模板
    "cookie_secret":'abcdefgijk',       # cookie加密
    "ui_methods":ut,                    # 模板标签不渲染
    "ui_modules":mm,                    # 模板标签自动渲染
    "static_path":'static',
}

application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
    (r"/home", HomeHandler),
],**settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
app.py
"""
模板标签不自动渲染
"""
from tornado import escape

def tab(request,val):

    # print(request)      # LoginHandler
    # print(val)          # 前端传过来的值
    return "<h1>这是模板</h1>"
uimethods.py
"""
模板自动帮我们渲染
"""

from tornado.web import UIModule
from tornado import escape

class Foo(UIModule):
    def css_files(self):
        """添加static下面的common.css样式到login.html"""
        return "common.css"
    def embedded_css(self):
        """添加下面的样式到login.html"""
        return ".c1{display:none}"
    def javascript_files(self):
        """添加static下面的common.js样式到login.html"""
        return "common.js"
    def embedded_javascript(self):
        """添加下面的JS样式到login.html"""
        return "function fun(){alert(1)}"

    def render(self):

        return "<h1>这是modules模板</h1>"
        # return escape.xhtml_escape("<h1>这是modules模板</h1>")
uimodules.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    {{ tab(666) }}              <!--不渲染-->
    {% raw tab(11) %}           <!--帮我们渲染-->

    {% module Foo() %}          <!--自动渲染-->
    <form action="/login" method="post">
        <input type="text" name="username"><br>
        <input type="text" name="password"><br>
        <input type="submit" value="提交">{{ msg }}
    </form>
    <script>
        window.onload=function () {
            // fun();
        }
    </script>
</body>
</html>
login.html

 参考:

 

 

Keep coding...

posted @ 2019-03-23 00:28  rayh  阅读(218)  评论(0编辑  收藏  举报