Tornado
一、Tornado初探

import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
# self.write("Hello, world")
self.render('index.html')
class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.render('login.html')
def post(self, *args, **kwargs):
username = self.get_argument('username')
print(username)
self.redirect('/index')
settings = {
'template_path':'templates',
'static_path':'statics',
'static_url_prefix':'static',
}
#application对象中封装了 路由信息,配置信息
application = tornado.web.Application([
(r"/index", MainHandler),
(r'/login.html',LoginHandler),
],**settings)
# application.add_handlers(r"^a\.com$",[
# (r"/", MainHandler),
# (r'/login.html',LoginHandler),
# ])
if __name__ == "__main__":
#创建socket对象 [socket,]
#socket = socket.socket
application.listen(8888)
#开启r,w,e = select.select([socket,],)
tornado.ioloop.IOLoop.instance().start()
二、Tornado原理

1.基本操作 -路由系统(用户将请求发送给引擎,通过路由系统发送给视图函数) url - 类(根据method执行方法) -视图函数(由视图函数渲染模板返回用户) -控制器
class Foo(xx):
def get(self):
self.write()
self.render()
self.redirect()
self.get_argument()
self.get_cookies()
self.set_cookies()
self.get_body_argument() post方式
self.get_query_argument() get方式
self.get_argument() get或post方式
self.get_arguments()
self.get_cookie()
self.set_cookie()
self.get_secure_cookie('xxxx')
self.set_secure_cookie('xxxx','oooo')
PS:加密cookie依赖配置文件cookie_secret
self.request.files['filename']
self._headers
查找请求数据:1、Handler对象
2、self.request -> tornado.httputil.HTTPServerRequest
def post(self):
pass
-模板引擎(更接近python)
-基本
{{li[0]}}
{% for i in range(10) %}
{% end %}
-UIMethod
-内容
-UIModule
-css,js
-内容
2.自定义开源组件
-session
(1).super按照顺序查找
(2).类名.方法名(self)
class Bar(object):
def __init__(self):
pass
def __setitem__(self, key, value):
pass
def __getitem__(self, item):
pass
def __delitem__(self, key):
pass
(3)self是谁?永远是调用方法的对象
-Form表单验证(*)
# -*- coding: utf-8 -*-
"""
@Datetime: 2018/8/28
@Author: Zhang Yafei
"""
import tornado.web
import tornado.ioloop
import time
import hashlib
container = {}
class Cache(object):
"""将session保存在内存"""
def __contains__(self, item):
return item in container
def initial(self,random_str):
container[random_str] = {}
def get(self,random_str,key):
return container[random_str].get(key)
def set(self, random_str,key,value):
container[random_str][key] = value
print(container)
def delete(self, random_str,key):
del container[random_str][key]
def clear(self,random_str):
del container[random_str]
def open(self):
pass
def close(self):
pass
P = Cache
class Bar(object):
def __init__(self,handler):
self.handler = handler
self.random_str = None
self.db = P()
self.db.open()
#去用户请求信息中获取session_id,如果没有,新用户
client_random_str = self.handler.get_cookie('session_id')
if not client_random_str:
"""新用户"""
self.random_str = self.create_random_str()
self.db.initial(self.random_str)
else:
if client_random_str in self.db:
"""老用户"""
self.random_str = client_random_str
else:
"""非法用户"""
self.random_str = self.create_random_str()
self.db.initial(self.random_str)
#更新cookie过期时间
self.handler.set_cookie('session_id', self.random_str, expires=time.time()+1800)
self.db.close()
def create_random_str(self):
v = str(time.time())
m = hashlib.md5()
m.update(v.encode('utf-8'))
return m.hexdigest()
def __setitem__(self, key, value):
self.db.open()
self.db.set(self.random_str, key, value)
self.db.close()
"""
# 1.生成随机字符串
if self.random_str:
pass
else:
self.random_str = self.create_random_str()
# 2.写入用户cookies(只写一次)
self.handler.set_cookie('seesion_id',self.random_str)
# 3.后台存储
if self.random_str in container:
container[self.random_str][key] = value
else:
container[self.random_str]={}
container[self.random_str][key] = value
"""
def __getitem__(self, key):
self.db.open()
v = self.db.get(self.random_str, key)
self.db.close()
return v
def __delitem__(self, key):
self.db.open()
self.db.delete(self.random_str,key)
self.db.close()
def clear(self):
self.db.open()
self.db.clear(self.random_str)
self.db.close()
class Foo(object):
def initialize(self):
#self是MainHandler对象
self.session = Bar(self)
# super(Foo, self).initialize()
"""python支持多继承"""
class HomeHandler(Foo,tornado.web.RequestHandler):
def get(self):
user = self.session['uuuuu']
if not user:
self.redirect('http://www.oldboyedu.com')
else:
self.write(user)
class LoginHandler(Foo,tornado.web.RequestHandler):
def get(self):
self.session['uuuuu'] = 'root'
self.redirect('/home')
"""
# self.set_cookie()
#1.生成随机字符串
#2.写入用户cookies
#3.后台存储
self.session['is_login'] = True #__setitem__
self.session['user'] = 'zhangyafei' #__setitem__
# self.session['xx'] #__getitem__
# del self.session['xx'] #__delitem__
self.write('hello world')
"""
application = tornado.web.Application([
(r'/login', LoginHandler),
(r'/home',HomeHandler),
])
if __name__ == '__main__':
application.listen(9999)
tornado.ioloop.IOLoop.instance().start()
三、websocket
概述
--http,socket实现,短连接,单工,请求响应
--WebSocket,socket实现,双工通道,,请求响应,推送 魔法字符串
websocket原理
-服务端(socket服务器)
1.服务器开启socket,监听ip和端口
3.允许连接
* 5.服务端收到特殊值【特殊值加密sha1,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】
* 6.加密后的值发送给客户端
-客户端(浏览器)
2.客户端发起连接请求(ip和端口)
* 4.客户端生成一个随机字符串xxx,【特殊值加密sha1,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】,向服务端发送一段特殊值
* 7.客户端收到加密的值
"""
1.位运算,右移动
10010001
右4
00001001
左4
100100010000
2.异或运算
1,1:1
0,1 :0
0,0 :0
查看某个数的后四位
10001010
00001111
00001010
info = b'\x81\x8b\xc9\x11\x81b\xa1t\xed\x0e\xa61\xf6\r\xbb}\xe5'
opcode = info[0] & 15 获取第一个字节的后四位
fin = info[0] >> 7
payload_len = info[1] & 127
if payload_len<126:
头部占2个字节
elif payload_len == 126:
头部占4个字节
else:
头部占10个字节
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+------------------------------------------------------------
"""
四、异步非阻塞web框架
同步阻塞
# -*- coding: utf-8 -*-
"""
@Datetime: 2018/8/29
@Author: Zhang Yafei
"""
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
import time
time.sleep(5)
self.write("Hello, world")
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/main", MainHandler),
(r"/index", IndexHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
异步非阻塞
# -*- coding: utf-8 -*-
"""
@Datetime: 2018/8/29
@Author: Zhang Yafei
"""
import time
import tornado.ioloop
import tornado.web
from tornado import gen
from tornado.concurrent import Future
class MainHandler(tornado.web.RequestHandler):
@gen.coroutine
def get(self):
future = Future()
#特殊的形式等待5秒
tornado.ioloop.IOLoop.current().add_timeout(time.time()+5,self.doing)
yield future
def doing(self,*args,**kwargs):
self.write('Main')
self.finish()
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/main", MainHandler),
(r"/index", IndexHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
自定义异步非阻塞框架支持异步非阻塞web框架 -Tornado,Nodejs:一个线程处理多个请求(服务端)
异步IO模块(socket时做的):一个线程发送多个请求(客户端)
异步IO模块:我们作为客户端向服务端发起并发请求,select监听socket是否已经发生变化 futrue对象:
future = Future()
三种请求:超时,发起请求,设置值释放挂起请求
1.挂起当前请求,线程可以处理其他请求 *****
2.future设置值,当前挂起的请求返回
自定义web框架:select + socket
--同步
--异步:通过future对象,如果future对象为None,则挂起,如果有值的话则断开连接
案例:web聊天室
# -*- coding: utf-8 -*-
"""
@Datetime: 2018/8/28
@Author: Zhang Yafei
"""
import json
import uuid
import tornado.web
import tornado.ioloop
import tornado.websocket
class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('index.html')
class ChatHandler(tornado.websocket.WebSocketHandler):
users = set()
messages = []
def open(self, *args, **kwargs):
"""
客户端和服务器已经建立连接
1.连接
2.握手
:param args:
:param kwargs:
:return:
"""
ChatHandler.users.add(self)
# uid = str(uuid.uuid4())
# self.write_message(uid)
# for msg in ChatHandler.messages:
# content = self.render_string('message.html', **msg)
# self.write_message(content)
def on_message(self, message):
msg = json.loads(message)
ChatHandler.messages.append(message)
for client in ChatHandler.users:
content = self.render_string('message.html',**msg)
client.write_message(content)
def on_close(self):
"""
客户端主动关闭连接
:return:
"""
ChatHandler.users.remove(self)
def run():
settings = {
'template_path': 'templates',
'static_path': 'static',
}
application = tornado.web.Application([
(r"/", IndexHandler),
(r"/chat", ChatHandler),
], **settings)
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
run()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{
background-color: black;
}
.container{
border:2px solid #dddddd;
height: 400px;
overflow: auto;
}
</style>
</head>
<body>
<div style="width: 750px;margin: 0 auto;">>
<h1 style="">>1024聊天室</h1>
<div class="container"></div>
<div class="input">
<input class="name" style="width: 50px;height: 15px;" type="text" value="游客">
<input type="text" id="txt">
<input type="button" id="btn" value="发送" onclick="sendMessage()">
<input type="button" id="close" value="关闭连接" onclick="closeConn()"/>
</div>
<div id="content"></div>
</div>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$(function () {
wsUpdater.start();
});
var wsUpdater = {
socket: null,
name: null,
start: function() {
var url = "ws://127.0.0.1:8888/chat";
wsUpdater.socket = new WebSocket(url);
wsUpdater.socket.onopen = function () {
/* 与服务器端连接成功后,自动执行 */
var newTag = document.createElement('div');
newTag.innerHTML = "【连接成功】";
document.getElementById('content').appendChild(newTag);
};
wsUpdater.socket.onmessage = function(event) {
console.log(event);
if(wsUpdater.name){
wsUpdater.showMessage(event.data);
}else{
wsUpdater.name = event.data;
}
}
},
showMessage: function(content) {
$('.container').append(content);
}
};
function closeConn() {
/* 服务器端主动断开连接时,自动执行 */
if (confirm("您确定要关闭本页吗?")){
window.opener=null;
window.open('','_self');
window.close();
}
else{}
};
$("#txt").keydown(function (e) {//当按下按键时
if (e.which == 13) {//.which属性判断按下的是哪个键,回车键的键位序号为13
$('#btn').trigger("click
