zoukankan      html  css  js  c++  java
  • 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
    
    ")
        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...

  • 相关阅读:
    在网易和百度实习之后,我才明白了这些事
    从Java小白到收获BAT等offer,分享我这两年的经验和感悟
    曾经做的一个JS小游戏——《Battle City》
    适配器(Adapter)模式
    装饰器(Decorator)模式
    Java IO
    JDBC中驱动加载的过程分析
    从PipedInputStream/PipedOutputStream谈起
    从InputStream到ByteArrayInputStream
    JDK中的动态代理
  • 原文地址:https://www.cnblogs.com/ray-h/p/10582241.html
Copyright © 2011-2022 走看看