zoukankan      html  css  js  c++  java
  • 01: tornado基础篇

    目录:Tornado其他篇

    01: tornado基础篇

    02: tornado进阶篇

    03: 自定义异步非阻塞tornado框架

    04: 打开tornado源码剖析处理过程

    目录:

    1.1 Tornado安装与基本使用     返回顶部

      1、 安装tornado

        1、pip3安装
            pip3 install tornado

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

      2、tornado概述

          1、Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本

          2、Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。

          3、得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接

          4、我们开发这个 Web 服务器的主要目的就是为了处理 FriendFeed 的实时功能 ——在 FriendFeed 的应用里
               每一个活动用户都会保持着一个服务器连接。

      3、tornado快速上手

          1、使用pycharm创建一个普通项目s131415文件夹,并创建文件s131415/app.py
          2、在app.py中粘贴下列内容,运行app.py文件
          3、在浏览器中访问: http://127.0.0.1:8888/index 即可看到“Hello, world!!”请求内容

    import tornado.ioloop
    import tornado.web
    
    #1、 处理访问/index/的get请求: http://127.0.0.1:8888/index/
    class MainHandler(tornado.web.RequestHandler):
       def get(self):
          self.write("I am index!!")
          # self.redirect('http://www.baidu.com')
          # self.render('index.html',k1='v1')
    
    #2、 处理访问 /login/的post请求和get请求: http://127.0.0.1:8888/login/
    class LoginHandler(tornado.web.RequestHandler):
       def get(self):
          self.write('login')
       def post(self,*args,**kwargs):
          self.write('login post')
    
    #3、 配置settings
    settings = {
        'template_path': 'template',         # 配置html文件模板位置
        'static_path': 'static',             # 配置静态文件路径(图片等)
        'static_url_prefix': '/static/',     # 前端引入静态文件路径
    }
    
    #4 路由系统
    application = tornado.web.Application([
       (r"/index/", MainHandler),
       (r"/login/", LoginHandler),
    ],**settings)
    
    #5 启动这个tornado这个程序
    if __name__ == "__main__":
       application.listen(8888)
       tornado.ioloop.IOLoop.instance().start()
    tornado基本使用

    1.2 tornado各种url写法     返回顶部

      1、无正则匹配url  (http://127.0.0.1:8000/index/?nid=1&pid=2)

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            nid = self.get_query_argument('nid')
            pid = self.get_query_argument('pid')
            self.write("Hello, world")
    
    # http://127.0.0.1:8000/index/?nid=1&pid=2
    application = tornado.web.Application([
        (r"/index/", MainHandler),
    ])
    
    if __name__ == "__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    app.py

      2、基于(d+)正则的url

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self,nid,pid):
            print(nid,pid)
            self.write("Hello, world")
    
    # http://127.0.0.1:8000/index/1/2/
    application = tornado.web.Application([
        (r"/index/(d+)/(d+)/", MainHandler),        # 这种只能传数字
        # (r"/index/(w+)/(w+)/", MainHandler),        # 这种可以传数字、字母、下划线
    ])
    
    if __name__ == "__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    app.py

      3、基于正则分组(?P<nid>d+),可以不考虑接收参数顺序 (推荐)

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self,nid,pid):
            print(nid,pid)
            self.write("Hello, world")
    
    # http://127.0.0.1:8000/index/1/2/
    application = tornado.web.Application([
        (r"/index/(?P<nid>d+)/(?P<pid>d+)/", MainHandler),        # 这种只能传数字
    ])
    
    if __name__ == "__main__":
        application.listen(8000)
        tornado.ioloop.IOLoop.instance().start()
    app.py

    1.3 配置settings & 获取get,post请求     返回顶部

      1、settings可配置参数

    settings = {
        'template_path': 'template',        #配置html文件模板位置
        'static_path': 'static',             #配置静态文件路径(图片等)
        'static_url_prefix': '/static/',    #前端引入静态文件路径
        'ui_methods': mt,
        'ui_modules': md,
    
        'xsrf_cookies':True,
        'cookie_secret':'xxx',
        'login_url':"/auth/login",
        'autoescape':None,
        'local':"zh_CN",
        'debug':True,
    }
    tornado中settings字典可配置参数

      2、获取get、post请求

    import tornado.ioloop
    import tornado.web
    
    #1、 处理访问/index/的get请求: http://127.0.0.1:9999/index
    class MainHandler(tornado.web.RequestHandler):
       def get(self):
          self.write("I am index!!")
          # self.redirect('http://www.baidu.com')
          # self.render('index.html',k1='v1')
    
    #2、 处理访问 /login/的post请求和get请求: http://127.0.0.1:9999/login
    class LoginHandler(tornado.web.RequestHandler):
       def get(self):
    
          #2.1 获取url中以get方式传递过来的数据: http://127.0.0.1:9999/login/?username=zhangsan
          # print(self.get_query_argument('username'))        # zhangsan
          # print(self.get_query_arguments('username'))       # ['zhangsan']
          # print( self.get_argument('username') )            # get和post两种请求传递的数据都能获取
    
          self.render('login.html')
       def post(self,*args,**kwargs):
    
          #2.2 获取请求体中以post传递的数据
          # print( self.get_body_argument('faver') )     # 仅能获取单选,多选仅能获取最后一个
          # print( self.get_body_arguments('faver') )    # ['1', '2', '3']  获取多选
    
          #2.3 get和post两种请求传递的数据都能获取
          # print( self.get_argument('username') )
    
          #2.4 设置和获取cookie
          # self.cookies
          # self.set_cookie()
    
          #2.5 设置和获取请求头
          # self._headers
          # self.get_header()
    
          self.write('login post')
    
    #3、 配置settings
    settings = {
        'template_path': 'template',         # 配置html文件模板位置
        'static_path': 'static',             # 配置静态文件路径(图片等)
        'static_url_prefix': '/static/',     # 前端引入静态文件路径
    }
    
    #4 路由系统
    application = tornado.web.Application([
       (r"/index/", MainHandler),
       (r"/login/", LoginHandler),
    ],**settings)
    
    #5 启动这个tornado这个程序
    if __name__ == "__main__":
       application.listen(9999)
       tornado.ioloop.IOLoop.instance().start()
    app.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/base.css">
    </head>
    <body>
        <form method="POST" action="/login/">
            <input type="text" name="username">
    
            <h5 class="c1">多选</h5>
                男球:<input type="checkbox" name="faver" value="1" />
                足球:<input type="checkbox" name="faver" value="2" />
                皮球:<input type="checkbox" name="faver" value="3" />
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    /template/login.html
    .c1{
        color: red;
    }
    /template/base.css

    1.4 tornado渲染     返回顶部

      1、for循环

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
       def get(self):
          self.render("index.html", username='tom',list_info=[11, 22, 33],user_dic={'username':'zhangsan','age':77})
    
    application = tornado.web.Application([
       (r"/index", MainHandler),
    ])
    
    if __name__ == "__main__":
       application.listen(8888)
       tornado.ioloop.IOLoop.instance().start()
    app.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h3>用户名:{{username}}</h3>
        {% for item in list_info %}
            <li>{{item}}</li>
        {% end %}
        <p></p>
        {% for item in user_dic %}
            <li>{{item}} : {{user_dic[item]}}</li>
        {% end %}
    </body>
    </html>
    index.html

      2、if、in、判断相等

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
       def get(self):
          self.render("index.html", list_info=[11, 22, 33],username='tom')
    
    application = tornado.web.Application([
       (r"/index", MainHandler),
    ])
    
    if __name__ == "__main__":
       application.listen(8888)
       tornado.ioloop.IOLoop.instance().start()
    app.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        {% if 11 in list_info %}
            true
        {% else %}
            false
        {% end %}
        
        {% if username == "tom" %}
            my name is {{username}}
        {% else %}
            not tom
        {% end %}
    </body>
    </html>
    index.html

    1.5 自定义UIMethod和UIModule: 类似于djando中simple_tag和自定义filter      返回顶部

      1、UIModule与UIMethod比较

          1. UIModule: 可以传参、可以生成html、css、js代码

          2. UIMethod: 这个不能传参数,不能生成css,js等,只能生成html文件

      2、UIModule和UIMethod使用举例

           

    import tornado.ioloop
    import tornado.web
    from tornado.escape import linkify
    import uimodules as md     #1.导入uimodules模块
    import uimethods as mt     #2.导入uimethods模块
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html')
    settings = {
        'template_path': 'template',
        'static_path': 'static',
        'static_url_prefix': '/static/',
        'ui_methods': mt,      #3.将uimethods模块注册到settings中
        'ui_modules': md,      #4.将uimodules模块注册到settings中
    }
    
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ], **settings)
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    app.py注册
    from tornado.web import UIModule
    from tornado import escape
    
    # uimodule不仅可以帮生成标签,还可以帮添加css,js样式
    class custom(UIModule):
       # def javascript_files(self):
       #    '''1、生成: <script src="base.js"></script> '''
       #    return ['base.js','header.js']
       #
       # def embedded_javascript(self):
       #    '''2、生成:  <script> alert(123); </script> '''
       #    return "alert(123);"
       #
       # def css_files(self):
       #    '''3、在头部生成: <link rel="stylesheet" href="base.css">'''
       #    return ['base.css','header.css']
       #
       # def embedded_css(self):
       #    '''4、在头部style标签生成: <style> .c1{ color:red; } </style>'''
       #    return ".c1{color:red;}"
    
       def render(self, *args, **kwargs):
          '''5、生成html文件'''
          return escape.xhtml_escape('<h1>tom</h1>')
    uimodules.py定义
    def tab(self):
        return '<h1>tom</h1>'
    uimethods.py定义
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>hello</h1>
        <p>{% module custom(123) %}</p>
    
        {{ tab() }}
    </body>
    </html>
    index.html使用

    1.6 模板继承     返回顶部

       1、模板继承使用

           1. 在master.html中定义模板:  {% block css %} {% endblock %}

           2. 在子类中引入要继承的模板:  {% extends 'layout.html' %}

       2、模板导入

           1. 使用时直接导入即可:  {% include "header.html" %}

                   

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
       def get(self):
          self.render("index.html")
    
    settings = {
       'template_path':'template',
       'static_path':'static',
       'static_url_prefix':'/static/',
    }
    
    application = tornado.web.Application([
       (r"/index/", MainHandler),
    ],**settings)
    
    if __name__ == "__main__":
       application.listen(8888)
       tornado.ioloop.IOLoop.instance().start()
    app.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <title>{% block title %}Default title{% end %}</title>
    
        <link rel="stylesheet" href="/static/css/base.css">
        {% block css %}{% end %}
    
    </head>
    <body>
        <div class="c1">这里是layout.html这个母版中的内容</div>
        {% block RenderBody %}{% end %}
    </body>
    </html>
    layout.html 母版文件
    {% extends 'layout.html'%}
    {% block css %}<link rel="stylesheet" href="/static/css/index.css">{% end %}
    
    {% block RenderBody %}
        <h3 class="c1">这个RenderBody块继承的是header.html这个母版</h3>
    
        <div>
            {% include 'header.html' %}
        </div>
    {% end %}
    index.html 子版中引入母版
    <h3>
         这里是header.html中的内容,需要导入的文件
    </h3>
    header.html 被导入的文件

    1.7 tornado多文件上传      返回顶部

    import tornado.ioloop
    import tornado.web
    
    class MainHandler(tornado.web.RequestHandler):
        def get(self):
            self.render('index.html')
    
        def post(self, *args, **kwargs):
            file_metas = self.request.files["fff"]
            for meta in file_metas:
                file_name = meta['filename']
                with open(file_name,'wb') as up:
                    print('hahah')
                    up.write(meta['body'])
    
    settings = {
        'template_path': 'template',
    }
    
    application = tornado.web.Application([
        (r"/index", MainHandler),
    ], **settings)
    
    
    if __name__ == "__main__":
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    app.py
    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>上传文件</title>
    </head>
    <body>
        <form id="my_form" name="form" action="/index" method="POST"  enctype="multipart/form-data" >
            <input name="fff" id="my_file"  type="file" />
            <input type="submit" value="提交"  />
        </form>
    </body>
    </html>
    index.html

    1.8 @gen.coroutine实现异步非阻塞举例及原理解析     返回顶部

      1、tornado.gen.coroutine和tornado.web.asynchronous比较

          1. @tornado.web.asynchronous 实现长连接,调用self.finish()才结束
          2. @tornado.gen.coroutine 这个实现异步
          3. 你要想异步,就要保持长连接,否则你的handler执行完就自己return了
          4. @asynchronous会监听@gen.coroutine的返回结果(Future),并在@gen.coroutine装饰的代码段执行完成后自动调用finish。
          5. 从Tornado 3.1版本开始,只使用@gen.coroutine就可以了。

      2、tornado实现异步原理 

          1. 每个请求过来就会创建一个socket对象,并yield一个future对象,然后tornado就处理下一个连接了
          2. tornado内部会以socket对象为key,future对象为value加入字典
          3. tornado内部调用epoll方法监听这个全局字典,有socket对象变化就会执行future.set_result('...')
          4. 执行future.set_result('...')后就会将future.ready标志位变成True,然后就会调用callback方法返回内容

          注1:yield 一个 Future对象,那么Tornado会等待,直到执行future.set_result('...')才会释放
          注2:epoll实质是不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程

    import tornado.ioloop
    import tornado.web
    from tornado import gen
    
    class IndexHandler(tornado.web.RequestHandler):
        @gen.coroutine
        def get(self):
            self.write('I am index!!')
    
    application = tornado.web.Application([
       (r"/index/", IndexHandler),
    ])
    
    if __name__ == "__main__":
        print('http://127.0.0.1:8888/index/')
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    tornado实现异步非阻塞举例
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    import tornado.ioloop
    import tornado.web
    from tornado import gen
    from tornado.concurrent import Future
    
    
    future = None
    class IndexHandler(tornado.web.RequestHandler):
        @gen.coroutine
        def get(self):
            global future
            future  = Future()
            future.add_done_callback(self.doing)
            yield future
    
        def doing(self,*args,**kwargs):
            self.write('async')
            self.finish()
    
    
    class StopHandler(tornado.web.RequestHandler):
        def get(self):
            future.set_result('.......')
    
    
    application = tornado.web.Application([
       (r"/index/", IndexHandler),
       (r"/stop/", StopHandler),
    ])
    
    if __name__ == "__main__":
        print('http://127.0.0.1:8888/index/')
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()
    
    
    '''
    http://127.0.0.1:8888/index/          # 只要不返回数据,浏览器就不会返回一直等着保持长连接
    http://127.0.0.1:8888/stop/           # 访问/stop/是会调用future.set_result()此时 /index/就会返回数据
    '''
    使用Future对象模拟tornado异步非阻塞简单原理
  • 相关阅读:
    第四章的知识点:
    第一章的知识点:
    13
    12
    11
    10
    9
    zy
    金嘉琪 作业
    1022作业
  • 原文地址:https://www.cnblogs.com/xiaonq/p/8026197.html
Copyright © 2011-2022 走看看