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
自定制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



'''
View Code

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有返回值,则发送 关闭移除




'''
自定制异步非阻塞 (Future)

升级版

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()
自定制Future·

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
参考

 

posted @ 2017-05-25 23:37  红领巾下的大刀疤  阅读(122)  评论(0)    收藏  举报
/* 看板娘 */