Tornado 晋级1
一、自定制Web组件
Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作...
session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。
import tornado.ioloop import tornado.web from controllers.account import LoginHandler from controllers.home import HomeHandler import time import hashlib class Cache(object): """ 将session保存在内存 """ def __init__(self): self.container = {} def __contains__(self, item): return item in self.container def initial(self,random_str): self.container[random_str] = {} def get(self,random_str,key): return self.container[random_str].get(key) def set(self,random_str,key,value): self.container[random_str][key] = value def delete(self,random_str,key): del self.container[random_str][key] def open(self): pass def close(self): pass def clear(self,random_str): del self.container[random_str] class Memcache(object): def __init__(self): pass def get(self,key): pass def set(self,key,value): pass def delete(self,key): pass def open(self): pass def close(self): pass P = Cache class Session(object): def __init__(self,handler): self.handler = handler self.random_str = None self.ppp = P() self.ppp.open() # 去用户请求信息中获取session_id,如果没有,新用户 client_random_str = self.handler.get_cookie('session_id') if not client_random_str: "新用户" self.random_str = self.create_random_str() container[self.random_str] = {} else: if client_random_str in self.ppp: "老用户" self.random_str = client_random_str else: "非法用户" self.random_str = self.create_random_str() self.ppp.initial(self.random_str) ctime = time.time() self.handler.set_cookie('session_id',self.random_str,expires=ctime+1800) self.ppp.close() def create_random_str(self): v = str(time.time()) m = hashlib.md5() m.update(bytes(v,encoding='utf-8')) return m.hexdigest() def __setitem__(self, key, value): self.ppp.open() self.ppp.set(self.random_str,key,value) self.ppp.close() def __getitem__(self, key): self.ppp.open() v = self.ppp.get(self.random_str,key) self.ppp.close() return v def __delitem__(self, key): self.ppp.open() self.ppp.delete(self.random_str,key) self.ppp.close() def clear(self): self.ppp.open() self.ppp.clear(self.random_str) self.ppp.close() class Foo(object): def initialize(self): # self是MainHandler对象 self.session = Session(self) super(Foo,self).initialize() 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') class TestHandler(tornado.web.RequestHandler): def get(self): self.set_cookie('k1', 'vvv', expires=time.time()+20) class ShowHandler(tornado.web.RequestHandler): def get(self): self.write(self.get_cookie('k1')) application = tornado.web.Application([ (r"/login", LoginHandler), (r"/home", HomeHandler), (r"/test", TestHandler), (r"/show", ShowHandler), ]) if __name__ == "__main__": application.listen(9999) tornado.ioloop.IOLoop.instance().start() 自定义session
二、异步非阻塞
1.首先看一下同步阻塞情况
import socket import select class HttpRequest(object): """ 用户请求封装 """ def __init__(self, content): """ 用户发送的请求数据:请求头和请求体 :param coutent: """ self.content = content self.header_bytes = bytes() self.body_bytes = bytes() self.header_dict = {} self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b @property def header_str(self): """转换格式""" return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v def main(request): import time time.sleep(10) return 'main' def index(request): return "indexasdfasdfasdf" routers = [ ('/main/', main), ('/index/', index), ] def run(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("127.0.0.1", 9998,)) sock.setblocking(False) sock.listen(128) inputs = [] inputs.append(sock) while True: rlist, wlist, elist = select.select(inputs, [], [], 1.5) # print("rlist***********************************8") # print(rlist) # print("wlist***********************************8") # print(wlist) # print("elist***********************************8") # print(elist) for r in rlist: if r == sock: """心情求到来""" print(sock,'<------------------------------------') conn, addr = sock.accept() conn.setblocking(False) inputs.append(conn) else: """客户端发过来的数据""" data=b'' while True: """循环接收""" try: chunk = r.recv(1024) data = data + chunk except Exception as e: chunk = None if not chunk: break request = HttpRequest(data) import re flag = False func = None for route in routers: if re.match(route[0], request.url): flag=True # func就是函数名 func =route[1] break if flag: result = func(request) # r socket对象 r.sendall(bytes(result,encoding='utf-8')) else: r.sendall(b"404") inputs.remove(r) r.close() if __name__ == '__main__': run() # 叙述: # websocket同步io ''' 1.利用socket select实现 2.把路由放到列表中以组的形式(url,def), 3.创建socket对象设置病创建一个inputs列表 4.常见select对象循环监听 1.如果有对象连接请求rlist 有活动 2.conn 连接对象放入inputs列表中 3.接收msg 4.将数据进行分离 头 体 5.通过 循环路由列表 正在匹配msg分离出的url,找到给他个Flag 6.进行运行 7.完毕后讲列表的conn对象删除 8.关闭conn '''
2、装饰器 + Future 从而实现Tornado的异步非阻塞
装饰器 + Future 从而实现Tornado的异步非阻塞
class AsyncHandler(tornado.web.RequestHandler):
 
    @gen.coroutine
    def get(self):
        future = Future()
        future.add_done_callback(self.doing)
        yield future
        # 或
        # tornado.ioloop.IOLoop.current().add_future(future,self.doing)
        # yield future
 
    def doing(self,*args, **kwargs):
        self.write('async')
        self.finish()
当发送GET请求时,由于方法被@gen.coroutine装饰且yield 一个 Future对象,那么Tornado会等待,等待用户向future对象中放置数据或者发送信号,如果获取到数据或信号之后,就开始执行doing方法。
异步非阻塞体现在当在Tornaod等待用户向future对象中放置数据时,还可以处理其他请求。
注意:在等待用户向future对象中放置数据或信号时,此连接是不断开的。
自定制web非阻塞框架
import socket import select class HttpRequest(object): """ 用户封装用户请求信息 """ def __init__(self, content): """ :param content:用户发送的请求数据:请求头和请求体 """ self.content = content self.header_bytes = bytes() self.body_bytes = bytes() self.header_dict = {} self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): '''头体分离''' temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): '''具体分割头部各个参数''' headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v class Future(object): def __init__(self): self.result = None F = None def main(request): global F F = Future() return F def stop(reqeust): global F F.result = b"xxxxxxxxxxxxx" return "stop" def index(request): return "indexasdfasdfasdf" routers = [ ('/main/', main), ('/index/', index), ('/stop/', stop), ] def run(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("127.0.0.1", 9999,)) sock.setblocking(False) sock.listen(128) inputs = [] inputs.append(sock) async_request_dict = { # 'socket': futrue } while True: rlist, wlist, elist = select.select(inputs, [], [], 0.05) for r in rlist: if r == sock: """新请求到来""" conn, addr = sock.accept() conn.setblocking(False) inputs.append(conn) else: """客户端发来数据""" data = b"" while True: try: chunk = r.recv(1024) data = data + chunk except Exception as e: chunk = None if not chunk: break # data进行处理:请求头和请求体 request = HttpRequest(data) # 1. 请求头中获取url # 2. 去路由中匹配,获取指定的函数 # 3. 执行函数,获取返回值 # 4. 将返回值 r.sendall(b'alskdjalksdjf;asfd') import re flag = False func = None for route in routers: if re.match(route[0], request.url): flag = True func = route[1] break if flag: result = func(request) if isinstance(result, Future): async_request_dict[r] = result else: r.sendall(bytes(result, encoding='utf-8')) inputs.remove(r) r.close() else: r.sendall(b"404") inputs.remove(r) r.close() try: for conn in async_request_dict.keys(): future = async_request_dict[conn] if future.result: conn.sendall(future.result) conn.close() del async_request_dict[conn] inputs.remove(conn) except RuntimeError as e : pass if __name__ == '__main__': run() ''' 阐述: 使用Future实现异步 1.创建socket对象 并创建一个inputs列表 用来存放连接对象 并创建一个字典 用来存放 任务 及其返回值 2.建立select对象进行监听 如果rlist 出现连接请求 接收请求 吧conn放到inputs列表中 3.接受数据,处理数据 4,通过路由列表 找到该函数执行 5.如果返回是字符串,直接给客户端发送消息 ,移除conn在inputs中 关闭 6.如果反悔的是函数,则把conn 和 句柄放到函数 一起放到字典async_request_dict 7找不到该函数则 返回404 5,循环async_request_dict字典的keys,如result有返回值,则发送 关闭移除 '''
升级版
import socket import select import time class HttpRequest(object): """ 用户封装用户请求信息 """ def __init__(self, content): """ :param content:用户发送的请求数据:请求头和请求体 """ self.content = content self.header_bytes = bytes() self.body_bytes = bytes() self.header_dict = {} self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v # 自定制Future class Future(object): def __init__(self, timeout=0): self.result = None self.timeout = timeout self.start = time.time() def main(request): f=Future(5) return f def index(request): return 'xdfasdfkl;ajsdk;lfajsdlk;' routers = [ ('/main/',main), ('/index/',index), ] def run(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("127.0.0.1", 9999,)) sock.setblocking(False) sock.listen(128) inputs = [] inputs.append(sock) async_request_dict = { # 'socket': futrue } while True: rlist, wlist, elist = select.select(inputs, [], [], 0.05) for r in rlist: if r == sock: """新请求到来""" conn, addr = sock.accept() conn.setblocking(False) inputs.append(conn) else: """客户端发来数据""" data = b"" while True: try: chunk = r.recv(1024) data = data + chunk except Exception as e: chunk = None if not chunk: break # data进行处理:请求头和请求体 request = HttpRequest(data) # 1. 请求头中获取url # 2. 去路由中匹配,获取指定的函数 # 3. 执行函数,获取返回值 # 4. 将返回值 r.sendall(b'alskdjalksdjf;asfd') import re flag = False func = None for route in routers: if re.match(route[0], request.url): flag = True func = route[1] break if flag: result = func(request) if isinstance(result, Future): async_request_dict[r] = result else: r.sendall(bytes(result, encoding='utf-8')) inputs.remove(r) r.close() else: r.sendall(b"404") inputs.remove(r) r.close() for conn in async_request_dict.keys(): future = async_request_dict[conn] start = future.start timeout = future.timeout ctime = time.time() if (start + timeout) <= ctime: future.result = b"timeout" if future.result: conn.sendall(future.result) conn.close() del async_request_dict[conn] inputs.remove(conn) if __name__ == '__main__': run()
3、httpclient类库
Tornado提供了httpclient类库用于发送Http请求,其配合Tornado的异步非阻塞使用。
class AsyncHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        from tornado import httpclient
 
        http = httpclient.AsyncHTTPClient()
        yield http.fetch("http://www.google.com", self.endding)
 
 
    def endding(self, response):
        print(len(response.body))
        self.write('ok')
        self.finish()
import socket import select import time class HttpRequest(object): """ 用户封装用户请求信息 """ def __init__(self, content): """ :param content:用户发送的请求数据:请求头和请求体 """ self.content = content self.header_bytes = bytes() self.body_bytes = bytes() self.header_dict = {} self.method = "" self.url = "" self.protocol = "" self.initialize() self.initialize_headers() def initialize(self): temp = self.content.split(b'\r\n\r\n', 1) if len(temp) == 1: self.header_bytes += temp else: h, b = temp self.header_bytes += h self.body_bytes += b @property def header_str(self): return str(self.header_bytes, encoding='utf-8') def initialize_headers(self): headers = self.header_str.split('\r\n') first_line = headers[0].split(' ') if len(first_line) == 3: self.method, self.url, self.protocol = headers[0].split(' ') for line in headers: kv = line.split(':') if len(kv) == 2: k, v = kv self.header_dict[k] = v class Future(object): def __init__(self, timeout=0): self.result = None self.timeout = timeout self.start = time.time() def main(request): f = Future(5) return f def index(request): return "indexasdfasdfasdf" routers = [ ('/main/', main), ('/index/', index), ] def run(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("127.0.0.1", 9999,)) sock.setblocking(False) sock.listen(128) inputs = [sock, ] # inputs.append(sock) async_request_dict = { # 'socket': futrue } while True: rlist, wlist, elist = select.select(inputs, [], [], 0.05) for r in rlist: if r == sock: """新请求到来""" conn, addr = sock.accept() conn.setblocking(False) inputs.append(conn) else: """客户端发来数据""" data = b"" while True: try: chunk = r.recv(1024) data = data + chunk except Exception as e: chunk = None if not chunk: break # data进行处理:请求头和请求体 request = HttpRequest(data) # 1. 请求头中获取url # 2. 去路由中匹配,获取指定的函数 # 3. 执行函数,获取返回值 # 4. 将返回值 r.sendall(b'alskdjalksdjf;asfd') import re flag = False func = None for route in routers: if re.match(route[0], request.url): flag = True func = route[1] break if flag: result = func(request) if isinstance(result, Future): async_request_dict[r] = result else: r.sendall(bytes(result, encoding='utf-8')) inputs.remove(r) r.close() else: r.sendall(b"404") inputs.remove(r) r.close() for conn in async_request_dict.keys(): future = async_request_dict[conn] start = future.start timeout = future.timeout ctime = time.time() if (start + timeout) <= ctime: future.result = b"timeout" if future.result: conn.sendall(future.result) conn.close() del async_request_dict[conn] inputs.remove(conn) if __name__ == '__main__': run() 自定制web非阻塞框架-DEMO


                
            
        
浙公网安备 33010602011771号