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)
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!