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 文件操作的详解及实例
Sep 18 Python
Python基于socket模块实现UDP通信功能示例
Apr 10 Python
实例讲解python中的序列化知识点
Oct 08 Python
在win10和linux上分别安装Python虚拟环境的方法步骤
May 09 Python
python selenium实现发送带附件的邮件代码实例
Dec 10 Python
解决python执行较大excel文件openpyxl慢问题
May 15 Python
使用jupyter notebook运行python和R的步骤
Aug 13 Python
Scrapy基于scrapy_redis实现分布式爬虫部署的示例
Sep 29 Python
Python排序函数的使用方法详解
Dec 11 Python
Python lxml库的简单介绍及基本使用讲解
Dec 22 Python
使用pandas生成/读取csv文件的方法实例
Jul 09 Python
openstack中的rpc远程调用的方法
Jul 09 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自定义hash函数实例
2015/05/05 PHP
php从文件夹随机读取文件的方法
2015/06/01 PHP
php结合md5的加密解密算法实例
2016/09/30 PHP
解决laravel 5.1报错:No supported encrypter found的办法
2017/06/07 PHP
Yii2.0 RESTful API 基础配置教程详解
2018/12/26 PHP
Jquery实现点击按钮,连续地向textarea中添加值的实例代码
2014/03/08 Javascript
nodejs教程之入门
2014/11/21 NodeJs
快速学习jQuery插件 jquery.validate.js表单验证插件使用方法
2015/12/01 Javascript
简单理解vue中Props属性
2016/10/27 Javascript
jquery组件WebUploader文件上传用法详解
2020/10/23 Javascript
Javascript 实现放大镜效果实例详解
2016/12/03 Javascript
jquery.validate表单验证插件使用详解
2017/06/21 jQuery
基于jQuery选择器之表单对象属性筛选选择器的实例
2017/09/19 jQuery
Webpack框架核心概念(知识点整理)
2017/12/22 Javascript
JavaScript创建防篡改对象的方法分析
2018/12/30 Javascript
总结4个方面优化Vue项目
2019/02/11 Javascript
原生js实现贪食蛇小游戏的思路详解
2019/11/26 Javascript
uniapp,微信小程序中使用 MQTT的问题
2020/07/11 Javascript
[01:37]全新的一集《真视界》——TI7总决赛
2017/09/21 DOTA
Django的数据模型访问多对多键值的方法
2015/07/21 Python
给你选择Python语言实现机器学习算法的三大理由
2017/11/15 Python
Python中摘要算法MD5,SHA1简介及应用实例代码
2018/01/09 Python
python3.6+django2.0开发一套学员管理系统
2018/03/03 Python
python 输出所有大小写字母的方法
2019/01/02 Python
python基于SMTP协议发送邮件
2019/05/31 Python
python,Java,JavaScript实现indexOf
2020/09/09 Python
HTML5注册页面示例代码
2014/03/27 HTML / CSS
英国假发网站:Hothair
2018/02/23 全球购物
英国女士和男士时尚服装网上购物:Top Labels Online
2018/03/25 全球购物
写一个方法1000的阶乘
2012/11/21 面试题
矫正人员思想汇报
2014/01/08 职场文书
英语课外活动总结
2014/08/27 职场文书
2014年高二班主任工作总结
2014/12/16 职场文书
就业推荐表导师评语
2014/12/31 职场文书
社区敬老月活动总结
2015/05/07 职场文书
2015年员工试用期工作总结
2015/05/28 职场文书