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中属性和描述符的正确使用
Aug 23 Python
python下setuptools的安装详解及No module named setuptools的解决方法
Jul 06 Python
Pandas探索之高性能函数eval和query解析
Oct 28 Python
Python xlwt设置excel单元格字体及格式
Apr 18 Python
Python 爬虫之Beautiful Soup模块使用指南
Jul 05 Python
Django之使用内置函数和celery发邮件的方法示例
Sep 16 Python
python list多级排序知识点总结
Oct 23 Python
Python进程的通信Queue、Pipe实例分析
Mar 30 Python
python中逻辑与或(and、or)和按位与或异或(&、|、^)区别
Aug 05 Python
记一次django内存异常排查及解决方法
Aug 07 Python
Jupyter Notebook添加代码自动补全功能的实现
Jan 07 Python
Python Matplotlib绘制动画的代码详解
May 30 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
有关PHP中MVC的开发经验分享
2012/05/17 PHP
PHP生成(支持多模板)二维码海报代码
2018/04/30 PHP
JavaScript之HTMLCollection接口代码
2011/04/27 Javascript
借助javascript代码判断网页是静态还是伪静态
2014/05/05 Javascript
javascript解析xml实现省市县三级联动的方法
2015/07/25 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
2015/10/16 Javascript
仅30行代码实现Javascript中的MVC
2016/02/15 Javascript
jQuery模拟Marquee实现无缝滚动效果完整实例
2016/09/29 Javascript
jQuery实现的事件绑定功能基本示例
2017/10/11 jQuery
javascript json字符串到json对象转义问题
2019/01/22 Javascript
使用Three.js实现太阳系八大行星的自转公转示例代码
2019/04/09 Javascript
javascript中的this作用域详解
2019/07/15 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
浅谈Vuex的this.$store.commit和在Vue项目中引用公共方法
2020/07/24 Javascript
[42:25]2018DOTA2亚洲邀请赛 4.5 淘汰赛 LGD vs Liquid 第三场
2018/04/06 DOTA
[00:10]DOTA2 TI9勇士令状明日上线
2019/05/07 DOTA
Python数组定义方法
2016/04/13 Python
python 从csv读数据到mysql的实例
2018/06/21 Python
解决python3 HTMLTestRunner测试报告中文乱码的问题
2018/12/17 Python
Python嵌套函数,作用域与偏函数用法实例分析
2019/12/26 Python
sklearn线性逻辑回归和非线性逻辑回归的实现
2020/06/09 Python
基于Python 的语音重采样函数解析
2020/07/06 Python
Python字典取键、值对的方法步骤
2020/09/30 Python
推荐一些比较有用的css3新属性
2014/11/11 HTML / CSS
在canvas上实现元素图片镜像翻转动画效果的方法
2018/03/20 HTML / CSS
Gap工厂店:Gap Factory
2017/11/02 全球购物
英国领先的电视购物零售商:Ideal World
2019/03/18 全球购物
荣耀商城:HIHONOR
2020/11/03 全球购物
质量工程师岗位职责
2013/11/16 职场文书
股权转让协议范本
2014/12/07 职场文书
安全检查汇报材料
2014/12/26 职场文书
2015年售票员工作总结
2015/04/29 职场文书
毕业论文指导老师意见
2015/06/04 职场文书
创业计划书之家政服务
2019/09/18 职场文书
PHP命令行与定时任务
2021/04/01 PHP
Go语言编译原理之变量捕获
2022/08/05 Golang