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'\r\n\r\n', 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('\r\n')
 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)

 

posted @ 2017-09-15 15:24  ForeverPine  阅读(414)  评论(0编辑  收藏  举报
TOP