Tornado框架

Tornado框架

"""
**主要特点**:
1、拥有异步非阻塞IO的处理方式
2、作为服务器,具有出色的抗负载能力
**使用场景**:
1、抢票、网页游戏、大量的http持久连接
"""
# tornado安装
pip install tornado

主要支持

# 功能支持
"""
 1. url路由映射
 2. request上下文管理
 3. 基于模板的页面渲染
 4. 异步I/O支持,超时处理
 5. 服务器+客户端框架
 6. 内部HTTP服务器
 7. Websocket(HTML5)浏览器与服务器的双向实时通信
"""

概念

"""
 同步:代码调用I/O时,需要等I/O执行完成后,才能返回调用给下次调用, 顺序执行 
 异步:代码调用I/O时,无需等I/O执行完,就可以将函数返回给下次调用使用
 
 tornado框架客户端
 同步访问HTTP的客户端  ——  HTTPClient  (需要函数执行完成后,才将函数返回)
 异步访问HTTP的客户端  ——  AsycHTTPClient (无需等待函数完成,即可把函数返回
 
 协程
 原理:一个线程在执行过程中,利用发送请求等待应答的时间,再执行其他函数、或请求
 Tornado 主要是利用协程来实现的多并发。
 
 异步:	http.fetch("www.baidu.com", callback = self.on_response)
 协程:	response = yield http.fetch("www.badu.com")
								self.write(response.body)

 """

Tornado框架的主体架构
框架的主体架构
Hellow world 样例代码

# Hellow World
# tornado 核心IO循环模块(封装 linux的epoll 和BSD的kqueue队列)
import tornado.ioloop
import tornado.web

# handele业务处理类
class MainHandler(tornado.web.RequestHandler):
	# 处理get请求
    def get(self):
        self.write("Hello world")

def make_app():
	# Application: 核心应用类,与服务器对应的接口,保存路由映射表
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

def main():
	# 实例化
    app = make_app()
    # listen 绑定监听端口,listen 方法用来创建 一个HTTP服务器实例
    app.listen(8888)
    # IOLoop.current()  返回当前线程的IOLoop实例
	# IOLoop.start()    启动 IOLoop实例循环,开启监听
    tornado.ioloop.IOLoop.current().start()  # 不退出、处理用户请求

if __name__ == "__main__":
    main()

创建服务器对象

# 方式 1 :
if__name__ == "__main__":
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	app.listen(8000)  # 创建一个服务器对象,并给服务器绑定一个端口,启动单进程
	tornado.ioloop.IOLoop.current().start()


# 方式 2 :
if__name__ == "__main__":
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	# 实例化一个HTTP服务器对象,将服务绑定在端口 8000 
	httpServer = tornado.httpserver.HTTPServer(app)
	httpServer.listen(8000)
	tornado.ioloop.IOLoop.current().start()


# 方式 3 :
# 启动多个线程
if__name__ == "__main__":
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	# 实例化一个HTTP服务器对象
	httpServer = tornado.httpserver.HTTPServer(app)
	# 将服务器绑定到指定端口
	httpServer.bin(8000)
	# 启动多个进程
	httpServer.start(3)
	tornado.ioloop.IOLoop.current().start()

定义全局参数

"""
**tornado.optins模块**作用:
1、全局参数的定义、存储、转换

基础方法:
1、tornado.options.define()   定义 options 选项变量的方法
2、tornado.options.options()   使用 options 变量的方法

函数解析:
tornado.options.define(name,default = None,type = None,help = None,metavar = None,multiple = False,group = None,callback = None)  # 定义options 选项变量的方法
 - name  # 变量名称,保持唯一性
 - default  # 设置选项的默认值,默认为None
 - type  # 设置变量类型,默认为 define的类型
 - multiple  # 设置选项变量是否可以是多个值,默认为false
 - help  # 选项变量的提示信息

**# 获取全局参数的方法**
1、tornado.options.parse_command_line()  # 将命令行中的参数转化,并保存到 tornado.options.options
2、tornado.options.parse_config_file(path)  # 从配置文件导入参数 path为文件路径
"""

# 1、命令行获取全局变量
import tornado.options
# 定义两个全局变量
tornado.options.define("port",default = 8000,type= int)
tornado.options.define("list",dafault = [],type = str)

if__name__ == "__main__":
	# 通过命令行获取全局参数变量(手动启动程序时进行输入)
	tornado.options.parse_command_line()
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	httpServer = tornado.httpserver.HTTPServer(app)
	# 使用全局变量 port
	httpServer.bin(tornado.options.options.port)
	httpServer.start(3)
	tornado.ioloop.IOLoop.current().start()


# 2、从配置文件中获取全局变量
"""
/ config 配置文件中
port = 7000
list = ["one","two","three"]
"""
import tornado.options
# 定义两个全局变量
tornado.options.define("port",type= int)
tornado.options.define("list",type = str)

if__name__ == "__main__":
	# 通过全局配置文件进行获取  config 文件
	tornado.options.parse_config_file("config")  
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	httpServer = tornado.httpserver.HTTPServer(app)
	# 使用全局变量 port
	httpServer.bin(tornado.options.options.port)
	httpServer.start(3)
	tornado.ioloop.IOLoop.current().start()


# 3.目前常用方法(把config 当成一个包来用 )  config.py 
"""
/ config.py 配置文件中
options = {
	"port": 8000,
	"list": ["one","two","three"]
	}
"""
import tornado.options
import config

if__name__ == "__main__": 
	print(config.options.list)
	app = tornado.web.Application([
		(r"/",IndexHandler)
	])
	httpServer = tornado.httpserver.HTTPServer(app)
	# 使用全局变量 port
	httpServer.bin(config.options.port)
	httpServer.start(3)
	tornado.ioloop.IOLoop.current().start()

日志信息

1、使用parse_command_line() 或 parse_config_file(path) 时 tornado会默认开启日志 loggong模块
2、关闭日志:tornado.options.options.options.logging = None

项目基础框架

"""
views(包) / index.py 中
"""
import tornado.web
form tornado.web import RequestHandler

class IndexHandler(tornado.web.RequestHandler):
	def get(self,*args,**kwargs):
		self.write("sunck is a good man")

"""
config.py 文件
"""  
import os
BASE_DIRS = os.path.dirname(__file__)
# 参数
options = {
	"port":9000
}
# 配置
settings = {
	"debug":True,
	"static_path":os.path.join(BASE_DIRS,"static")   # 设置静态文件目录
	"template_path" :os.path.join(BASE_DIRS,"templates")  # 设置模板文件目录
}

"""
application.py 路由
建立一个tornado.web.Application 子类
"""
import tornado.web
# 从views文件中引入index文件、index中写handler函数
from views import index
import config

class Application(tornado.web.Application):
	def __init__(self):
		handlers = [
		(r"/",IndexHandler)
		] 
		super(Application,self).__init__(handlers,**config.settings)
		
"""
server.py 主文件
"""
import tornado.web
import tornado.ioloop
import tornado.httpserver
import config
from application import Application
	
if__name__ == "__main__":
	app = Application()
	httpServer = tornado.httpserver.HTTPServer(app)  # 创建服务器
	httpServer.bind(config.options["port"])  # 将服务器绑定到指定的端口上
	httpServer.start(5)   # 启动五个进程,默认开启 1 个进程
	tornado.ioloop.Ioloop.current().start()

路由解析

# 1、普通字符串固定匹配
class Application(tornado.web.Application):
	def __init__(self):
		Handlers = [
			(r"/", index.MainHandler),     # 匹配根路径
			(r"/entry", index.EntryHandler),   # 匹配/entry
			(r"/entry/2015", index.Entry2015Handler),  # 匹配/entry/2015
		
			tornado.web.url(r"/",index.IndexHandler,{"world":"name"}, name = "index")   # 传参
			]   
			super(Application,self).__init__(handlers,**config.settings)
			
# 2、带参数的字符串路径,参数部分用()标识
# url handler
http://127.0.0.1:8000/entry/good/nice/handsome
http://127.0.0.1:8000/entry?a=1&b=2&c=3     # get 方式传递参数
RequestHandler.get_query_arguments(name)  # 获取get 方法传递参数

# get传参接收实例
class EntryHandler(RequestHandler)def get(self,*args,**kwargs):   # 默认参数
		a = self.get_query_argument("a")
		pass

Handlers = [
	(r"/entry"([^/+]), EntryHandler), ]
	(r'entry'/(\w+)/(\w+)\(\w+),EntryHandler)   # 用下面方式接收
	(r'entry'/(?P<p1>\w+)/(?P<p2>\w+)\(?P<p3>\w+),EntryHandler)     # p1、p2、p3 为名字
class EntryHandler(RequestHandler):
	def get(self,h1,h2,h3,*args,**kwargs)

# 3、带默认值的参数路径
Handlers = [(r"/entry"([^/+]), EntryHandler), ]
class EntryHandler(tornado.web.RequestHandler)def get(self,slug = 'default'):   # 默认参数
		pass
		
# 4、多参数路径
Handlers = [(r"/(\d{4}/\d{2}/\d{2}), DetailHandler), ]
class EntryHandler(tornado.web.RequestHandler)def get(self,year,month,day,slug):   # 默认参数
		pass
		
# 5、传递参数
Handlers = [
	(r"/entry", EntryHandler,{"word1":"good","word2":"nice"}),   # 传入参数
	]
class ProfileHandler(RequestHandler):
   # 接收参数 函数初始化,应该和 django 中的__init__ 类似,一般用于为函数赋予初始属性
	def initalize(self,database):     
		self.database = database 
	def get(self,*args,**kwargs):
		print(self.word1,self.word2)

# 6、静态匹配 / 例如百度主页  例如:baidu/index.html
# 放在所有路由的最下面  (StaticFileHandler) 在 /html中 根据名字进行查找,若找不到则用默认的html文件
Handlers = [
	(r"/(.*)$",tornado.web.StaticFileHandler,{"path":os.path.join(config.BASE_DIRS,"static/html"),"default_filename":"index.html"})
	]

前端自动转义

# tornado 默认是开启了自动转义的
# 关闭自动转义
1、raw    {% raw str% }     # str 是返回的模板原生代码 , raw只能关闭一行
2{{str}}  {% autoescape None %}  {{str}}	# 关闭当前文档的自定义转义
3、settings/    "autoescape" :None     # 在 settings 中进行设置,关闭项目自动转义
4、escape()   # 在关闭自动转义后,可以使用该方法对特定的变量进行转义

RequestHandler(接入点函数)

from tornad.web import RequestHandler
from tornad.web import Application

#  1、RequestHandler.initalize()  函数初始化,应该和 django 中的__init__ 类似,一般用于为函数赋予初始属性
class ProfileHandler(RequestHandler):   # 基类  RequestHandler  
	def initalize(self,database):     # **函数初始化  __init__  接收参数用**
		self.database = database 
		
#  2、调用请求处理(get、post等)方法之前的资源初始化处理
 RequestHandler.prepare()  #调用请求处理(get、post等)方法之前的资源初始化处理,预处理方法(判断用户权限是否满足需求)
 RequestHandler.on_finish()  # 清理对象占用内存或关闭数据库连接等操作
 
 RequestHandler.set_default_headers()
 RequestHandler.write_error()
 
lass ProfileHandler(RequestHandler):   # 基类  RequestHandler  
	def initalize(self,database):     # **函数初始化  __init__  接收参数用**
		self.database = database 
	
	def prepar(self):   	# 预处理方法,在执行对应请求方法前调用,任何HTTP请求都会调用prepar函数
		pass				# 判断用户是否符合规则,若不符合则直接返回错误

	def on_finish(self):	#  请求结束后,进行调用,可以资源的清理释放,或日志处理
		pass
 
#  3、HTTP Action 处理函数(请求方法)
RequestHandler.get(*args,**kwargs)
RequestHandler.post(*args,**kwargs)			
RequestHandler.head(*args,**kwargs)		# 类似get,响应没有具体内容,用户获取请求头
RequestHandler.delete(*args,**kwargs)	# 请求服务器删除指定资源
RequestHandler.patch(*args,**kwargs)	# 请求修改局部内容
RequestHandler.put(*args,**kwargs)		# 从客户端向服务器发送指定内容
RequestHandler.options(*args,**kwargs)	# 返回url支持的所有http方法

输入捕获(从请求中获取参数)

# get、post 方法都可以获取
RequestHandler.get_argument(name)  # 获取参数单体
RequestHandler.get_arguments(name)   # 获取参数的列表,有多个名字的参数

# get方法获取
RequestHandler.get_query_argument(name)   # 获取get方法的单体

class ErrorHandle(RequestHandler):
	def get(self,*args,**kwargs):
		flag = self.get_query_argument("flag")
		self.write("flag")

RequestHandler.get_query_arguments(name)   # 获取get方法的列表

#post方法获取参数
RequestHandler.get_body_argument(name)   # 获取post方法的单体
RequestHandler.get_body_arguments(name)   # 获取post方法的列表

# 根据cookie 名称获取cookie值
RequestHandler.get_cookie(name,default = None)

# 获取HTTP请求的一切信息
RequestHandler.request  # 返回 tornado.httputil.HTTPServerRequest

响应函数(请求处理完成后返回给客户端的)

RequestHandler.set_status(status_code,reason = None)  # 设置HTTP Response 中的返回码,描述状态码
RequestHandler.set_header(name,value)   # 键值对的方式设置HTTP Response中头参数,覆盖之前的Header
RequestHandler.add_header(name,value)   # 键值对的方式添加HTTP Response中头参数,不盖之前的Header
RequestHandler.set_default_header(self)  # 在HTTP响应处理前被调用,重写预先设置的headers
RequestHandler.write(chunk)   # 将给定的块chunk作为HTTP Body 发送给客户端
RequestHandler.finish(chunk = None)  # 通知Tornado Response的生成工作完成,chunk参数需要传递给客户端的HTTP body
RequestHandler.render(template_name,**kwargs)  # 用给定的参数渲染模板,参数可以传递到模板文件中(个人感觉是最常用的返回函数)
RequestHandler.redirect(url,permanent = False,status = None)  # 重定向
RequestHandler.send_error(500)   # 抛出异常,去执行 self.write_error(self,status_code,**kwargs)
RequestHandler.clear()  # 清空本次请求中的消息头、消息体
#设置cookie值
RequestHandler.set_cookie(name,value,domain = None,expires = None, path = "/",expires_day = None- name   # cookie 名
 	- value  # cookie值
 	- domain	# 提交cookie时匹配的域名
 	- path	# 提交cookie时匹配的路径
 	- expires # cookie 有效时间
 	- expires_day  # 设置有效时间天数
get_cookie("cookie","未登录")   # 获取cookie值
RequestHandler.clear_all_cookies(path="/",domain = None#清空本次请求的cookies值
clear_cookie(name,path = "/",domain =None)   # 删除名为name的cookie,并同时匹配domain和path的cookie

tornado.httputil.HTTPFile对象

# 作用:是接收到的文件对象
# 属性:
1、filename		# 文件的实际名字
2、body		# 文件的数据实体
3、content_type		# 文件的类型
import os
import config

def post(self,*args,**kwargs):
	filesDict = self.request.files
	for inputname in filesDict:
		fileArr = fileDict[inputname]
		for fileObj in fileArr:
			filePath = "服务器路径"
			with open (filePath,"wb") as f:
				f.write(fileObj.body)
				
	files.filename   # 文件名
	files.body	# 文件内容
	files.content_type	# 文件类型

模板部分

# 1、配置模板路径
# config.py
settings = {
	"static_path":os.path.join(BASE_DIRS,"static")   # 设置静态文件目录
	"template_path" :os.path.join(BASE_DIRS,"templates")  # 设置模板文件目录
	"autoescape":None   # 关闭项目字符转义 (一般不要关闭,不写即可)
}

# 2、渲染并返回给客户端
class HomeHandler(RequestHandler):
	def get(self,*args,**kwargs):
		temp = 100
		per = {}  # 多个参数

		# 传递函数
		def mySum(n1,n2):
			return n1+n2
		# 函数传递到模板中,模板中可以直接调用此函数
		self.render('home.html',mySum = mySum,num = temp, per = per) 
		self.write(per)   # 传输数据、可以直接将per数据转化成JSON格式

tornado与数据库的交互

"""
无自带的ORM,对数据库需要自己适配
且目前无有效的驱动

"""
# /config  数据库配置
mysql = {
	"host":"10.10.10.10",
	"user":"root",
	"passwd":"sunck",
	"dbName":"tset"
	}

# 路由配置数据库  application.py
# SunckMySQL 为封装好的 查询驱动
self.db=SunckMySQL(config.mysql["host"],config.mysql["user"],config.mysql["passwd"],config.mysql["dbMame"])
	
class StudentsHandler(RequestHandler):
	def get(self,*args,**kwargs):
		stus = self.application.db.get_all_obj("select * from students")
		self.render('students.html',stus = stus)

框架的异步化+协程化

实现方式1 : 回调函数实现异步
实现方式 2 : 协程的方式实现异步

回调函数实现异步 — 多线程

import time
import threading

# 耗时操作 —— handler 获取数据(数据库、其他服务、循环耗时)
# 步骤2 :longIo 接收回调函数(callback = finish)
def longIo(callback):
	# 步骤 3.2 : 回调函数在 run执行完毕后进行执行,所以将 其在传给 run
	def run(cb):
		print("开始执行耗时操作")
		time.sleep(5)
		print("耗时操作结束")
		# 耗时操作返回的数据无法直接返回给用户的调用函数,所以需要用到回调函数
		# return data
		cb ("sunck is good man")
	# 此处建一个线程 进行去操作耗时操作,通过线程将 callback函数传给 run 函数
	# 步骤 3.1
	threading.Thread(target=run,args = (callback,)).start()


# 回调函数,data 为耗时操作返回的数据
def finish(data):
	print("开始处理回调函数")
	print("接收到 longIo的响应数据":data)
	print("结束处理回调函数")


# 用户A的请求
def reqA():
	print("开始处理A的请求")
	# 步骤 1:
	# longIo为耗时操作,将需要执行的回调函数finish传给 longIo
	longIo(finish)
	print("结束处理A的请求")

# 用户B的请求
def reqB():
	print("开始处理B的请求")
	print("结束处理B的请求")

# 主函数
def main():
	reqA()
	reqB()
	whilt1:
		time.sleep(0.5)
		pass

if__name__=="__main__":
	main()

协程实现异步

# 版本 1:
"""
基本过程描述 :
1、创建 reqA 生成器、通过next 进行执行reqA函数
2、当执行到 yield 时,调用了 longIo 函数,并将此函数挂起
	2.1 在 reqA 中将通过 global gen 将 gen 定义为全局变量,以便 longIo 耗时 完成后调用进行返回
	2.2 耗时执行完成后,通过需要通过gen.send() 进行将数据返回给 reqA进行唤醒
3、挂起后,另一方面继续向下执行,执行reqB 函数
4、当挂起的 longIo  函数有返回时,继续向下执行 reqA 函数
"""
# 用户A的请求
# 将gen定义为全局
gen = None  

def reqA():
	print("开始处理A的请求")
	res = yield longIo()
	print("接收到 longIo的响应数据":res)
	print("结束处理A的请求")

# 用户B的请求
def reqB():
	print("开始处理B的请求")
	print("结束处理B的请求")

def longIo():
	def run(cb):
		print("开始执行耗时操作")
		time.sleep(5)
		try:
			global gen
			# 生成器gen.send 进行唤醒 reqA,将内容返回给reqA 函数的res接收, 但生成器目前在 longIo 函数中没有,所以需要定义为全局变量
			gen.send("sunck is a good man")
		except StopIteration as e:
			pass
		print("耗时操作结束")
	threading.Thread(target=run).start()
	
	
# 主函数
def main():
	# 创建reqA函数的生成器,通过next提取生成器中的值
	# 定义global gen  定义全部,覆盖前面的 gen = None
	global gen
	gen = reqA()
	next(gen)
	reqB()
	whilt1:
		time.sleep(0.5)
		pass
# 版本 2
"""
版本 1 中针对 reqA() 函数不能等同于普通的函数,需要将其协程一个生成器。为了使reqA等同于普通函数,所以产生版本 2,通过装饰器进行执行。
"""

# 手写生成器
def genCoroutine(func):
	def wrapper(*args,**kwargs):
		global gen
		gen = func(*args,**kwargs)
		next(gen)
	return wrapper


# 给A 函数增加生成器,在执行 A函数 前执行生成器
@genCoroutine
def reqA():
	print("开始处理A的请求")
	res = yield longIo()
	print("接收到 longIo的响应数据":res)
	print("结束处理A的请求")

# 用户B的请求
def reqB():
	print("开始处理B的请求")
	print("结束处理B的请求")
	
# 耗时操作
def longIo():
	def run(cb):
		print("开始执行耗时操作")
		time.sleep(5)
		try:
			global gen
			# 生成器gen.send 进行唤醒 reqA,将内容返回给reqA 函数的res接收, 但生成器目前在 longIo 函数中没有,所以需要定义为全局变量
			gen.send("sunck is a good man")
		except StopIteration as e:
			pass
		print("耗时操作结束")
	threading.Thread(target=run).start()


# 主函数
def main():
	reqA()
	reqB()
	whilt1:
		time.sleep(0.5)
		pass
# 版本 3:
"""
版本 2 中 还存在一个一个全局变量 gen,所以需要解决变量的问题,并且 longIo 中还写了一个线程,所以产生了版本3 对这两处进行了改进
"""
# 手写生成器 —— 终极版本 以后不用写 、genCoroutine已经做了封装,直接调用即可
def genCoroutine(func):
	def wrapper(*args,**kwargs):
		gen1 = func()   # reqA的生成器
		gen2 = next(gen1)    # longIo的生成器
		def run(g):
			res = next(g)
			try:
				gen1.send(res)  # 返回给 reqA数据
			except StopIteration as e:
			pass
		threading.Thread(target = run,args =(gen2,)).start()
	return wrapper


# 给A 函数增加生成器,在执行 A函数 前执行生成器
@genCoroutine
def reqA():
	print("开始处理A的请求")
	res = yield longIo()
	print("接收到 longIo的响应数据":res)
	print("结束处理A的请求")

# 用户B的请求
def reqB():
	print("开始处理B的请求")
	print("结束处理B的请求")
	
# 耗时操作
def longIo():
	print("开始执行耗时操作")
	time.sleep(5)
	print("耗时操作结束")
	# 返回数据
	yield "sunck is a good man"


# 主函数
def main():
	reqA()
	reqB()
	whilt1:
		time.sleep(0.5)
		pass

handler客户端实例化—回调函数实现异步 — 装饰器

#	框架的异步化+协程化
#	1、异步化:针对RequestHandler   使用  @tornado.web.asynchronous 修饰器,长连接保持 + 将同步机制更改为异步机制(callback)。
#	2、协程化:针对RequestHandler   使用  @tornado.gen.coroutine 修饰器,将同步机制更改为协程异步机制
import tornado.ioloop
import tornado.web
import tornado.httpclient

class MainHandler(tornado.web.RequestHandler):
	# 长连接、保持装饰器 + 异步机制装饰器
    @tornado.web.asynchronous
    def get(self):
    	# 将 handler 异步请求客户端实例化
        http = tornado.httpclient.AsyncHTTPClient()
        http.fetch("http://www.baidu.com",
                   callback=self.on_response)

    def on_response(self, response):
        if response.error: raise tornado.web.HTTPError(500)
        self.write(response.body)
        self.finish()


def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

def main():
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()

handler客户端实例化 — 协程实现异步 — 装饰器

#	框架的异步化+协程化
#	1、异步化:针对RequestHandler   使用  @tornado.web.asynchronous 修饰器,将同步机制更改为异步机制(callback)。
#	2、协程化:针对RequestHandler   使用  @tornado.gen.coroutine 修饰器,将同步机制更改为协程异步机制。
"""
tornado.httpclient.AsyncHTTPClient —— tornado 提供的异步web请求客户端,用来进行异步 web 请求
fetch(request,callback = None) —— 用于执行 web 请求,并异步响应返回一个tornado.httpclient.Httpclient.HttpResponse
 - request 可以是 一个 URL 也可以是一个tornado.httpclient.HTTPRequest对象

**tornado.httpclient.HTTPRequest对象**  HTTPRequest
1、http请求类,该类的构造函数可以接收参数
	(1)、url —— 字符串,要访问的网址,必传
	(2)、method —— 字符串类型 ,http 请求方法
	(3)、headers —— 字典或HTTPHeaders 、附加协议头
	(4)、body —— http 请求体
	
**tornado.httpclient.Httpclient.HttpResponse**   HttpResponse
1、http响应的类
2、属性 
	(1)、code —— 状态码
	(2)、reason —— 状态码描述
	(3)、body —— 响应数据
	(4)、error —— 异常
"""

import tornado.ioloop
import tornado.web
import tornado.httpclient
from tornado.httpclient import AsyncHTTPClient

class MainHandler(tornado.web.RequestHandler):
	# 协程异步装饰器 (生成器 + 保持长连接)
    @tornado.gen.coroutine
    def get(self):
    	# 创建异步请求客户端
        http = tornado.httpclient.AsyncHTTPClient()
        # fetch 向 url发送请求
        response = yield http.fetch("http://www.baidu.com")
        # 若此处不用 协程 还可以用异步函数进行处理   http.fetch("http://www.baidu.com",self.on_response)  
        # on_response 为回调函数,用于处理 返回的数据,只要在写一个 on_response 函数即可处理。
        self.write(response.body)


def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

def main():
    app = make_app()
    app.listen(8888)
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()

#  异步: http.fetch("www.baidu.com", callback = self.on_response)
#  协程:response = yield http.fetch("www.badu.com")
					    self.write(response.body)

handler作为客户端 — 回调异步 - 通信信道保持及关闭

# handler 同步客户端 HTTPClient
from tornado.httpclient import HTTPClient 
def synchronous_visit():
	http_client = HTTPClient()
	response = http_client.fetch("www.baidu.com")    # 访问百度,有返回界面后才会继续执行下面的
	print response.body

# handler 异步客户端 AsycHTTPClient
from tornado.httpclient import AsycHTTPClient 

def handle_respinse(response):
	print response.body
	self.finish()  # 函数完成后关闭通信通道

@tornado.web.asynchronous	# 不关闭通信的通道,为回调函数提供数据通道
def asynchronous_visit():
	http_client = AsycHTTPClient()
	# 将请求返回的数据 交给 handle_reponse 函数进行处理
	http_client.fetch("www.baidu.com",callback = handle_reponse)    # 访问百度后立刻返回,百度有反馈后asynchronous_visit会调用handle_response接收

# 本人理解是将原来的函数拆分成两个部分,一个部分取等待函数的响应,一分部返回,所以原函数可以继续使用

handler 作为客户端请求协程异步

class Students2Handler(RequestHandler):

	@tornado.gen.coroutine   # 协程异步装饰器
	def get(self,*args,**kwargs):
		url = "baidu.com.cn...."
		# 创建异步客户端
		client = AsycHTTPClient()
		res = yield client.fetch(url)
		if res.error:
			self.send_error(500)
		else:
			data = json.loads(res.body)
			self.write(data)

handler 作为客户端请求协程异步 - web请求独立

class Students3Handler(RequestHandler):
	@tornado.gen.coroutine   # 协程异步装饰器
	def get(self,*args,**kwargs):
		res = yield self.getData()
		self.write(data)
	
	@tornado.gen.coroutine
	def getData(self):
		url = "baidu.com.cn...."
		# 创建异步客户端
		client = AsycHTTPClient()
		res = yield client.fetch(url)
		if res.error:
			ret = {"ret":0}
		else:
			data = json.loads(res.body)
		raise tornado.gen.Return(ret)

协程函数的调用

"""
方法1:在本身协程的函数内通过yield关键字调用 (可以看上面的例子)
方法2:在IOLoop尚未启动时,通过IOLoop的 run_sync()函数调用
方法3:在IOLoop已经启动时,通过IOLoop的 spawn_callback()函数调用
"""
# **方法1:通过yield关键字调用**
# 因为两个函数都是协程函数,所以可以通过yield进行相互调用
from tornado import gen   # 引入协程库 gen
@gen.coroutine   # 协程声明
def outer_corouterine():      #协程函数一
	print("第一行")
	yield coroutine_visit()   #协程函数二
	print("第二行")



# **方法2:IOLoop开启,spawn_callback())函数调用**
from tornado.ioloop import IOLoop
def func_normal():
	print("第一行")
	IOLoop.current().run_sync(lambda:coroutine_visit())   #调用协程函数 coroutine_visit()
	print("第二行")



# **方法3:IOLoop未开启,run_sync()函数调用**	
#开启状态
from tornado.ioloop import IOLoop
def func_normal():
	print("第一行")
	IOLoop.current().spawn_callback(coroutine_visit)   #调用协程函数 coroutine_visit()
	print("第二行")
# spawn_callback()   只能调用没有返回值的协程函数

协程中利用阻塞函数(利用线程池)

from concurrent.futures import ThreadPOOLExeutor  #  引入线程池
thead_pool = ThreadPOOLExeutor(2)   # 线程池中含两个线程
@gen.coroutine   # 协程声明
def call_blocking():
print("第一行")
yield thead_pool.submit( mysleep, 10)  # mysleep  是被挂起的函数名,后面的是10  是函数中所需的参数
print("第二行")

协程中等待多个异步调用

# 通过yield 关键字 来等待多个异步调用,这些调用只要通过list  或字典的方式传给yield即可
from tornado import gen   # 引入协程库 gen
from tornado.httpclient import AsycHTTPClient 

@gen.coroutine   # 协程声明
def coroutine_visit():      #协程函数一
	http_client = AsycHTTPClient()
	list_response = yield [http_client.fetch("www.baidu.com"),    # 多个协程访问,返回后打印 response.body
						http_client.fetch("www.163.com"),
						http_client.fetch("www.xinlang.com"),
						http_client.fetch("www.tengxun.com"),]
	for response in list_response:  
		print response.body
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值