自制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. Spring源码分析(十二)FactoryBean的使用

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 一般情况下,Spring通过反射机制利用bean的class属性指定实现 ...

  2. (未解决)记录一次登录&jmeter,留下的一地鸡毛

    一般的登录校验过程是这样的:客户端发起请求,拿到服务器给的“令牌”,再次发起请求,服务器验证“令牌”是否正确,从而返回给客户端是登录成功还是登录失败.然后我按照这个流程,用jmeter去模拟了登录过程 ...

  3. linux 学习第十八天学习(DNS分离解析、DHCP配置、邮件服务配置)

    DNS分离解析技术 yum install bind-chroot systemctl restart named systemctl enable named vim /etc/named.conf ...

  4. spark上的一些常用命令(一)

    1. 加速跑 spark-sql --name uername --num-executors --driver-memory 8G --executor-memory 8G 2. 上传数据 建表 ) ...

  5. 用NI的数据采集卡实现简单电子测试之3——绘制二极管V-I特性曲线图

    本文从本人的163博客搬迁至此. 接下来用USB-6009和LabVIEW实现对二极管最重要的特性曲线“V-I特性曲线”的测试和绘制. 一.什么是二极管V-I特性曲线    康华光版的<电子技术 ...

  6. 2017-2018-1 20155232 《信息安全系统设计基础》第十周课堂测试(ch06)补交

    # 2017-2018-1 20155232 <信息安全系统设计基础>第十周课堂测试(ch06)补交 上课时完成测试后在提交的时候,没有提交成功,进行补交. 1.下面代码中,对数组x填充后 ...

  7. css文字环绕

    html: <div class="wrap-div-topSpacer"></div> <div class="wrap-div" ...

  8. JavaWeb总结(十五)

    AJAX(Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)) AJAX的作用是什么? 在无需重新加载整个网页的情况下,能够更新部分网页的技术 ...

  9. Oracle单节点_Grid_Infrastructure_DB_安装过程图解(三/三)

    接上文: Oracle单节点_Grid_Infrastructure_DB_安装过程图解(二/三)

  10. jQuery学习-显示与隐藏

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...