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实现去除代码前行号的方法
Mar 10 Python
Python操作csv文件实例详解
Jul 31 Python
分析python动态规划的递归、非递归实现
Mar 04 Python
神经网络(BP)算法Python实现及应用
Apr 16 Python
在双python下设置python3为默认的方法
Oct 31 Python
python 将大文件切分为多个小文件的实例
Jan 14 Python
VSCode Python开发环境配置的详细步骤
Feb 22 Python
django url到views参数传递的实例
Jul 19 Python
Python读写操作csv和excle文件代码实例
Mar 16 Python
Python实现自动装机功能案例分析
Oct 22 Python
Python爬虫入门教程01之爬取豆瓣Top电影
Jan 24 Python
python实现批量移动文件
Apr 05 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采集腾讯微博的实现代码
2012/01/19 PHP
php限制文件下载速度的代码
2015/10/20 PHP
php-7.3.6 编译安装过程
2020/02/11 PHP
javascript延时重复执行函数 lLoopRun.js
2007/06/29 Javascript
显示js对象所有属性和方法的函数
2009/10/16 Javascript
js获取浏览器的可视区域尺寸的实现代码
2011/11/30 Javascript
jQuery随机切换图片的小例子
2013/04/18 Javascript
ie8模式下click无反应点击option无反应的解决方法
2014/10/11 Javascript
jquery中表单 多选框的一种巧妙写法
2015/09/06 Javascript
angularJS+requireJS实现controller及directive的按需加载示例
2017/02/20 Javascript
JS实现的简单四则运算计算器功能示例
2017/09/27 Javascript
详解Puppeteer 入门教程
2018/05/09 Javascript
Vue 组件修改根实例的数据的方法
2019/04/02 Javascript
js实现轮播图特效
2020/05/28 Javascript
js实现从右往左匀速显示图片(无缝轮播)
2020/06/29 Javascript
解决vue侦听器watch,调用this时出现undefined的问题
2020/10/30 Javascript
JavaScript实现消消乐的源代码
2021/01/12 Javascript
[00:36]DOTA2上海特级锦标赛 LGD战队宣传片
2016/03/04 DOTA
python 文件与目录操作
2008/12/24 Python
Python的内存泄漏及gc模块的使用分析
2014/07/16 Python
解决安装tensorflow遇到无法卸载numpy 1.8.0rc1的问题
2018/06/13 Python
CentOS6.9 Python环境配置(python2.7、pip、virtualenv)
2019/05/06 Python
Django网络框架之HelloDjango项目创建教程
2019/06/06 Python
centos 安装Python3 及对应的pip教程详解
2019/06/28 Python
wxPython实现整点报时
2019/11/18 Python
Python xlrd模块导入过程及常用操作
2020/06/10 Python
css3 伪元素和伪类选择器详解
2014/09/04 HTML / CSS
Html5页面中的返回实现的方法
2018/02/26 HTML / CSS
Chemist Warehouse中文网:澳洲连锁大药房
2021/02/05 全球购物
会计找工作求职信范文
2013/12/09 职场文书
购房意向书
2014/04/01 职场文书
食堂标语大全
2014/06/11 职场文书
先进基层党组织事迹材料
2014/12/25 职场文书
三八节活动简报
2015/07/20 职场文书
百年校庆感言
2015/08/01 职场文书
世界无敌的ICOM IC-R9500宽频接收机
2022/03/25 无线电