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.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
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)

Tornado----自定义异步非阻塞Web框架:Snow的更多相关文章

  1. 200行自定义异步非阻塞Web框架

    Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞 ...

  2. 150行代码搭建异步非阻塞Web框架

    最近看Tornado源码给了我不少启发,心血来潮决定自己试着只用python标准库来实现一个异步非阻塞web框架.花了点时间感觉还可以,一百多行的代码已经可以撑起一个极简框架了. 一.准备工作 需要的 ...

  3. 03: 自定义异步非阻塞tornado框架

    目录:Tornado其他篇 01: tornado基础篇 02: tornado进阶篇 03: 自定义异步非阻塞tornado框架 04: 打开tornado源码剖析处理过程 目录: 1.1 源码 1 ...

  4. Tornado的异步非阻塞

    阻塞和非阻塞Web框架 只有Tornado和Node.js是异步非阻塞的,其他所有的web框架都是阻塞式的. Tornado阻塞和非阻塞两种模式都支持. 阻塞式: 代表:Django.Flask.To ...

  5. tornado 之 异步非阻塞

    异步非阻塞 1.基本使用 装饰器 + Future 从而实现Tornado的异步非阻塞 import tornado.web import tornado.ioloop from tornado im ...

  6. Tornado之异步非阻塞

    同步模式:同步模式下,只有处理完前一个任务下一个才会执行 class MainHandler(tornado.web.RequestHandler): def get(self): time.slee ...

  7. Tornado之自定义异步非阻塞的服务器和客户端

    一.自定义的异步非阻塞的客户端 #!/usr/bin/env python # -*- coding: utf8 -*- # __Author: "Skiler Hao" # da ...

  8. python-自定义异步非阻塞爬虫框架

    api import socket import select class MySock: def __init__(self, sock, data): self.sock = sock self. ...

  9. Python web框架 Tornado(二)异步非阻塞

    异步非阻塞 阻塞式:(适用于所有框架,Django,Flask,Tornado,Bottle) 一个请求到来未处理完成,后续一直等待 解决方案:多线程,多进程 异步非阻塞(存在IO请求): Torna ...

随机推荐

  1. 三、Django之请求与响应-Part 1

    一.新建项目 进入你指定的项目保存目录,然后运行下面的命令: $ django-admin startproject mysite 这将在目录下生成一个mysite目录,也就是你的这个Django项目 ...

  2. openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 一

    openstack-r版(rocky)搭建基于centos7.4 的openstack swift对象存储服务 一 openstack-r版(rocky)搭建基于centos7.4 的openstac ...

  3. 152.[LeetCode] Maximum Product Subarray

    Given an integer array nums, find the contiguous subarray within an array (containing at least one n ...

  4. Material Safety Data Sheet,MSDS - 化学品安全说明书

    化学品安全说明书(Material Safety Data Sheet)MSDS,国际上称作化学品安全信息卡,是化学品生产商和经销商按法律要求必须提供的化学品理化特性(如PH值,闪点,易燃度,反应活性 ...

  5. loadrunner socket协议问题归纳(6)

    首先让我们先看一下loadrunner- winsock 函数 一览表: lrs_accept_connection 接受侦听套接字连接 lrs_close_socket 关闭打开的套接字       ...

  6. js操作对象属性值为字符串

    今天在项目开发中遇到一个没遇到过的问题,这个问题是需要对比两个对象a和b,a是一个只有一个属性的对象,b是一个含有多个属性对象,如果b中包含和a一模一样的属性名和值,则把这个一样的属性和值从b中删除了 ...

  7. “Hello World!“”团队第五周召开的第二次会议

    今天是我们团队“Hello World!”团队第五周召开的第二次会议.也祝大家双十一快乐~~博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七 ...

  8. CS小分队第一阶段冲刺站立会议(5月11日)

    昨日成果:完成了倒计时器的制作,为其添加了声音:并对扫雷游戏的失败添加了动态效果: 遇到的困难:把图片放入picturebox中无法改变图片的大小,音乐格式只能使用.wav,该格式音乐比较大,增加了整 ...

  9. 2018软工实践—Alpha冲刺(6)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试服务器并行能力 学习MSI.CUDA ...

  10. OOP 学习笔记汇总

    1.1 引用 1.2 const关键字 1.3 动态内存分配 1.4 内联函数和重载函数函数参数缺省值 1.5 类和对象的基本概念与用法1 2.1 类和对象的基本概念2