开发简单的IO多路复用web框架
自制web框架
1、核心IO多路复用部分

# -*- coding:utf-8 -*-
import socket
import select class Snow(): def __init__(self):
self.inputs = set() def run(self,ip="localhost",port=9999):
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip,port))
sock.setblocking(False)
sock.listen(128)
self.inputs.add(sock) while True:
# 使用select模块达到io多路复用
readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005)
for conn in readable_list:
if sock is conn:
# 新建连接
client,address = conn.accept()
client.setblocking(False)
self.inputs.add(client)
else:
# 接收数据get/post
recv_bytes = bytes("",encoding="utf-8")
while True:
try:
_recv = conn.recv(8096)
recv_bytes += _recv
except:
# 循环收齐数据后,由于set blocking(False),所以出发except
break
print(recv_bytes)
conn.sendall(bytes("HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}".format(len=len("hello world"),body="hello world"),encoding="utf-8"))
self.inputs.remove(conn) core/main.py
core/main.py
# -*- coding:utf-8 -*- from core.main import Snow if __name__ == '__main__':
print("http://127.0.0.1:9999")
Snow().run()
app.py

2、封装Request/Response类
# -*- coding:utf-8 -*-
import socket
import select class HttpRequest():
def __init__(self, conn):
self.conn = conn
self.headers_bytes = bytes("", encoding="utf-8")
self.body_bytes = bytes("", encoding="utf-8")
self.initial() def initial(self):
# 接收数据get/post
split_flag = False
while True:
try:
_recv_bytes = self.conn.recv(8096)
except:
# 循环收齐数据后,由于setblocking(False),所以触发except
break if split_flag:
self.body_bytes += _recv_bytes
else:
self.headers_bytes += _recv_bytes
if b"\r\n\r\n" in self.headers_bytes:
self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1)
split_flag = True class HttpResponse():
def __init__(self, content=""):
self.content = content def response(self):
return bytes(self.content,encoding="utf-8") class Snow(): def __init__(self):
self.inputs = set() def run(self, ip="localhost", port=9999):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.setblocking(False)
sock.listen(128)
self.inputs.add(sock) while True:
# 使用select模块达到io多路复用
readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005)
for conn in readable_list:
if sock is conn:
# 新建连接
client, address = conn.accept()
client.setblocking(False)
self.inputs.add(client)
else:
# 把“接收数据get/post”这个封装到request里
response = self.process(conn)
conn.sendall(response.response())
self.inputs.remove(conn) def process(self,conn):
request = HttpRequest(conn)
res = HttpResponse("HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}".format(len=len("hello world"), body="hello world"))
return res
core/main.py
# -*- coding:utf-8 -*- from core.main import Snow if __name__ == '__main__':
print("http://127.0.0.1:9999")
Snow().run()
app.py不变

3、增加用户端router
# -*- coding:utf-8 -*-
import socket
import select
import re class HttpRequest():
def __init__(self, conn):
self.conn = conn
self.headers_bytes = bytes("", encoding="utf-8")
self.body_bytes = bytes("", encoding="utf-8")
self.initial() def initial(self):
# 接收数据get/post
split_flag = False
while True:
try:
_recv_bytes = self.conn.recv(8096)
except:
# 循环收齐数据后,由于setblocking(False),所以触发except
break if split_flag:
self.body_bytes += _recv_bytes
else:
self.headers_bytes += _recv_bytes
if b"\r\n\r\n" in self.headers_bytes:
self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1)
split_flag = True class HttpResponse():
def __init__(self, content=""):
self.content = content
self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" def response(self):
return bytes(self.template.format(
len=len(self.content),
body=self.content,
),encoding="utf-8") class Snow(): def __init__(self,router):
self.router = router
self.inputs = set() def run(self, ip="localhost", port=9999):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.setblocking(False)
sock.listen(128)
self.inputs.add(sock) while True:
# 使用select模块达到io多路复用
readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005)
for conn in readable_list:
if sock is conn:
# 新建连接
client, address = conn.accept()
client.setblocking(False)
self.inputs.add(client)
else:
# 把“接收数据get/post”这个封装到request里
response = self.process(conn)
if isinstance(response,HttpResponse):
conn.sendall(response.response())
self.inputs.remove(conn) def process(self,conn):
request = HttpRequest(conn)
header_line1 = str(request.headers_bytes.split(b"\r\n",1)[0],encoding="utf-8")
method,url,version = header_line1.split()
func = None
for kv in self.router:
if len(kv) == 2:
re_url = kv[0]
if re.match(re_url,url):
func = kv[1]
break
if func:
return func()
core/main.py
# -*- coding:utf-8 -*- from core.main import Snow,HttpResponse def index():
return HttpResponse("index ok") router = [
(r"/index/",index),
] if __name__ == '__main__':
print("http://127.0.0.1:9999")
Snow(router).run()
app.py

4、增加httpnotfound页面
# -*- coding:utf-8 -*-
import socket
import select
import re class HttpRequest():
def __init__(self, conn):
self.conn = conn
self.headers_dict = dict()
self.headers_bytes = bytes("", encoding="utf-8")
self.body_bytes = bytes("", encoding="utf-8")
self.method = ""
self.url = ""
self.version = "" self.initial()
self.initial_headers() @property
def headers_str(self):
return str(self.headers_bytes, encoding="utf-8") def initial(self):
# 接收数据get/post
split_flag = False
while True:
try:
_recv_bytes = self.conn.recv(8096)
except:
# 循环收齐数据后,由于setblocking(False),所以触发except
break if split_flag:
self.body_bytes += _recv_bytes
else:
self.headers_bytes += _recv_bytes
if b"\r\n\r\n" in self.headers_bytes:
self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1)
split_flag = True def initial_headers(self):
header_lines = self.headers_str.split("\r\n")
first_line = header_lines[0].split()
if len(first_line) == 3:
self.method, self.url, self.version = first_line for header_line in header_lines:
kv = header_line.split(":", 1)
if len(kv) == 2:
k, v = kv
self.headers_dict[k] = v class HttpResponse():
def __init__(self, content=""):
self.content = content
self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" def response(self):
return bytes(self.template.format(
len=len(self.content),
body=self.content,
), encoding="utf-8") class HttpNotFound(HttpResponse): def __init__(self):
super(HttpNotFound, self).__init__('404 Not Found') class Snow(): def __init__(self, router):
self.router = router
self.inputs = set()
self.request = None def run(self, ip="localhost", port=9999):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.setblocking(False)
sock.listen(128)
self.inputs.add(sock) try:
while True:
# 使用select模块达到io多路复用
readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005)
for conn in readable_list:
if sock is conn:
# 新建连接
client, address = conn.accept()
client.setblocking(False)
self.inputs.add(client)
else:
# 把“接收数据get/post”这个封装到request里
_process = self.process(conn)
if isinstance(_process, HttpResponse):
conn.sendall(_process.response())
self.inputs.remove(conn)
conn.close()
else:
# 可以做其他操作
pass except Exception as e:
pass
finally:
sock.close() def process(self, conn):
self.request = HttpRequest(conn)
func = None
for route in self.router:
if len(route) == 2:
if re.match(route[0], self.request.url):
func = route[1]
break
if func:
return func(self.request)
else:
return HttpNotFound()
core/main.py
# -*- coding:utf-8 -*- from core.main import Snow,HttpResponse def index(request):
print(request.url)
print(request.headers_bytes)
print(request.body_bytes)
return HttpResponse("index ok") router = [
(r"/index/",index),
] if __name__ == '__main__':
print("http://127.0.0.1:9999")
Snow(router).run()
app.py

5、增加future对象
# -*- coding:utf-8 -*-
import socket
import select
import re
import time class HttpRequest():
def __init__(self, conn):
self.conn = conn
self.headers_dict = dict()
self.headers_bytes = bytes("", encoding="utf-8")
self.body_bytes = bytes("", encoding="utf-8")
self.method = ""
self.url = ""
self.version = "" self.initial()
self.initial_headers() @property
def headers_str(self):
return str(self.headers_bytes, encoding="utf-8") def initial(self):
# 接收数据get/post
split_flag = False
while True:
try:
_recv_bytes = self.conn.recv(8096)
except:
# 循环收齐数据后,由于setblocking(False),所以触发except
break if split_flag:
self.body_bytes += _recv_bytes
else:
self.headers_bytes += _recv_bytes
if b"\r\n\r\n" in self.headers_bytes:
self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1)
split_flag = True def initial_headers(self):
header_lines = self.headers_str.split("\r\n")
first_line = header_lines[0].split()
if len(first_line) == 3:
self.method, self.url, self.version = first_line for header_line in header_lines:
kv = header_line.split(":", 1)
if len(kv) == 2:
k, v = kv
self.headers_dict[k] = v class HttpResponse():
def __init__(self, content=""):
self.content = content
self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" def response(self):
return bytes(self.template.format(
len=len(self.content),
body=self.content,
), encoding="utf-8") class HttpNotFound(HttpResponse): def __init__(self):
super(HttpNotFound, self).__init__('404 Not Found') 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(): def __init__(self, router):
self.router = router
self.inputs = set()
self.request = None
self.async_request_handler = dict() def run(self, ip="localhost", port=9999):
print("http://{}:{}".format(ip,port))
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((ip, port))
sock.setblocking(False)
sock.listen(128)
self.inputs.add(sock) try:
while True:
# 使用select模块达到io多路复用
readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005)
for conn in readable_list:
if conn is sock:
# 新建连接
client, address = conn.accept()
client.setblocking(False)
self.inputs.add(client)
else:
# 把“接收数据get/post”这个封装到request里
_process = self.process(conn)
if isinstance(_process, HttpResponse):
conn.sendall(_process.response())
self.inputs.remove(conn)
conn.close()
else:
print(_process)
# 可以做其他操作
self.async_request_handler[conn] = _process
self.polling_callback() except Exception as e:
print(e)
pass
finally:
sock.close() def polling_callback(self):
for conn in list(self.async_request_handler.keys()):
fut = self.async_request_handler[conn]
if not fut.ready:
continue
if fut.callback:
ret = fut.callback(self.request,fut)
conn.sendall(ret.response())
self.inputs.remove(conn)
del self.async_request_handler[conn]
conn.close() def process(self, conn):
self.request = HttpRequest(conn)
func = None
for route in self.router:
if len(route) == 2:
if re.match(route[0], self.request.url):
func = route[1]
break
if func:
return func(self.request)
else:
return HttpNotFound()
core/main.py
# -*- coding:utf-8 -*- from core.main import Snow,HttpResponse,TimeoutFuture,Future def index(request):
print(request.url)
print(request.headers_bytes)
print(request.body_bytes)
return HttpResponse("index ok") def async(request): obj = TimeoutFuture(5) return obj request_list = [] def callback(request, future):
return HttpResponse(future.value) def req(request):
obj = Future(callback=callback) request_list.append(obj) return obj def stop(request):
obj = request_list[0] del request_list[0] obj.set_result('done') return HttpResponse('stop') router = [
(r"/index/",index),
(r"/async/",async),
(r'/req/', req),
(r'/stop/', stop),
] if __name__ == '__main__': Snow(router).run()
app.py
超时

自定制stop

参考
http://www.cnblogs.com/wupeiqi/p/6536518.html
开发简单的IO多路复用web框架的更多相关文章
- python运维开发(十七)----jQuery续(示例)web框架django
内容目录: jQuery示例 前端插件 web框架 Django框架 jQuery示例 dom事件绑定,dom绑定在form表单提交按钮地方都会绑定一个onclick事件,所有查看网站的人都能看到代码 ...
- python 全栈开发,Day66(web应用,http协议简介,web框架)
一.web应用 web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...
- 第六模块:WEB框架开发 第1章·Django框架开发1~50
01-Django基础介绍 02-Web应用程序1 03-Web应用程序2 04-http请求协议1 05-http请求协议2 06-http协议之响应协议 07-wsgire模块1 08-wsgir ...
- python3开发进阶-Web框架的前奏
我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 1.自定义web框架 import socket ...
- 读《架构探险——从零开始写Java Web框架》
内容提要 <架构探险--从零开始写Java Web框架>首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA.Maven.Git 等开发工具搭建 Java Web 应用:接着通 ...
- [转]轻量级 Java Web 框架架构设计
工作闲暇之余,我想设计并开发一款轻量级 Java Web 框架,看看能否取代目前最为流行的而又越来越重的 Spring.Hibernate 等框架.请原谅在下的大胆行为与不自量力,本人不是为了重造轮子 ...
- Web框架本质及第一个Django实例
Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...
- WEB框架-Django框架学习-预备知识
今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...
- django——web框架简介
1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式C/S.B/S.C/S是客户 ...
随机推荐
- Python自动化之高级语法单例模式
方法1 共享属性;所谓单例就是所有引用(实例.对象)拥有相同的状态(属性)和行为(方法) 同一个类的所有实例天然拥有相同的行为(方法), 只需要保证同一个类的所有实例具有相同的状态(属性)即可 所有实 ...
- P2983 [USACO10FEB]购买巧克力Chocolate Buying
题目描述 Bessie and the herd love chocolate so Farmer John is buying them some. The Bovine Chocolate Sto ...
- 罗技 HTPC K700
1.下方的 播放,暂停 快进 可以控制midea 2.CTRL+ALT+FN+(PG UP)可开启触控板左键点击功能3.FN(功能键)+左键=右键功能
- 【图像处理】Schmid滤波器
Schmid也是一种类Gabor图像滤波器,在这篇文章[1]中有详细推导和介绍. 一种更简洁的表达公式是: 当中,r为核半径,Z为归一化參数,τ和σ是比較重要的參数,在ReID提取TextFeatur ...
- jQuery----JQuery动画(hide()和show())(上)
hide()和show()方法,可以设置动画效果,本文对这两种方法效果加以说明. hide(参数1,参数2): 参数1:时间,单位为毫秒,表示对象隐藏所用的时间 参数2:回调函数,该函数在对象隐藏后触 ...
- ie中input光标问题
为input 添加 readonly=”readonly” UNSELECTABLE="on" 属性. IE中设置了readonly=”readonly”,点击使用日期选择器 ...
- 关于groupby与层次化索引的联系和层次化标签的使用
groupby出来对象并不是dataFrame,所以直接print是看不到矩阵或者高维矩阵的,所以需要用能够产生标量值的方法去处理groupby对象,这样可以利用矩阵形式处理高维数据: 这样group ...
- 时间戳转为C#格式时间
经常发现很多地方使用一个时间戳表示时间.比如: 1370838759 表示 2013年6月10日 12:32:39. 我们就需要一个工具,方便地转换这种时间格式 什么是时间戳? 时间戳, 又叫Unix ...
- 20145209刘一阳《JAVA程序设计》第四周课堂测试
第四周课堂测试 1.下列说法正确的是(ACD) A .使用extends关键字定义一个类的子类. B .Java与C++类似,支持多继承,即子类可以有一个或多个父类. C .Object是所有类的祖先 ...
- PowerDesigner16.5物理数据表生成C#实体类Model
原文:PowerDesigner16.5物理数据表生成C#实体类Model 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/da454122373/a ...