200行自定义python异步非阻塞Web框架
Python的Web框架中Tornado以异步非阻塞而闻名。本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow。
一、源码
本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞的Web框架,其中便是众多异步非阻塞Web框架内部原理。
#!/usr/bin/envpython #-*-coding:utf-8-*- importre importsocket importselect importtime classHttpResponse(object): """ 封装响应信息 """ def__init__(self,content=''): self.content=content self.headers={} self.cookies={} defresponse(self): returnbytes(self.content,encoding='utf-8') classHttpNotFound(HttpResponse): """ 404时的错误提示 """ def__init__(self): super(HttpNotFound,self).__init__('404NotFound') classHttpRequest(object): """ 用户封装用户请求信息 """ 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() definitialize(self): header_flag=False whileTrue: try: received=self.conn.recv(8096) exceptExceptionase: received=None ifnotreceived: break ifheader_flag: self.body_bytes+=received continue temp=received.split(b'\r\n\r\n',1) iflen(temp)==1: self.header_bytes+=temp else: h,b=temp self.header_bytes+=h self.body_bytes+=b header_flag=True @property defheader_str(self): returnstr(self.header_bytes,encoding='utf-8') definitialize_headers(self): headers=self.header_str.split('\r\n') first_line=headers[0].split('') iflen(first_line)==3: self.method,self.url,self.protocol=headers[0].split('') forlineinheaders: kv=line.split(':') iflen(kv)==2: k,v=kv self.header_dict[k]=v classFuture(object): """ 异步非阻塞模式时封装回调函数以及是否准备就绪 """ def__init__(self,callback): self.callback=callback self._ready=False self.value=None defset_result(self,value=None): self.value=value self._ready=True @property defready(self): returnself._ready classTimeoutFuture(Future): """ 异步非阻塞超时 """ def__init__(self,timeout): super(TimeoutFuture,self).__init__(callback=None) self.timeout=timeout self.start_time=time.time() @property defready(self): current_time=time.time() ifcurrent_time>self.start_time+self.timeout: self._ready=True returnself._ready classSnow(object): """ 微型Web框架类 """ def__init__(self,routes): self.routes=routes self.inputs=set() self.request=None self.async_request_handler={} defrun(self,host='localhost',port=9999): """ 事件循环 :paramhost: :paramport: :return: """ sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock.bind((host,port,)) sock.setblocking(False) sock.listen(128) sock.setblocking(0) self.inputs.add(sock) try: whileTrue: readable_list,writeable_list,error_list=select.select(self.inputs,[],self.inputs,0.005) forconninreadable_list: ifsock==conn: client,address=conn.accept() client.setblocking(False) self.inputs.add(client) else: gen=self.process(conn) ifisinstance(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() exceptExceptionase: pass finally: sock.close() defpolling_callback(self): """ 遍历触发异步非阻塞的回调函数 :return: """ forconninlist(self.async_request_handler.keys()): yielded=self.async_request_handler[conn] ifnotyielded.ready: continue ifyielded.callback: ret=yielded.callback(self.request,yielded) conn.sendall(ret.response()) self.inputs.remove(conn) delself.async_request_handler[conn] conn.close() defprocess(self,conn): """ 处理路由系统以及执行函数 :paramconn: :return: """ self.request=HttpRequest(conn) func=None forrouteinself.routes: ifre.match(route[0],self.request.url): func=route[1] break ifnotfunc: returnHttpNotFound() else: returnfunc(self.request) snow.py
二、使用
1.基本使用
fromsnowimportSnow fromsnowimportHttpResponse defindex(request): returnHttpResponse('OK') routes=[ (r'/index/',index), ] app=Snow(routes) app.run(port=8012)
2.异步非阻塞:超时
fromsnowimportSnow fromsnowimportHttpResponse fromsnowimportTimeoutFuture request_list=[] defasync(request): obj=TimeoutFuture(5) yieldobj defhome(request): returnHttpResponse('home') routes=[ (r'/home/',home), (r'/async/',async), ] app=Snow(routes) app.run(port=8012)
3.异步非阻塞:等待
基于等待模式可以完成自定制操作
fromsnowimportSnow fromsnowimportHttpResponse fromsnowimportFuture request_list=[] defcallback(request,future): returnHttpResponse(future.value) defreq(request): obj=Future(callback=callback) request_list.append(obj) yieldobj defstop(request): obj=request_list[0] delrequest_list[0] obj.set_result('done') returnHttpResponse('stop') routes=[ (r'/req/',req), (r'/stop/',stop), ] app=Snow(routes) app.run(port=8012)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!