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 相关文章推荐
pymssql数据库操作MSSQL2005实例分析
May 25 Python
Android模拟器无法启动,报错:Cannot set up guest memory ‘android_arm’ Invalid argument的解决方法
Jul 01 Python
python的socket编程入门
Jan 29 Python
详解分布式任务队列Celery使用说明
Nov 29 Python
Python构建图像分类识别器的方法
Jan 12 Python
Pandas 重塑(stack)和轴向旋转(pivot)的实现
Jul 22 Python
Django 对IP访问频率进行限制的例子
Aug 30 Python
python实现的按要求生成手机号功能示例
Oct 08 Python
Django实现CAS+OAuth2的方法示例
Oct 30 Python
python 实现方阵的对角线遍历示例
Nov 29 Python
Python CSV文件模块的使用案例分析
Dec 21 Python
 Python 中 logging 模块使用详情
Mar 03 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
BBS(php & mysql)完整版(五)
2006/10/09 PHP
PHP下操作Linux消息队列完成进程间通信的方法
2010/07/24 PHP
php addslashes及其他清除空格的方法是不安全的
2012/01/25 PHP
php对图像的各种处理函数代码小结
2013/07/08 PHP
PHP获取短链接跳转后的真实地址和响应头信息的方法
2014/07/25 PHP
PHP递归创建多级目录
2015/11/05 PHP
javascript web页面刷新的方法收集
2009/07/02 Javascript
jquery+ajax每秒向后台发送请求数据然后返回页面的代码
2011/01/17 Javascript
打印json对象的内容及JSON.stringify函数应用
2013/03/29 Javascript
jquery二级导航内容均分的原理及实现
2013/08/13 Javascript
jQuery对指定元素中指定字符串进行替换的方法
2015/03/17 Javascript
基于jQuery插件实现环形图标菜单旋转切换特效
2015/05/15 Javascript
jQuery控制DIV层实现由大到小,由远及近动画变化效果
2015/10/09 Javascript
解决jquery无法找到其他父级子集问题的方法
2016/05/10 Javascript
微信小程序 loading(加载中提示框)实例
2016/10/28 Javascript
nodejs+express实现文件上传下载管理网站
2017/03/15 NodeJs
JQuery用$.ajax或$.getJSON跨域获取JSON数据的实现代码
2017/09/23 jQuery
two.js之实现动画效果示例
2017/11/06 Javascript
Vue实现商品飞入购物车效果(电商项目)
2019/11/26 Javascript
小程序实现长按保存图片的方法
2019/12/31 Javascript
python调用新浪微博API项目实践
2014/07/28 Python
python基础教程之对象和类的实际运用
2014/08/29 Python
Python中生成Epoch的方法
2017/04/26 Python
Python实现通过解析域名获取ip地址的方法分析
2019/05/17 Python
详解python pandas 分组统计的方法
2019/07/30 Python
python GUI库图形界面开发之PyQt5复选框控件QCheckBox详细使用方法与实例
2020/02/28 Python
基于python实现MQTT发布订阅过程原理解析
2020/07/27 Python
举例详解CSS3中的Transition
2015/07/15 HTML / CSS
德国大型的家具商店:Pharao24.de
2016/10/02 全球购物
卡拉威高尔夫官方网站:Callaway Golf
2020/09/16 全球购物
电气工程和自动化自荐信范文
2013/12/25 职场文书
2014年学生会工作总结
2014/11/07 职场文书
高三数学教学反思
2016/02/18 职场文书
八年级物理教学反思
2016/02/19 职场文书
Python 实现Mac 屏幕截图详解
2021/10/05 Python
Go 语言中 20 个占位符的整理
2021/10/16 Golang