开发简单的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是客户 ...
随机推荐
- 解决Mac外接显示器经常没反应
问题描述 最近在使用绿联扩展坞的时候,发现连接显示器时,有时插上后可以正常使用,有时插上后显示器没反应. 解决办法 经过一段时间的尝试,发现这样操作可以避免出现这种问题: 关机的时候: 从转换器拔掉H ...
- tp5简要
1.实例化模型 namespace app\web\controller; use think\Controller; use app\web\model\Member; use think\Load ...
- selenium 无界面跑UI脚本
from selenium.webdriver.chrome.options import Options from selenium import webdriver import time chr ...
- ORA-00600: internal error code, arguments: [kcratr_nab_less_than_odr], [1], [1498], [18713], [18720]
数据库server出现ORA-00600[kcratr_nab_less_than_odr].不能open数据库 1.open数据库报ORA-00600[kcratr_nab_less_than_od ...
- Eclipse设置格式化每行字符的长度
Windows>>prefrence>>Java>>CodeStyle>>formatter>>edit>>line wrapp ...
- SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_'
SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_' 错误:select * from emp where ename like '%SML_%' 正确:select * from em ...
- mysql数据库使用insert语句插入中文数据报错
在mysql的命令行模式中,通过insert语句插入中文数据的时候报错,类似于下面这样: Incorrect string value: '\xE7\x8F' for column 'name' at ...
- 十七、S3C2440 音频解码芯片WM8976声卡驱动移植、madplay测试
学习目标:1. WM9876接口和工作原理:2. WM9876驱动移植:3. WM9876应用测试:4. 问题总结 1. WM9876接口和工作原理 本节使用了JZ2440开发板移植WM9876驱动 ...
- AGC 005 D - ~K Perm Counting
D - ~K Perm Counting 链接 题意: 求有多少排列对于每个位置i都满足$|ai−i|!=k$.n<=2000 分析: 容斥+dp. $answer = \sum\limits_ ...
- IDEA/Git 设置多个push远程仓库或者同时提交多个push仓库
注:写在最上面的这个提交地址将会是唯一的pull地址 具体解决办法: 在隐藏文件.git 下有个config文件,打开,在最后一行添加以下信息 [remote "all"] url ...