200行自定义python异步非阻塞Web框架


Posted in Python onMarch 15, 2017

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

一、源码

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
import socket
import select
import time
class HttpResponse(object):
 """
 封装响应信息
 """
 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时的错误提示
 """
 def __init__(self):
  super(HttpNotFound, self).__init__('404 Not Found')
class HttpRequest(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()
 def initialize(self):
  header_flag = False
  while True:
   try:
    received = self.conn.recv(8096)
   except Exception as e:
    received = None
   if not received:
    break
   if header_flag:
    self.body_bytes += received
    continue
   temp = received.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] = v
class Future(object):
 """
 异步非阻塞模式时封装回调函数以及是否准备就绪
 """
 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._ready
class TimeoutFuture(Future):
 """
 异步非阻塞超时
 """
 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._ready
class Snow(object):
 """
 微型Web框架类
 """
 def __init__(self, routes):
  self.routes = routes
  self.inputs = set()
  self.request = None
  self.async_request_handler = {}
 def run(self, host='localhost', port=9999):
  """
  事件循环
  :param host:
  :param port:
  :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:
   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()
except Exception as e:
   pass
  finally:
   sock.close()
def polling_callback(self):
  """
  遍历触发异步非阻塞的回调函数
  :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):
  """
  处理路由系统以及执行函数
  :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

二、使用

1. 基本使用

from snow import Snow
from snow import HttpResponse
def index(request):
return HttpResponse('OK')
routes = [
 (r'/index/', index),
]
app = Snow(routes)
app.run(port=8012)

2.异步非阻塞:超时

from snow import Snow
from snow import HttpResponse
from snow import TimeoutFuture
request_list = []
def async(request):
 obj = TimeoutFuture(5)
 yield obj
def home(request):
 return HttpResponse('home')
routes = [
 (r'/home/', home),
 (r'/async/', async),
]
app = Snow(routes)
app.run(port=8012)

3.异步非阻塞:等待

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

from snow import Snow
from snow import HttpResponse
from snow import Future
request_list = []
def callback(request, future):
 return HttpResponse(future.value)
def req(request):
 obj = Future(callback=callback)
 request_list.append(obj)
 yield obj
def 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)

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Python 相关文章推荐
Python实现多线程下载文件的代码实例
Jun 01 Python
Python中在for循环中嵌套使用if和else语句的技巧
Jun 20 Python
利用TensorFlow训练简单的二分类神经网络模型的方法
Mar 05 Python
python opencv人脸检测提取及保存方法
Aug 03 Python
Python数据可视化之画图
Jan 15 Python
Python开启线程,在函数中开线程的实例
Feb 22 Python
Python实现字典按key或者value进行排序操作示例【sorted】
May 03 Python
django 微信网页授权登陆的实现
Jul 30 Python
一文了解python 3 字符串格式化 F-string 用法
Mar 04 Python
解决Django提交表单报错:CSRF token missing or incorrect的问题
Mar 13 Python
浅谈Python列表嵌套字典转化的问题
Apr 07 Python
python和Appium的移动端多设备自动化测试框架
Apr 26 Python
Python实现简易端口扫描器代码实例
Mar 15 #Python
Python使用sftp实现上传和下载功能(实例代码)
Mar 14 #Python
Python实现Youku视频批量下载功能
Mar 14 #Python
Python实现视频下载功能
Mar 14 #Python
python 实现自动远程登陆scp文件实例代码
Mar 13 #Python
python executemany的使用及注意事项
Mar 13 #Python
Python的标准模块包json详解
Mar 13 #Python
You might like
基于mysql的论坛(7)
2006/10/09 PHP
PHP生成自定义长度随机字符串的函数分享
2014/05/04 PHP
javascript attachEvent和addEventListener使用方法
2009/03/19 Javascript
jqGrid读取选择的多行的某个属性代码
2014/05/18 Javascript
jQuery unbind()方法实例详解
2016/01/19 Javascript
JS仿hao123导航页面图片轮播效果
2016/09/01 Javascript
基于javascript实现按圆形排列DIV元素(二)
2016/12/02 Javascript
js对象实例详解(JavaScript对象深度剖析,深度理解js对象)
2017/09/21 Javascript
原生js封装运动框架的示例讲解
2017/10/01 Javascript
JavaScript实现精美个性导航栏筋斗云效果
2017/10/29 Javascript
vue+jquery+lodash实现滑动时顶部悬浮固定效果
2018/04/28 jQuery
详解jenkins自动化部署vue
2019/05/14 Javascript
layui.tree组件的使用以及搜索节点功能的实现
2019/09/26 Javascript
JavaScript实现图片上传并预览并提交ajax
2019/09/30 Javascript
Vue + Element-ui的下拉框el-select获取额外参数详解
2020/08/14 Javascript
javascript实现简单留言板案例
2021/02/09 Javascript
Python enumerate遍历数组示例应用
2008/09/06 Python
python在windows和linux下获得本机本地ip地址方法小结
2015/03/20 Python
Python中read()、readline()和readlines()三者间的区别和用法
2017/07/30 Python
Python面向对象之类和对象属性的增删改查操作示例
2018/12/14 Python
Python实现的旋转数组功能算法示例
2019/02/23 Python
详解Python3迁移接口变化采坑记
2019/10/11 Python
在Python中使用K-Means聚类和PCA主成分分析进行图像压缩
2020/04/10 Python
matplotlib.pyplot.plot()参数使用详解
2020/07/28 Python
你可能不熟练的十个前端HTML5经典面试题
2018/07/03 HTML / CSS
英国剑桥包官网:The Cambridge Satchel Company
2016/08/01 全球购物
全球知名提供各类营养保健品的零售商:Vitamin Shoppe
2016/10/09 全球购物
联欢晚会主持词
2014/03/25 职场文书
大专应届毕业生求职信
2014/07/15 职场文书
毕业生班级鉴定评语
2015/01/04 职场文书
法院个人总结
2015/03/03 职场文书
小学教师自我评价
2015/03/04 职场文书
2015年师德表现自我评价
2015/03/05 职场文书
单位工作证明范本
2015/06/15 职场文书
先进个人主要事迹怎么写
2015/11/04 职场文书
Python机器学习之基于Pytorch实现猫狗分类
2021/06/08 Python