自制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框架的更多相关文章

  1. python运维开发(十七)----jQuery续(示例)web框架django

    内容目录: jQuery示例 前端插件 web框架 Django框架 jQuery示例 dom事件绑定,dom绑定在form表单提交按钮地方都会绑定一个onclick事件,所有查看网站的人都能看到代码 ...

  2. python 全栈开发,Day66(web应用,http协议简介,web框架)

    一.web应用 web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...

  3. 第六模块: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 ...

  4. python3开发进阶-Web框架的前奏

    我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 1.自定义web框架 import socket ...

  5. 读《架构探险——从零开始写Java Web框架》

    内容提要 <架构探险--从零开始写Java Web框架>首先从一个简单的 Web 应用开始,让读者学会如何使用 IDEA.Maven.Git 等开发工具搭建 Java Web 应用:接着通 ...

  6. [转]轻量级 Java Web 框架架构设计

    工作闲暇之余,我想设计并开发一款轻量级 Java Web 框架,看看能否取代目前最为流行的而又越来越重的 Spring.Hibernate 等框架.请原谅在下的大胆行为与不自量力,本人不是为了重造轮子 ...

  7. Web框架本质及第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

  8. WEB框架-Django框架学习-预备知识

    今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...

  9. django——web框架简介

    1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式C/S.B/S.C/S是客户 ...

随机推荐

  1. 解决Mac外接显示器经常没反应

    问题描述 最近在使用绿联扩展坞的时候,发现连接显示器时,有时插上后可以正常使用,有时插上后显示器没反应. 解决办法 经过一段时间的尝试,发现这样操作可以避免出现这种问题: 关机的时候: 从转换器拔掉H ...

  2. tp5简要

    1.实例化模型 namespace app\web\controller; use think\Controller; use app\web\model\Member; use think\Load ...

  3. selenium 无界面跑UI脚本

    from selenium.webdriver.chrome.options import Options from selenium import webdriver import time chr ...

  4. 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 ...

  5. Eclipse设置格式化每行字符的长度

    Windows>>prefrence>>Java>>CodeStyle>>formatter>>edit>>line wrapp ...

  6. SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_'

    SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_' 错误:select * from emp  where ename like '%SML_%' 正确:select * from em ...

  7. mysql数据库使用insert语句插入中文数据报错

    在mysql的命令行模式中,通过insert语句插入中文数据的时候报错,类似于下面这样: Incorrect string value: '\xE7\x8F' for column 'name' at ...

  8. 十七、S3C2440 音频解码芯片WM8976声卡驱动移植、madplay测试

    学习目标:1. WM9876接口和工作原理:2. WM9876驱动移植:3. WM9876应用测试:4. 问题总结 1. WM9876接口和工作原理  本节使用了JZ2440开发板移植WM9876驱动 ...

  9. AGC 005 D - ~K Perm Counting

    D - ~K Perm Counting 链接 题意: 求有多少排列对于每个位置i都满足$|ai−i|!=k$.n<=2000 分析: 容斥+dp. $answer = \sum\limits_ ...

  10. IDEA/Git 设置多个push远程仓库或者同时提交多个push仓库

    注:写在最上面的这个提交地址将会是唯一的pull地址 具体解决办法: 在隐藏文件.git 下有个config文件,打开,在最后一行添加以下信息 [remote "all"] url ...