开发简单的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是客户 ...
随机推荐
- selenium测试报告(含通过率统计图和失败截图)
前言: 介绍的是含饼状统计图及失败截图的测试报告文件. 原文地址:https://testerhome.com/topics/9984 此版本增加了如下功能 测试报告完全汉化,包括错误日志的中文处理 ...
- PCB布线经验
查看: 3645|回复: 11 [经验] PCB设计经验(1)——布局基本要领 [复制链接] ohahaha 927 TA的帖子 0 TA的资源 纯净的硅(中级) 发消息 加好友 电 ...
- 面向对象之final关键字
1.1 final的概念 final是个修饰符,它可以用来修饰类,类的成员,以及局部变量.不能修饰构造方法. 问题: 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之 ...
- Redis高级应用——2
Redis-事务 Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: 事务是一个单独的隔离操作,事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的 ...
- how browser works
https://developers.google.com/speed/articles/reflow http://blog.letitialew.com/post/30425074101/repa ...
- const限定符用法汇总
const限定符限定变量的类型是一个常量,对象一旦创建后其值就无法改变,所以const对象必须初始化. 初始化 const int i = get_size(); //运行时初始化 const int ...
- loj2230 「BJOI2014」大融合
LCT裸题 我LCT学傻了这题明显可以树剖我不会树剖了 本来的siz是Splay上的子树和,并没有什么用. 所以每个点维护虚子树和和子树和 虚子树和即虚边连接的子树和,且只有在access和link操 ...
- 【项目管理】 使用IntelliJ IDEA 将项目发布(提交)到GitLab
https://blog.csdn.net/zsq520520/article/details/51004721 gitlab地址: http://192.168.1.81:200 idea项目p ...
- Python之面向对象的组合、多态、菱形问题、子类中重用父类的两种方式
一.组合 ''' 1.什么是组合 组合就是一个类的对象具备某一个属性,该属性的值是指向另外一个类的对象 2.为何用组合 组合也是用来解决类与类直接代码冗余问题的 3.如何用组合 ''' # 继承减少代 ...
- 底部线条css样式
1.首先固定宽高 (将文字移至左边,例如 “姓名:”) .line{ width:100%; height:40px; float:left; border-bottom:1px solid #ccc ...