Tornado学习笔记
web应用部署时,采用wsgi协议与服务器对接,这类通常是基于多线程的,也就是说每一个请求都会有一个线程来处理。这种不适用于以下两种场景
场景一:用户量大、高并发(双十一、抢火车票)
场景二:大量的HTTP持久连接,长期占用服务器资源,容易过负荷。
C10K问题
单台服务器无法处理10w+以上并发,而采用多台又会增加成本,tornado旨在解决该问题,它是一个高性能的解决方案(服务器与框架的集合体)
tornado是一个轻量级的web框架,拥有异步非阻塞的处理方式
Tornado和Django比较
tornado.ioloop
tornado充分利用linux的epoll工具和BSD的kqueue工具,是Tornado不依赖多进程/多线程而达到高性能的原因
epoll去管理socket(相当于socket的容器),应用程序IOloop
向epoll发送请求,所以要不断循环(对应ioloop)询问epoll
每次循环请求epoll时,哪个socket有数据就对哪个处理,不需要分配资源监听不必要的socket;
tornado单线程循环(当完成一个socket的响应时,才向下执行下一个),当执行的方法中有耗时较长的程序时,就会发生阻塞,程序就会卡死;这时候就用到异步
传入参数
url拼接,获取请求头参数(get请求)
get_query_argument(name, default=DEFAULT, strip=True)
# strip 是否删除左右空白符
get_query_arguments(name, strip=True) # 传入多个参数,返回List
获取请求体参数(post请求)
get_body_argument(name, default=DEFAULT, strip=True)
get_body_arguments(name, strip=True)
说明
传入json数据
json_data = self.request.body # 获取json数据
dict_data = json.loads(json_data)
上传文件
img_data = self.request.files["key"]
self.write() # 将返回的人数据写到缓冲区中,等到方法执行完毕后,一起返回,所以会执行所有的self.write方法
self.finish() # 把缓冲区的内容写到socket中,结束本次请求
self.set_header(name,value) # 设置返回头
self.status(status_code,reason=None) # 设置状态码
self.redirect(url) # 跳转
self.send_error(status_code) #传递给write_error方法,返回浏览器错误页面,调用完send_error会自动调用finish,代码后再调用write会报错
python在进行字符串验证拼接时,默认会以ascii
编码方式转换为unicode
,但是ascii
又不能编码中文,所以会报错
json格式数据实现不同语言之间的数据传输
RequestHandler的方法,和post,get方法同级
prepare # 访问该接口的任何http请求都会执行该方法,做预处理
on_finish # 请求结束,数据返回客户端后再执行一些清理操作
set_default_headers # 设置header头
write_error # 自定义错误页面
安全应用
1、cookie,存储在浏览器的键值对
self.set_cookie()
或者
self.set_header()
浏览器根据响应头中的set-cookie
字段在本地设置
cookie存储在浏览器端很容易被篡改,为了防止恶意篡改,需要给cookie配置一个随机字符串作为密钥
设置xsrf_cookie
2、用户认证
@tornado.web.authenticated
def get(self):
pass
认证装饰器调用get_current_user()
方法,可以在该方法中自定义完成方法的认证逻辑
如果认证失败,跳转到登陆页,登录页的url需要自定义
如果多个线程之间是相互独立的,那多线程就可以称为异步
异步也是同时进行,那异步是否要求两个操作间互相独立?
使用yield
关键字让函数变成一个生成器,调用该函数时,就是创建了一个生成器;
yield异步,再函数中开启一个新的线程,新的线程和主线程相互不影响,完成异步
tornado异步
tornado利用epoll实现异步,程序的挂起与唤醒始终在一个线程上,由tornado自己来调度,属于真正意义的协程
ioloop是跟epoll交互的接口
epoll是轮询socket,并询问socket状态,分配任务
把耗时长的handler通过yield交给ioloop,然后主程序去继续遍历socket
epoll主要是解决网络IO的并发问题,所以Tornado的异步编程也主要体现在网络IO的异步上,即异步web请求,
tornado提供了一个异步请求客户端
tornado.httpclient.AsyncHTTPClient
装饰器
# 回调的方式实现异步
@tornado.web.asynchronous #get执行完后不要关闭通道,等待耗时执行的结果,执行回调函数
def get(self):
client = AsyncHTTPClient()
client.fetch("http://www.baidu.com",callback=self.on_response)
def on_response(self, resp):
data = json(resp.body)
self.write(data.get("city",""))
self.finish()
# 同步的方式实现异步
@tornado.gen.coroutine
def get(self):
client = AsyncHTTPClient()
resp = yield client.fetch("http://www.baidu.com")
data = json(resp.body)
self.write(data.get("city",""))
self.finish()
对一次访问请求并不会提升速度,但是会提升多个人访问时候的并发能力
一个函数中出现出现了yield就不允许用return
返回数据,tornado封装了用于在生成器中返回值的特殊异常
raise tornado.gen.Return(rep) # 异步返回数据
异步web请求
tornado提供了异步请求web客户端tornado.httpclient.AsyncHTTPClient
fetch(request,callback=None)
协程异步
经常使用的异步操作封装成函数
websocket
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端直接向客户端推送数据而不需要客户端进行请求,两者之间可以创建持久性的连接,并允许数据进行双向传递
模块tornado.websocket
,其中提供了一个WebSocketHandler
类来处理通讯
websocket建立连接也是被动的,等待客户端发送请求;但是可以主动向客户端发送消息和关闭连接
JS与WebSocket通讯
聊天室demo
部署Tornado
管理多进程
tornado配置文件