开发简单的IO多路复用web框架

自制web框架

1、核心IO多路复用部分

image

 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
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()
app.py

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

 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()
core/main.py
 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()
app.py

 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()
core/main.py
 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()
app.py

 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()
core/main.py
 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()
app.py

超时

自定制stop

 

 参考

http://www.cnblogs.com/wupeiqi/p/6536518.html

posted @ 2018-12-06 18:12  fat39  阅读(318)  评论(0编辑  收藏  举报