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 16 Python
Python实现对比不同字体中的同一字符的显示效果
Apr 23 Python
用Python的Tornado框架结合memcached页面改善博客性能
Apr 24 Python
Python for Informatics 第11章之正则表达式(二)
Apr 21 Python
Django项目实战之用户头像上传与访问的示例
Apr 21 Python
python实现数据导出到excel的示例--普通格式
May 03 Python
使用pandas模块读取csv文件和excel表格,并用matplotlib画图的方法
Jun 22 Python
Python文件常见操作实例分析【读写、遍历】
Dec 10 Python
python 同时运行多个程序的实例
Jan 07 Python
简单的Python调度器Schedule详解
Aug 30 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
Jan 10 Python
python重要函数eval多种用法解析
Jan 14 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学习资料汇总与网址
2007/03/16 PHP
php中Session的生成机制、回收机制和存储机制探究
2014/08/19 PHP
微信JSSDK分享功能图文实例详解
2019/04/08 PHP
php实现简单的守护进程创建、开启与关闭操作
2019/08/13 PHP
PHP简单实现图片格式转换(jpg转png,gif转png等)
2019/10/30 PHP
jquery tools 系列 scrollable(2)
2009/09/06 Javascript
JavaScript 类似flash效果的立体图片浏览器
2010/02/08 Javascript
JQuery对checkbox操作 (循环获取)
2011/05/20 Javascript
网页加载时页面显示进度条加载完成之后显示网页内容
2012/12/23 Javascript
JQuery页面的表格数据的增加与分页的实现
2013/12/10 Javascript
js(JavaScript)实现TAB标签切换效果的简单实例
2014/02/26 Javascript
代码获取历史上的今天发生的事
2014/04/11 Javascript
JavaScript编程的10个实用小技巧
2014/04/18 Javascript
js中使用replace方法完成某个字符的转换
2014/08/20 Javascript
我用的一些Node.js开发工具、开发包、框架等总结
2014/09/25 Javascript
node.js中Socket.IO的进阶使用技巧
2014/11/04 Javascript
javascript中的作用域和闭包详解
2016/01/13 Javascript
AngularJS入门教程之数据绑定原理详解
2016/11/02 Javascript
浅谈JavaScript异步编程
2017/01/20 Javascript
小程序组件之仿微信通讯录的实现代码
2018/09/12 Javascript
iview的table组件自带的过滤器实现
2019/07/12 Javascript
基于原生js实现判断元素是否有指定class名
2020/07/11 Javascript
如何HttpServletRequest文件对象并储存
2020/08/14 Javascript
[00:57]深扒TI7聊天轮盘语音出处5
2017/05/11 DOTA
python实现2048小游戏
2015/03/30 Python
Python 多线程Threading初学教程
2017/08/22 Python
Python中利用aiohttp制作异步爬虫及简单应用
2018/11/29 Python
python实现根据文件关键字进行切分为多个文件的示例
2018/12/10 Python
使用python搭建服务器并实现Android端与之通信的方法
2019/06/28 Python
python numpy 常用随机数的产生方法的实现
2019/08/21 Python
python画环形图的方法
2020/03/25 Python
HTML5如何为形状图上颜色怎么绘制具有颜色和透明度的矩形
2014/06/23 HTML / CSS
中国领先的专业演出票务网:永乐票务
2016/08/29 全球购物
英国在线自行车店:Merlin Cycles
2018/08/20 全球购物
环卫工人慰问信
2015/02/15 职场文书
大学毕业生个人总结
2015/02/28 职场文书