开发简单的IO多路复用web框架
自制web框架
1、核心IO多路复用部分
1 # -*- coding:utf-8 -*- 2 import socket 3 import select 4 5 6 class Snow(): 7 8 def __init__(self): 9 self.inputs = set() 10 11 def run(self,ip="localhost",port=9999): 12 sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 13 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 14 sock.bind((ip,port)) 15 sock.setblocking(False) 16 sock.listen(128) 17 self.inputs.add(sock) 18 19 while True: 20 # 使用select模块达到io多路复用 21 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005) 22 for conn in readable_list: 23 if sock is conn: 24 # 新建连接 25 client,address = conn.accept() 26 client.setblocking(False) 27 self.inputs.add(client) 28 else: 29 # 接收数据get/post 30 recv_bytes = bytes("",encoding="utf-8") 31 while True: 32 try: 33 _recv = conn.recv(8096) 34 recv_bytes += _recv 35 except: 36 # 循环收齐数据后,由于set blocking(False),所以出发except 37 break 38 print(recv_bytes) 39 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")) 40 self.inputs.remove(conn) 41 42 core/main.py
1 # -*- coding:utf-8 -*- 2 3 from core.main import Snow 4 5 if __name__ == '__main__': 6 print("http://127.0.0.1:9999") 7 Snow().run()
2、封装Request/Response类
1 # -*- coding:utf-8 -*- 2 import socket 3 import select 4 5 6 class HttpRequest(): 7 def __init__(self, conn): 8 self.conn = conn 9 self.headers_bytes = bytes("", encoding="utf-8") 10 self.body_bytes = bytes("", encoding="utf-8") 11 self.initial() 12 13 def initial(self): 14 # 接收数据get/post 15 split_flag = False 16 while True: 17 try: 18 _recv_bytes = self.conn.recv(8096) 19 except: 20 # 循环收齐数据后,由于setblocking(False),所以触发except 21 break 22 23 if split_flag: 24 self.body_bytes += _recv_bytes 25 else: 26 self.headers_bytes += _recv_bytes 27 if b"\r\n\r\n" in self.headers_bytes: 28 self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1) 29 split_flag = True 30 31 32 class HttpResponse(): 33 def __init__(self, content=""): 34 self.content = content 35 36 def response(self): 37 return bytes(self.content,encoding="utf-8") 38 39 40 class Snow(): 41 42 def __init__(self): 43 self.inputs = set() 44 45 def run(self, ip="localhost", port=9999): 46 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 47 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 48 sock.bind((ip, port)) 49 sock.setblocking(False) 50 sock.listen(128) 51 self.inputs.add(sock) 52 53 while True: 54 # 使用select模块达到io多路复用 55 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005) 56 for conn in readable_list: 57 if sock is conn: 58 # 新建连接 59 client, address = conn.accept() 60 client.setblocking(False) 61 self.inputs.add(client) 62 else: 63 # 把“接收数据get/post”这个封装到request里 64 response = self.process(conn) 65 conn.sendall(response.response()) 66 self.inputs.remove(conn) 67 68 def process(self,conn): 69 request = HttpRequest(conn) 70 res = HttpResponse("HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}".format(len=len("hello world"), body="hello world")) 71 return res
# -*- coding:utf-8 -*- from core.main import Snow if __name__ == '__main__': print("http://127.0.0.1:9999") Snow().run()
3、增加用户端router
1 # -*- coding:utf-8 -*- 2 import socket 3 import select 4 import re 5 6 class HttpRequest(): 7 def __init__(self, conn): 8 self.conn = conn 9 self.headers_bytes = bytes("", encoding="utf-8") 10 self.body_bytes = bytes("", encoding="utf-8") 11 self.initial() 12 13 def initial(self): 14 # 接收数据get/post 15 split_flag = False 16 while True: 17 try: 18 _recv_bytes = self.conn.recv(8096) 19 except: 20 # 循环收齐数据后,由于setblocking(False),所以触发except 21 break 22 23 if split_flag: 24 self.body_bytes += _recv_bytes 25 else: 26 self.headers_bytes += _recv_bytes 27 if b"\r\n\r\n" in self.headers_bytes: 28 self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1) 29 split_flag = True 30 31 32 33 class HttpResponse(): 34 def __init__(self, content=""): 35 self.content = content 36 self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" 37 38 def response(self): 39 return bytes(self.template.format( 40 len=len(self.content), 41 body=self.content, 42 ),encoding="utf-8") 43 44 45 class Snow(): 46 47 def __init__(self,router): 48 self.router = router 49 self.inputs = set() 50 51 def run(self, ip="localhost", port=9999): 52 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 53 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 54 sock.bind((ip, port)) 55 sock.setblocking(False) 56 sock.listen(128) 57 self.inputs.add(sock) 58 59 while True: 60 # 使用select模块达到io多路复用 61 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005) 62 for conn in readable_list: 63 if sock is conn: 64 # 新建连接 65 client, address = conn.accept() 66 client.setblocking(False) 67 self.inputs.add(client) 68 else: 69 # 把“接收数据get/post”这个封装到request里 70 response = self.process(conn) 71 if isinstance(response,HttpResponse): 72 conn.sendall(response.response()) 73 self.inputs.remove(conn) 74 75 def process(self,conn): 76 request = HttpRequest(conn) 77 header_line1 = str(request.headers_bytes.split(b"\r\n",1)[0],encoding="utf-8") 78 method,url,version = header_line1.split() 79 func = None 80 for kv in self.router: 81 if len(kv) == 2: 82 re_url = kv[0] 83 if re.match(re_url,url): 84 func = kv[1] 85 break 86 if func: 87 return func()
1 # -*- coding:utf-8 -*- 2 3 from core.main import Snow,HttpResponse 4 5 def index(): 6 return HttpResponse("index ok") 7 8 9 router = [ 10 (r"/index/",index), 11 ] 12 13 14 if __name__ == '__main__': 15 print("http://127.0.0.1:9999") 16 Snow(router).run()
4、增加httpnotfound页面
1 # -*- coding:utf-8 -*- 2 import socket 3 import select 4 import re 5 6 7 class HttpRequest(): 8 def __init__(self, conn): 9 self.conn = conn 10 self.headers_dict = dict() 11 self.headers_bytes = bytes("", encoding="utf-8") 12 self.body_bytes = bytes("", encoding="utf-8") 13 self.method = "" 14 self.url = "" 15 self.version = "" 16 17 self.initial() 18 self.initial_headers() 19 20 @property 21 def headers_str(self): 22 return str(self.headers_bytes, encoding="utf-8") 23 24 def initial(self): 25 # 接收数据get/post 26 split_flag = False 27 while True: 28 try: 29 _recv_bytes = self.conn.recv(8096) 30 except: 31 # 循环收齐数据后,由于setblocking(False),所以触发except 32 break 33 34 if split_flag: 35 self.body_bytes += _recv_bytes 36 else: 37 self.headers_bytes += _recv_bytes 38 if b"\r\n\r\n" in self.headers_bytes: 39 self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1) 40 split_flag = True 41 42 def initial_headers(self): 43 header_lines = self.headers_str.split("\r\n") 44 first_line = header_lines[0].split() 45 if len(first_line) == 3: 46 self.method, self.url, self.version = first_line 47 48 for header_line in header_lines: 49 kv = header_line.split(":", 1) 50 if len(kv) == 2: 51 k, v = kv 52 self.headers_dict[k] = v 53 54 55 class HttpResponse(): 56 def __init__(self, content=""): 57 self.content = content 58 self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" 59 60 def response(self): 61 return bytes(self.template.format( 62 len=len(self.content), 63 body=self.content, 64 ), encoding="utf-8") 65 66 67 class HttpNotFound(HttpResponse): 68 69 def __init__(self): 70 super(HttpNotFound, self).__init__('404 Not Found') 71 72 73 class Snow(): 74 75 def __init__(self, router): 76 self.router = router 77 self.inputs = set() 78 self.request = None 79 80 def run(self, ip="localhost", port=9999): 81 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 82 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 83 sock.bind((ip, port)) 84 sock.setblocking(False) 85 sock.listen(128) 86 self.inputs.add(sock) 87 88 try: 89 while True: 90 # 使用select模块达到io多路复用 91 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005) 92 for conn in readable_list: 93 if sock is conn: 94 # 新建连接 95 client, address = conn.accept() 96 client.setblocking(False) 97 self.inputs.add(client) 98 else: 99 # 把“接收数据get/post”这个封装到request里 100 _process = self.process(conn) 101 if isinstance(_process, HttpResponse): 102 conn.sendall(_process.response()) 103 self.inputs.remove(conn) 104 conn.close() 105 else: 106 # 可以做其他操作 107 pass 108 109 except Exception as e: 110 pass 111 finally: 112 sock.close() 113 114 def process(self, conn): 115 self.request = HttpRequest(conn) 116 func = None 117 for route in self.router: 118 if len(route) == 2: 119 if re.match(route[0], self.request.url): 120 func = route[1] 121 break 122 if func: 123 return func(self.request) 124 else: 125 return HttpNotFound()
1 # -*- coding:utf-8 -*- 2 3 from core.main import Snow,HttpResponse 4 5 def index(request): 6 print(request.url) 7 print(request.headers_bytes) 8 print(request.body_bytes) 9 return HttpResponse("index ok") 10 11 12 13 14 router = [ 15 (r"/index/",index), 16 ] 17 18 19 if __name__ == '__main__': 20 print("http://127.0.0.1:9999") 21 Snow(router).run()
5、增加future对象
1 # -*- coding:utf-8 -*- 2 import socket 3 import select 4 import re 5 import time 6 7 class HttpRequest(): 8 def __init__(self, conn): 9 self.conn = conn 10 self.headers_dict = dict() 11 self.headers_bytes = bytes("", encoding="utf-8") 12 self.body_bytes = bytes("", encoding="utf-8") 13 self.method = "" 14 self.url = "" 15 self.version = "" 16 17 self.initial() 18 self.initial_headers() 19 20 @property 21 def headers_str(self): 22 return str(self.headers_bytes, encoding="utf-8") 23 24 def initial(self): 25 # 接收数据get/post 26 split_flag = False 27 while True: 28 try: 29 _recv_bytes = self.conn.recv(8096) 30 except: 31 # 循环收齐数据后,由于setblocking(False),所以触发except 32 break 33 34 if split_flag: 35 self.body_bytes += _recv_bytes 36 else: 37 self.headers_bytes += _recv_bytes 38 if b"\r\n\r\n" in self.headers_bytes: 39 self.headers_bytes, self.body_bytes = self.headers_bytes.split(b"\r\n\r\n", 1) 40 split_flag = True 41 42 def initial_headers(self): 43 header_lines = self.headers_str.split("\r\n") 44 first_line = header_lines[0].split() 45 if len(first_line) == 3: 46 self.method, self.url, self.version = first_line 47 48 for header_line in header_lines: 49 kv = header_line.split(":", 1) 50 if len(kv) == 2: 51 k, v = kv 52 self.headers_dict[k] = v 53 54 55 class HttpResponse(): 56 def __init__(self, content=""): 57 self.content = content 58 self.template = "HTTP/1.1 200 OK\r\nContent-Length: {len}\r\n\r\n{body}" 59 60 def response(self): 61 return bytes(self.template.format( 62 len=len(self.content), 63 body=self.content, 64 ), encoding="utf-8") 65 66 67 class HttpNotFound(HttpResponse): 68 69 def __init__(self): 70 super(HttpNotFound, self).__init__('404 Not Found') 71 72 73 class Future(object): 74 """ 75 异步非阻塞模式时封装回调函数以及是否准备就绪 76 """ 77 def __init__(self, callback): 78 self.callback = callback 79 self._ready = False 80 self.value = None 81 82 def set_result(self, value=None): 83 self.value = value 84 self._ready = True 85 86 @property 87 def ready(self): 88 return self._ready 89 90 91 class TimeoutFuture(Future): 92 """ 93 异步非阻塞超时 94 """ 95 def __init__(self, timeout): 96 super(TimeoutFuture, self).__init__(callback=None) 97 self.timeout = timeout 98 self.start_time = time.time() 99 100 @property 101 def ready(self): 102 current_time = time.time() 103 if current_time > self.start_time + self.timeout: 104 self._ready = True 105 return self._ready 106 107 108 109 class Snow(): 110 111 def __init__(self, router): 112 self.router = router 113 self.inputs = set() 114 self.request = None 115 self.async_request_handler = dict() 116 117 def run(self, ip="localhost", port=9999): 118 print("http://{}:{}".format(ip,port)) 119 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 120 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 121 sock.bind((ip, port)) 122 sock.setblocking(False) 123 sock.listen(128) 124 self.inputs.add(sock) 125 126 try: 127 while True: 128 # 使用select模块达到io多路复用 129 readable_list, writeable_list, error_list = select.select(self.inputs, [], self.inputs, 0.005) 130 for conn in readable_list: 131 if conn is sock: 132 # 新建连接 133 client, address = conn.accept() 134 client.setblocking(False) 135 self.inputs.add(client) 136 else: 137 # 把“接收数据get/post”这个封装到request里 138 _process = self.process(conn) 139 if isinstance(_process, HttpResponse): 140 conn.sendall(_process.response()) 141 self.inputs.remove(conn) 142 conn.close() 143 else: 144 print(_process) 145 # 可以做其他操作 146 self.async_request_handler[conn] = _process 147 self.polling_callback() 148 149 except Exception as e: 150 print(e) 151 pass 152 finally: 153 sock.close() 154 155 def polling_callback(self): 156 for conn in list(self.async_request_handler.keys()): 157 fut = self.async_request_handler[conn] 158 if not fut.ready: 159 continue 160 if fut.callback: 161 ret = fut.callback(self.request,fut) 162 conn.sendall(ret.response()) 163 self.inputs.remove(conn) 164 del self.async_request_handler[conn] 165 conn.close() 166 167 def process(self, conn): 168 self.request = HttpRequest(conn) 169 func = None 170 for route in self.router: 171 if len(route) == 2: 172 if re.match(route[0], self.request.url): 173 func = route[1] 174 break 175 if func: 176 return func(self.request) 177 else: 178 return HttpNotFound()
1 # -*- coding:utf-8 -*- 2 3 from core.main import Snow,HttpResponse,TimeoutFuture,Future 4 5 def index(request): 6 print(request.url) 7 print(request.headers_bytes) 8 print(request.body_bytes) 9 return HttpResponse("index ok") 10 11 12 def async(request): 13 14 obj = TimeoutFuture(5) 15 16 return obj 17 18 19 request_list = [] 20 21 22 def callback(request, future): 23 return HttpResponse(future.value) 24 25 26 def req(request): 27 obj = Future(callback=callback) 28 29 request_list.append(obj) 30 31 return obj 32 33 34 def stop(request): 35 obj = request_list[0] 36 37 del request_list[0] 38 39 obj.set_result('done') 40 41 return HttpResponse('stop') 42 43 44 router = [ 45 (r"/index/",index), 46 (r"/async/",async), 47 (r'/req/', req), 48 (r'/stop/', stop), 49 ] 50 51 52 if __name__ == '__main__': 53 54 Snow(router).run()
超时
自定制stop
参考
http://www.cnblogs.com/wupeiqi/p/6536518.html