概述 【wbe后台原理|python-web】本文是简单web服务程序,采用进程发并发实现请求处理,采用进程队列保证数据一致性,即完成不同进程间的同步
- 监听socket,用于监听并接受http请求的tcp连接
- 服务程序,用于处理http请求
- 通信socket用于与请求浏览器通信
- 多进程调度并发处理请求
效果如下图:
文章图片
文章图片
- 对请求头进行分析,采用re正则表达式取出请求内容
# GET /index.html HTTP/1.1
ret = re.match(r"[^/]+(/[^ ]*)", request_line[0])
flie_name = ret.group(1)
- 判断请求类型是否为静态文件,若为静态文件则在静态文件夹寻找该文件,将该文件通过socket发送给客户端,若为动态请求则查询路由表找到对应请求的服务
#访问静态文件
if not flie_name.endswith(".py"):
#读取静态文件并发送
pass
#get访问
else:
func = URL_FUNC_DICT[flie_name]
- 利用装饰器构建路由字典
URL_FUNC_DICT = dict() #路由字典
#闭包
def route(url):
def set_func(func):
URL_FUNC_DICT[url] = func
def call_func(*args, **kwargs):
return func(*args, **kwargs)
return call_func
return set_func@route("/index.py") #装饰器
def index():
with open("./html/index.html") as f:
content = f.read()
return content
整个服务程序参考源码
'''路由'''
# _*_coding:utf-8 _*_
'''
URL_FUNC_DICT =
{
"/index.py":index,
"/login.py":login
}
'''
URL_FUNC_DICT = dict()def route(url):
def set_func(func):
URL_FUNC_DICT[url] = func
def call_func(*args, **kwargs):
return func(*args, **kwargs)
return call_func
return set_func@route("/index.py")
def index():
with open("./html/index.html") as f:
content = f.read()
return content@route("/login.py")
def login():
return b"logining!..."'''服务程序'''
def server(new_socket, static,flag=False):
# 获取浏览器数据,GET/HTTP/1.1
overtime = 500
if flag:overtime=0
new_socket.setblocking(False)#解阻塞
begin = time.time()
while True:
request = new_socket.recv(1024).decode("utf-8")
print(request)
if request == b'': break
request_line = request.splitlines()
print(">>>" * 50)
# GET /index.html HTTP/1.1
flie_name = ""
ret = re.match(r"[^/]+(/[^ ]*)", request_line[0])
if ret:
flie_name = ret.group(1)
if flie_name == "/":
flie_name = "/index.html"
#访问静态文件
if not flie_name.endswith(".py"):
try:
f = open(static + flie_name, 'rb')
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
else:
response = "HTTP/1.1 200 OK\r\n\r\n"
new_socket.send(response.encode("utf-8"))
for each_connect in f.readlines():
new_socket.send(each_connect)
f.close()
#get访问
else:
#请求头
status = '200 OK'
headers = ('Contene-Type', 'text/html;
charset=utf-8')
print(flie_name)
try:
func = URL_FUNC_DICT[flie_name]
body = func()
header = "HTTP/1.1 %s\r\n" % status
for temp in headers:
header += "%s:%s\r\n" % (temp[0], temp[1])
header += "\r\n"
response = header + body
except Exception as ret:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
new_socket.send(response.encode('utf-8'))
#超时退出
if overtime <= 0:break
else: overtime = overtime-int(time.time() - begin)
new_socket.close()
调度程序(wbe类)
- 建立进程池,用于并发服务,建立进程队列用于进程通信
pool = multiprocessing.Pool(5)
queue = multiprocessing.Manager().Queue(10)
2.创建socket并进行初始化
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server_socket.bind(("", port))
tcp_server_socket.listen(128)
#非阻塞
tcp_server_socket.setblocking(False)
参考源码
class Web(object):
def __init__(self, port, static):
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.tcp_server_socket.bind(("", port))
self.tcp_server_socket.listen(128)
#非阻塞
self.tcp_server_socket.setblocking(False)
self.static = static#静态文件目录
self.pool = multiprocessing.Pool(5)#进程池
self.queue = multiprocessing.Manager().Queue(10)#进程队列
self.__isStop = Truedef __del__(self):
self.stop()
self.tcp_server_socket.close()
self.queue.clear()
# 进程池停止接受新的任务
self.pool.close()
# 等待进程结束
self.pool.join()def stop(self):
self.__isStop = False
while not self.queue.empty():
self.pool.apply_async(server, (self.queue.get(), self.static,True))
def run_forever(self):
while self.__isStop:
try:
new_socket, client_addr = self.tcp_server_socket.accept()
self.queue.put(new_socket)
except Exception as e: pass
finally:
if not self.queue.empty():
work_socket = self.queue.get()
#进程调度
self.pool.apply_async(server, (work_socket, self.static, False))
else:
pass
最后补上main函数调用
def main():
#用于配置静态目录{"static":"./html",}
with open("./server.cnf") as f:
config_info = eval(f.read())
if len(sys.argv) == 2:
try:
port = int(sys.argv[1])
print(port)
except Exception as ret:
print("端口输入错误!!")
else:
port = 7890
print("使用python server.py 端口号 ")
minwbe = Web(port, config_info["static"])
minwbe.run_forever()