Python-web:web服务器+动态资源‘框架’1
程序员文章站
2022-07-15 11:16:06
...
前:
服务器的种类有很多比如Nginx、Apache等等,这涉及到了服务器的性能,故有了服务器自己的技术,那么如何让自己的动态资源框架实现忽略这些不同的web服务器呢,于是就有了WSGI协议。
web服务器+动态资源‘框架’ 模拟
1.文件结构图:
2.参考代码
web_server.py
# 让web服务器支持WSGI协议
# 面对对象的方式
# 多进程实现
# 补充知识点:F5是刷新(不过很多时候都是用的浏览器缓存);用ctrl+r 强制刷新。
import socket, re
import multiprocessing
import time
# import dynamic.mini_frame
from dynamic import mini_frame
class WSGIServer(object):
def __init__(self):
""" 初始化服务器的各项内容 """
# 1. 创建监听套接字
self.tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#此处可以加一句,资源立即释放的语句(略)
# 2.绑定信息
local_ip = ""
local_port = 5000
local_addr = (local_ip, local_port)
self.tcp_socket_server.bind(local_addr)
# 3.设置为监听模式
self.tcp_socket_server.listen(128)
# 给新连接进来的客户端返回一个html页面
def communicate(self, new_socket, client_addr):
# (1).将收到的客户端请求先解码,以便后续代码中提取想要的具体请求页面
request = new_socket.recv(1024).decode('utf-8')
print(request," [from:{}".format(client_addr))
# (2).将已经解码变为字符串的request进行切割
request_lines = request.splitlines()
# print(request_lines)
# (3).从列表中取得想要的东西,浏览器想要的文件名
# GET /index.html HTTP/1.1
# 这个正则又看不懂了。得查。
# ^ :不是后面的字符
# 把需要的用括号括起来
# 防止没有flie_name ,先设为空字符串
file_name = ""
print(">>>>>>",request_lines)
if request_lines:
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
print("*"*50, file_name)
if file_name == '/':
file_name = '/index.html'
# 返回http格式的数据,给浏览器
# 如果请求的资源不是以.py结尾,那么就认为是静态资源(html/css/js/png,JPG等)
if not file_name.endswith('.py'):
# 打开请求的文件, 由于不一定有文件,所以用try except
try:
f = open("./static" + file_name, 'rb')
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "-----no page-----"
new_socket.send(response.encode('utf-8'))
else:
html_content = f.read()
f.close()
# 准备要发送给浏览器的数据
response = "HTTP/1.1 200 ok\r\n"
response += "\r\n"
new_socket.send(response.encode('utf-8')) # 发送head
new_socket.send(html_content) #
else:
# 如果是以.py结尾,那么就认为是动态资源的请求
env = dict()
env['PATH_INFO'] = file_name
body = mini_frame.application(env, self.set_response_header)
header = "HTTP/1.1 %s \r\n" % self.status
for temp in self.headers:
header += "%s:%s\r\n"%(temp[0], temp[1])
header += "\r\n"
response = header + body
#发送response给浏览器
new_socket.send(response.encode('utf-8'))
new_socket.close()
def set_response_header(self, status, headers):
self.status = status
self.headers = [('server', 'mini_web v8.8')]
self.headers += headers
# 充当http server
def fun_forever(self):
# 4.准备接客
while True:
print("等待连接...")
# (1) accept等待连接,等待到连接后返回新创建的套接字和连接进来的客户端地址
new_socket, client_addr = self.tcp_socket_server.accept()
# (2) (使用多进程的方式)调用communicate(返回给连接进来的客户端一个html页面)
p = multiprocessing.Process(target=self.communicate, args=(new_socket, client_addr))
p.start()
# 注!为什么这里要用new_socket.close(),因为在用多进程去实现时,子进程是复制了父进程的资源
new_socket.close()
# 6.正常的程序流程要关闭套接字
self.tcp_socket_server.close()
def main():
""" 控制整体, 创建一个web服务器对象,然后调用这个对象的run_forever方法运行 """
wsgiserver = WSGIServer()
wsgiserver.fun_forever()
if __name__ == "__main__":
main()
mini_frame.py
def login():
return "login!"
def index():
with open("./templates/index.html", 'r') as ref:
return ref.read()
def introduce():
with open("./templates/introduce.html", 'r') as ref:
return ref.read()
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
file_name = environ["PATH_INFO"]
if file_name == '/login.py':
return login()
elif file_name == '/index.py':
return index()
elif file_name == '/introduce.py':
return introduce()
else:
return "no page!"
3.展示
小结
理解这个,有助于下一步flask框架的学习。
下一篇: leetcode.53最大子序和