200-line custom asynchronous non-blocking Web framework and 200-line asynchronous web Framework
In the Python Web framework, Tornado is famous for its asynchronous non-blocking. This article uses 200 lines of code to complete a micro asynchronous non-blocking Web Framework: Snow.
I. Source Code
This article is based on the non-blocking Socket and IO multiplexing to Implement Asynchronous non-blocking Web framework, among which is the internal principle of many asynchronous non-blocking Web frameworks.
#! /Usr/bin/env python #-*-coding: UTF-8-*-import reimport socketimport selectimport timeclass HttpResponse (object ): "encapsulate response information" "def _ init _ (self, content =''): self. content = content self. headers = {} self. cookies = {} def response (self): return bytes (self. content, encoding = 'utf-8') class HttpNotFound (HttpResponse): "" 404 error message "def _ init _ (self ): super (HttpNotFound, self ). _ init _ ('2014 Not Found ') class HttpRequest (object): "User encapsulation user request information" def _ init _ (self, conn): self. conn = conn self. header_bytes = bytes () self. header_dict ={} self. body_bytes = bytes () self. method = "" self. url = "" self. protocol = "" self. initialize () self. initialize_headers () def initialize (self): header_flag = False while True: try: received = self. conn. recv (8096) failed t Exception as e: pinned ED = None if not passed ed: break if header_flag: self. body_bytes + = already ed continue temp = already ed. 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 header_flag = True @ 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] = vclass Future (object): "encapsulates the callback function in asynchronous non-blocking mode and is ready?" def _ init _ (self, callback): self. callback = callback self. _ ready = False self. value = None def set_result (self, value = None): self. value = value self. _ ready = True @ property def ready (self): return self. _ readyclass TimeoutFuture (Future): "Asynchronous non-blocking timeout" def _ init _ (self, timeout): super (TimeoutFuture, self ). _ init _ (callback = None) self. timeout = timeout self. start_time = time. time () @ property def ready (self): current_time = time. time () if current_time> self. start_time + self. timeout: self. _ ready = True return self. _ readyclass Snow (object): "micro-Web framework class" def _ init _ (self, routes): self. routes = routes self. inputs = set () self. request = None self. async_request_handler = {} def run (self, host = 'localhost', port = 9999): "" event loop: param host: param port: return: "sock = socket. socket (socket. AF_INET, socket. SOCK_STREAM) sock. bind (host, port,) sock. setblocking (False) sock. listen (1, 128) sock. setblocking (0) self. inputs. add (sock) try: while True: readable_list, writeable_list, error_list = select. select (self. inputs, [], self. inputs, 0.005) for conn in readable_list: if sock = conn: client, address = conn. accept () client. setblocking (False) self. inputs. add (client) else: gen = self. process (conn) if isinstance (gen, HttpResponse): conn. sendall (gen. response () self. inputs. remove (conn) conn. close () else: yielded = next (gen) self. async_request_handler [conn] = yielded self. polling_callback () failed t Exception as e: pass finally: sock. close () def polling_callback (self): "traverses the callback function that triggers asynchronous non-blocking: return:" for conn in list (self. async_request_handler.keys (): yielded = self. async_request_handler [conn] if not yielded. ready: continue if yielded. callback: ret = yielded. callback (self. request, yielded) conn. sendall (ret. response () self. inputs. remove (conn) del self. async_request_handler [conn] conn. close () def process (self, conn): "processes the routing system and executes the function: param conn: return:" "self. request = HttpRequest (conn) func = None for route in self. routes: if re. match (route [0], self. request. url): func = route [1] break if not func: return HttpNotFound () else: return func (self. request)Snow. py 2. Use
1. Basic use
from snow import Snowfrom snow import HttpResponsedef index(request): return HttpResponse('OK')routes = [ (r'/index/', index),]app = Snow(routes)app.run(port=8012)
2. asynchronous non-blocking: timeout
from snow import Snowfrom snow import HttpResponsefrom snow import TimeoutFuturerequest_list = []def async(request): obj = TimeoutFuture(5) yield objdef home(request): return HttpResponse('home')routes = [ (r'/home/', home), (r'/async/', async),]app = Snow(routes)app.run(port=8012)
3. asynchronous non-blocking: waiting
Custom operations can be completed based on the waiting mode
from snow import Snowfrom snow import HttpResponsefrom snow import Futurerequest_list = []def callback(request, future): return HttpResponse(future.value)def req(request): obj = Future(callback=callback) request_list.append(obj) yield objdef stop(request): obj = request_list[0] del request_list[0] obj.set_result('done') return HttpResponse('stop')routes = [ (r'/req/', req), (r'/stop/', stop),]app = Snow(routes)app.run(port=8012)