01: tornado基础篇
目录:Tornado其他篇
01: tornado基础篇
02: tornado进阶篇
03: 自定义异步非阻塞tornado框架
04: 打开tornado源码剖析处理过程
目录:
- 1.1 Tornado安装与基本使用
- 1.2 tornado各种url写法
- 1.3 配置settings & 获取get,post请求
- 1.4 tornado渲染
- 1.5 自定义UIMethod和UIModule: 类似于djando中simple_tag和自定义filter
- 1.6 模板继承
- 1.7 tornado多文件上传
- 1.8 @gen.coroutine实现异步非阻塞举例及原理解析
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!!”请求内容
importtornado.ioloopimporttornado.web#1、 处理访问/index/的get请求: http://127.0.0.1:8888/index/ classMainHandler(tornado.web.RequestHandler):defget(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/ classLoginHandler(tornado.web.RequestHandler):defget(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)
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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+),可以不考虑接收参数顺序 (推荐)
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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请求
importtornado.ioloopimporttornado.web#1、 处理访问/index/的get请求: http://127.0.0.1:9999/index classMainHandler(tornado.web.RequestHandler):defget(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 classLoginHandler(tornado.web.RequestHandler):defget(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> <htmllang="en"> <head><metacharset="UTF-8"><title>Title</title><linkrel="stylesheet"href="/static/base.css"> </head> <body><formmethod="POST"action="/login/"><inputtype="text"name="username"><h5class="c1">多选</h5>男球:<inputtype="checkbox"name="faver"value="1" />足球:<inputtype="checkbox"name="faver"value="2" />皮球:<inputtype="checkbox"name="faver"value="3" /><inputtype="submit"value="提交"></form> </body> </html>
/template/login.html
.c1{color:red; }
/template/base.css
1.4 tornado渲染 返回顶部
1、for循环
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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、判断相等
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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> <htmllang="en"> <head><metacharset="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使用举例
importtornado.ioloopimporttornado.webfrom tornado.escape importlinkifyimport uimodules as md #1.导入uimodules模块 import uimethods as mt #2.导入uimethods模块classMainHandler(tornado.web.RequestHandler):defget(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 importUIModulefrom tornado importescape#uimodule不仅可以帮生成标签,还可以帮添加css,js样式 classcustom(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定义
deftab(self):return '<h1>tom</h1>'
uimethods.py定义
<!DOCTYPE html> <htmllang="en"> <head><metacharset="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" %}
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(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> <htmllang="en"> <head><metacharset="UTF-8"><title>Title</title><title>{% block title %}Default title{% end %}</title><linkrel="stylesheet"href="/static/css/base.css">{% block css %}{% end %}</head> <body><divclass="c1">这里是layout.html这个母版中的内容</div>{% block RenderBody %}{% end %}</body> </html>
layout.html 母版文件
{% extends 'layout.html'%} {% block css %}<linkrel="stylesheet"href="/static/css/index.css">{% end %}{% block RenderBody %}<h3class="c1">这个RenderBody块继承的是header.html这个母版</h3><div>{% include 'header.html' %}</div>{% end %}
index.html 子版中引入母版
<h3>这里是header.html中的内容,需要导入的文件</h3>
header.html 被导入的文件
1.7 tornado多文件上传 返回顶部
importtornado.ioloopimporttornado.webclassMainHandler(tornado.web.RequestHandler):defget(self):self.render('index.html')def post(self, *args, **kwargs):file_metas= self.request.files["fff"]for meta infile_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><metahttp-equiv="Content-Type"content="text/html; charset=UTF-8"/><title>上传文件</title> </head> <body><formid="my_form"name="form"action="/index"method="POST"enctype="multipart/form-data" ><inputname="fff"id="my_file"type="file" /><inputtype="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有数据到达了,就通知用户进程
importtornado.ioloopimporttornado.webfrom tornado importgenclassIndexHandler(tornado.web.RequestHandler):@gen.coroutinedefget(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 -*- importtornado.ioloopimporttornado.webfrom tornado importgenfrom tornado.concurrent importFuturefuture=NoneclassIndexHandler(tornado.web.RequestHandler):@gen.coroutinedefget(self):globalfuturefuture=Future()future.add_done_callback(self.doing)yieldfuturedef doing(self,*args,**kwargs):self.write('async')self.finish()classStopHandler(tornado.web.RequestHandler):defget(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异步非阻塞简单原理
转载于:https://www.cnblogs.com/xiaonq/p/8026197.html
01: tornado基础篇相关推荐
- Arduino 高级教程 01:基础篇
我与 Arduino,以及为什么要写这个系列的文章 Arduino 这个已经火了好多年了,早就不是什么新鲜的技术.如果有人还不清楚 Arduino 是个什么东西,对不起,请自行搜索,随便翻开哪个维基百 ...
- 视觉slam学习|基础篇01
系列文章目录 SLAM基础篇01 SLAM基础篇02 目录 系列文章目录 前言 SLAM是干什么的? SLAM的数学建模 机器人学基础 齐次矩阵 关于旋转的表示:旋转向量.欧拉角.四元数 李群和李代数 ...
- mysql经典总结文章_MySQL基础篇(01):经典实用查询案例,总结整理
MySQL基础篇(01):经典实用查询案例,总结整理 发布时间:2020-02-26 22:25:21 来源:51CTO 阅读:244 作者:知了一笑 本文源码:GitHub·点这里 || GitEE ...
- python 01列表异或_python基础篇三
python基础篇二所介绍的列表是基本的数据类型之一,元组.集合.字典也是基本的数据类型之一.熟练运用这些基本的数据类型很重要,就像是一座高楼大厦,把地基打扎实了,这栋高楼大厦才能在狂风暴雨中岿然不动 ...
- 小何同学的leetcode刷题笔记 基础篇(01)整数反转
小何同学的leetcode刷题笔记 基础篇(01)整数反转[07] *** [01]数学取余法*** 对数字进行数位操作时,常见的方法便是用取余的方法提取出各位数字,再进行操作 操作(1):对10取余 ...
- Jmeter 入门 从0-1 基础篇-实操
Jmeter 入门 从0-1 基础篇 笔记有的图片链接可能失效了,等我修改好了在来编辑哈 文章目录 1 JMeter 1.1 JMeter环境搭建和基本使用 1.1.1 JMeter环境搭建 1.1. ...
- 01 MSC类设备-基础篇(一)
一.简介 在USB协议中,规定了一类大容量存储设备(Mass Storage Device Class)协议.常见的USB大容量设备有:U盘.USB移动硬盘.USB移动光驱.USB读卡器.USB打印机 ...
- 01 - Java并发编程与高并发解决方案笔记-基础篇
01 - Java并发编程与高并发解决方案笔记-基础篇 基础篇很重要!很重要!很重要!!!一定要理解和认真思考. 01 - Java并发编程与高并发解决方案笔记-基础篇 1.课程准备 2.并发编程基础 ...
- 自然语言处理——基础篇01
自然语言处理--基础篇01 一.什么是自然语言处理? 二.自然语言处理的难点与特点? 三.语言模型 四.NLP的常见任务类型 1. 中文分词 2. 子词切分(Subword) 3. 句法分析 4. 语 ...
最新文章
- 架构师之路 — API 经济 — 身份认证系统
- MySQL学习笔记_9_MySQL高级操作(上)
- linux系统管理命令,压缩命令
- 在Delphi程序中应用IE浏览器控件
- 【Paper】英文论文写作小技巧
- make pycaffe 报错:“fatal error: numpy/arrayobject.h: No such file or directory” 解决方案
- 设计模式学习---(2)工厂模式
- MySQL 如何查找并删除重复行
- lightshot截图工具的安装及使用
- LoadRunner字符串编码转换函数:lr_convert_string_encoding
- python列表语法_python学习之列表语法
- 开源微信小程序源码+小程序游戏代码附搭建框架教程
- PRN(20201012):Improved updating of Euclidean distance maps and Voronoi diagrams
- 寺庙招聘爆火:月薪15000,五险一金,早九晚五,周末双休,饭菜免费!网友:想出家了......
- Web 中的“选区”和“光标”需求实现
- 离职后重回老东家?你需要明白这些事情
- 【对称日】今天朋友圈对称日刷屏了,也来凑个热闹,用代码实力打脸
- VMware虚拟机怎么安装ghost系统
- 什么是锁PHP,并发下常见的加锁及锁的PHP具体实现代码
- 微信H5支付(V3)