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 Queue模块详解
Nov 30 Python
在Python中使用pngquant压缩png图片的教程
Apr 09 Python
Python字符串格式化输出方法分析
Apr 13 Python
Python编程之gui程序实现简单文件浏览器代码
Dec 08 Python
Python数据分析中Groupby用法之通过字典或Series进行分组的实例
Dec 08 Python
django用户登录和注销的实现方法
Jul 16 Python
selenium+python自动化测试之多窗口切换
Jan 23 Python
基于python的BP神经网络及异或实现过程解析
Sep 30 Python
Python处理mysql特殊字符的问题
Mar 02 Python
jupyter notebook oepncv 显示一张图像的实现
Apr 24 Python
Python 利用argparse模块实现脚本命令行参数解析
Dec 28 Python
Python数据分析入门之教你怎么搭建环境
May 13 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
一个简单的自动发送邮件系统(一)
2006/10/09 PHP
PHP syntax error, unexpected $end 错误的一种原因及解决
2008/10/25 PHP
WordPress中登陆后关闭登陆页面及设置用户不可见栏目
2015/12/31 PHP
Smarty实现页面静态化(生成HTML)的方法
2016/05/23 PHP
PHP的AES加密算法完整实例
2016/07/20 PHP
Date对象格式化函数代码
2010/07/17 Javascript
JS保存和删除cookie操作 判断cookie是否存在
2013/11/13 Javascript
javascript中typeof的使用示例
2013/12/19 Javascript
从JQuery源码分析JavaScript函数的apply方法与call方法
2014/09/25 Javascript
解决Jquery向页面append新元素之后事件的绑定问题
2015/03/16 Javascript
JavaScript使用shift方法移除素组第一个元素实例分析
2015/04/06 Javascript
jQuery Mobile动态刷新页面样式的实现方法
2016/05/28 Javascript
JavaScript中的Array 对象(数组对象)
2016/06/02 Javascript
实例解析jQuery中如何取消后续执行内容
2016/12/01 Javascript
jQuery实现文字自动横移
2017/01/08 Javascript
Bootstrap BootstrapDialog使用详解
2017/02/17 Javascript
Swiper自定义分页器使用详解
2017/12/28 Javascript
react+redux仿微信聊天界面
2019/06/21 Javascript
在node环境下parse Smarty模板的使用示例代码
2019/11/15 Javascript
vue使用map代替Aarry数组循环遍历的方法
2020/04/30 Javascript
python下os模块强大的重命名方法renames详解
2017/03/07 Python
python的socket编程入门
2018/01/29 Python
Selenium的使用详解
2018/10/19 Python
Pandas读取并修改excel的示例代码
2019/02/17 Python
pycharm new project变成灰色的解决方法
2019/06/27 Python
Python如何使用turtle库绘制图形
2020/02/26 Python
django xadmin 管理器常用显示设置方式
2020/03/11 Python
医药工作岗位求职信分享
2013/12/31 职场文书
打架检讨书100字
2014/01/08 职场文书
新闻学专业个人求职信写作
2014/02/04 职场文书
经典洗发水广告词
2014/03/13 职场文书
会计电算化专业自荐信
2014/03/15 职场文书
工人先锋号事迹材料
2014/12/24 职场文书
2015年客服工作总结范文
2015/04/02 职场文书
摘录式读书笔记
2015/07/01 职场文书
Node与Python 双向通信的实现代码
2021/07/16 Javascript