• Tornado----自定义异步非阻塞Web框架:Snow


    Python的Web框架中Tornado以异步非阻塞而闻名。本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow。

    一、源码

    本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞的Web框架,其中便是众多异步非阻塞Web框架内部原理。

      1 #!/usr/bin/env python
      2 # -*- coding:utf-8 -*-
      3 import re
      4 import socket
      5 import select
      6 import time
      7 
      8 
      9 class HttpResponse(object):
     10     """
     11     封装响应信息
     12     """
     13     def __init__(self, content=''):
     14         self.content = content
     15 
     16         self.headers = {}
     17         self.cookies = {}
     18 
     19     def response(self):
     20         return bytes(self.content, encoding='utf-8')
     21 
     22 
     23 class HttpNotFound(HttpResponse):
     24     """
     25     404时的错误提示
     26     """
     27     def __init__(self):
     28         super(HttpNotFound, self).__init__('404 Not Found')
     29 
     30 
     31 class HttpRequest(object):
     32     """
     33     用户封装用户请求信息
     34     """
     35     def __init__(self, conn):
     36         self.conn = conn
     37 
     38         self.header_bytes = bytes()
     39         self.header_dict = {}
     40         self.body_bytes = bytes()
     41 
     42         self.method = ""
     43         self.url = ""
     44         self.protocol = ""
     45 
     46         self.initialize()
     47         self.initialize_headers()
     48 
     49     def initialize(self):
     50 
     51         header_flag = False
     52         while True:
     53             try:
     54                 received = self.conn.recv(8096)
     55             except Exception as e:
     56                 received = None
     57             if not received:
     58                 break
     59             if header_flag:
     60                 self.body_bytes += received
     61                 continue
     62             temp = received.split(b'
    
    ', 1)
     63             if len(temp) == 1:
     64                 self.header_bytes += temp
     65             else:
     66                 h, b = temp
     67                 self.header_bytes += h
     68                 self.body_bytes += b
     69                 header_flag = True
     70 
     71     @property
     72     def header_str(self):
     73         return str(self.header_bytes, encoding='utf-8')
     74 
     75     def initialize_headers(self):
     76         headers = self.header_str.split('
    ')
     77         first_line = headers[0].split(' ')
     78         if len(first_line) == 3:
     79             self.method, self.url, self.protocol = headers[0].split(' ')
     80             for line in headers:
     81                 kv = line.split(':')
     82                 if len(kv) == 2:
     83                     k, v = kv
     84                     self.header_dict[k] = v
     85 
     86 
     87 class Future(object):
     88     """
     89     异步非阻塞模式时封装回调函数以及是否准备就绪
     90     """
     91     def __init__(self, callback):
     92         self.callback = callback
     93         self._ready = False
     94         self.value = None
     95 
     96     def set_result(self, value=None):
     97         self.value = value
     98         self._ready = True
     99 
    100     @property
    101     def ready(self):
    102         return self._ready
    103 
    104 
    105 class TimeoutFuture(Future):
    106     """
    107     异步非阻塞超时
    108     """
    109     def __init__(self, timeout):
    110         super(TimeoutFuture, self).__init__(callback=None)
    111         self.timeout = timeout
    112         self.start_time = time.time()
    113 
    114     @property
    115     def ready(self):
    116         current_time = time.time()
    117         if current_time > self.start_time + self.timeout:
    118             self._ready = True
    119         return self._ready
    120 
    121 
    122 class Snow(object):
    123     """
    124     微型Web框架类
    125     """
    126     def __init__(self, routes):
    127         self.routes = routes
    128         self.inputs = set()
    129         self.request = None
    130         self.async_request_handler = {}
    131 
    132     def run(self, host='localhost', port=9999):
    133         """
    134         事件循环
    135         :param host:
    136         :param port:
    137         :return:
    138         """
    139         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    140         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    141         sock.bind((host, port,))
    142         sock.setblocking(False)
    143         sock.listen(128)
    144         sock.setblocking(0)
    145         self.inputs.add(sock)
    146         try:
    147             while True:
    148                 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs,0.005)
    149                 for conn in readable_list:
    150                     if sock == conn:
    151                         client, address = conn.accept()
    152                         client.setblocking(False)
    153                         self.inputs.add(client)
    154                     else:
    155                         gen = self.process(conn)
    156                         if isinstance(gen, HttpResponse):
    157                             conn.sendall(gen.response())
    158                             self.inputs.remove(conn)
    159                             conn.close()
    160                         else:
    161                             yielded = next(gen)
    162                             self.async_request_handler[conn] = yielded
    163                 self.polling_callback()
    164 
    165         except Exception as e:
    166             pass
    167         finally:
    168             sock.close()
    169 
    170     def polling_callback(self):
    171         """
    172         遍历触发异步非阻塞的回调函数
    173         :return:
    174         """
    175         for conn in list(self.async_request_handler.keys()):
    176             yielded = self.async_request_handler[conn]
    177             if not yielded.ready:
    178                 continue
    179             if yielded.callback:
    180                 ret = yielded.callback(self.request, yielded)
    181                 conn.sendall(ret.response())
    182             self.inputs.remove(conn)
    183             del self.async_request_handler[conn]
    184             conn.close()
    185 
    186     def process(self, conn):
    187         """
    188         处理路由系统以及执行函数
    189         :param conn:
    190         :return:
    191         """
    192         self.request = HttpRequest(conn)
    193         func = None
    194         for route in self.routes:
    195             if re.match(route[0], self.request.url):
    196                 func = route[1]
    197                 break
    198         if not func:
    199             return HttpNotFound()
    200         else:
    201             return func(self.request)
    snow.py

    二、使用

    1. 基本使用

     1 from snow import Snow
     2 from snow import HttpResponse
     3  
     4  
     5 def index(request):
     6     return HttpResponse('OK')
     7  
     8  
     9 routes = [
    10     (r'/index/', index),
    11 ]
    12  
    13 app = Snow(routes)
    14 app.run(port=8012)

    2.异步非阻塞:超时

     1 from snow import Snow
     2 from snow import HttpResponse
     3 from snow import TimeoutFuture
     4  
     5 request_list = []
     6  
     7  
     8 def async(request):
     9     obj = TimeoutFuture(5)
    10     yield obj
    11  
    12  
    13 def home(request):
    14     return HttpResponse('home')
    15  
    16  
    17 routes = [
    18     (r'/home/', home),
    19     (r'/async/', async),
    20 ]
    21  
    22 app = Snow(routes)
    23 app.run(port=8012)

    3.异步非阻塞:等待

    基于等待模式可以完成自定制操作

     1 from snow import Snow
     2 from snow import HttpResponse
     3 from snow import Future
     4  
     5 request_list = []
     6  
     7  
     8 def callback(request, future):
     9     return HttpResponse(future.value)
    10  
    11  
    12 def req(request):
    13     obj = Future(callback=callback)
    14     request_list.append(obj)
    15     yield obj
    16  
    17  
    18 def stop(request):
    19     obj = request_list[0]
    20     del request_list[0]
    21     obj.set_result('done')
    22     return HttpResponse('stop')
    23  
    24  
    25 routes = [
    26     (r'/req/', req),
    27     (r'/stop/', stop),
    28 ]
    29  
    30 app = Snow(routes)
    31 app.run(port=8012)
  • 相关阅读:
    496. 下一个更大元素 I
    240. 搜索二维矩阵 II
    java反射之ObjectAnalyzer
    PHP导出excel文件的多种方式
    git获取公钥和私钥以及常用的命令
    PHP PSR-2 代码风格规范
    phpStrom安装PHP_CodeSniffer检查代码规范
    常见PHP安全网站漏洞及防范措施
    Oracle中创建主键并在Spring data JPA中使用
    JPA自定义查询中报错:缺失右括号
  • 原文地址:https://www.cnblogs.com/wangyongsong/p/7526646.html
Copyright © 2020-2023  润新知