开发简单的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是客户 ...
随机推荐
- springboot项目打war包pom设置
<build> <finalName>PayManager</finalName><!--打包后的名字PayManager.war--> <plu ...
- HDU 1074 Doing Homework 状压dp(第一道入门题)
Doing Homework Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
- listener.ora 与 tnsnames.ora
listener.ora 是oracle服务器端的网络配置文件,oracle 根据它来配置监听服务. tnsnames.ora 类似于unix 的hosts文件,提供的tnsname到主机名或者ip的 ...
- SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_'
SQL语句查询关键字中含有特殊符号怎么处理, 例如 'SMI_' 错误:select * from emp where ename like '%SML_%' 正确:select * from em ...
- Oracle 12.2 报错:ORA-12012: error on auto execute of job "SYS"."ORA$AT_OS_OPT_SY_7458"
alert报错 2019-01-12T10:10:11.499130+08:00Errors in file /u01/app/oracle/diag/rdbms/rac1/rac112/trace/ ...
- 基于vue-cli3和追书神器制作的移动端小说阅读网站,附接口和源码
项目简介 基于node express+mysql+vue-cli3和追书神器接口制作的移动端小说阅读网站,**仅供参考学习!不用于任何商业用途!** 闲暇时间用vue练练手,就想写个小说网站来看看, ...
- 使用zabbix发送邮件的简易设置流程(存档用)
1.安装邮件软件 (一般默认安装sendmail,这样apache也不用重新设置.) $sudo yum install sendmail 2.在zabbix上设置发送邮件用的本地邮箱 选择管理-&g ...
- 性能测试loadrunner安装
把杀毒软件关闭 1. 点击 HP_LoadRunner_12.02_Community_Edition_T7177-15059.exe 完成后,点击下一步 接受协议 点击安装 点击完成 TOOLS - ...
- LZO压缩算法64位崩溃问题
*** vs2013 64位调用LZO算法失败,原因: vs2013 long 类型4位 指针为8位. 解决: 将static lzo_bool basic_ptr_check(void)函数中,指针 ...
- Mysql linux 安装文档
1.安装依赖包 yum -y install gcc-c++ ncurses-devel cmake make perl gcc autoconf automake zlib libxml libgc ...