天天看点

Python mini服务器框架设计范例,实现wsgi协议!

本次展示的是一个mini_web服务器及对应的框架设计及其思路.

分服务器跟框架两次源代码.实现wsgi协议!

一.相关知识点:

1.静态与动态

    1.静态:从硬盘直接读取内容返回不做修改就静态,其他都是动态

2.wsgi协议

    用来规定框架与服务器之间的数据传递方式,

    作用:让不同的服务器与框架进行无缝对接,不需要更改代码

    def application(env,respons_fun[函数的引用]):

        env用来获取服务器传过来的数据

        response_fun("200 ok",[(字段前部分[content-type],后部分[text/html;charset=utf-8])]

        上面的作用是给服务器传数据的(头部字段)

        return 这个是body的数据

3.如果ifelse超过三个请使用字典的方式去更换

4.如何让我们的函数引用跟地址绑定在一起,我们使用装饰器传参的方式

def route(file_name):
    def set_fun(func):
        def call_fun(*args, **kwargs)"

        return func(*args, **kwargs)

    return call_fun


return set_fun


@route("/index.html")
def add():
    pass
           

二.服务器代码:

import socket
import re
import multiprocessing

import mini_web_09

class WebServer(object):
	def __init__(self):
		"""初始化套接字"""
		# 创建套接字
		self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

		# 2. 绑定
		self.tcp_server_socket.bind(("", 5566))

		# 3. 变为监听套接字
		self.tcp_server_socket.listen(128)

	def service_client(self, new_socket):
		"""为这个客户端返回数据"""

		# 1. 接收浏览器发送过来的请求 ,即http请求
		# GET / HTTP/1.1
		# .....
		request = new_socket.recv(1024).decode("utf-8")
		# print(">>>"*50)
		# print(request)

		request_lines = request.splitlines()
		print("")
		print(">" * 20)
		print(request_lines)

		# GET /index.html HTTP/1.1
		# get post put del
		file_name = ""
		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"

		# 这里拿到文件(路径/index.html),如果是.py结尾,那么我们手动去返回数据  jsp action do py php
		if file_name.endswith(".py"):
			# 创建一个字典
			url_dict = dict()

			url_dict['file_name'] = file_name
			body = mini_web_09.application(url_dict,self.head_fun)


			# python手动返回的数据
			head = "HTTP/1.1 %s\r\n"%self.stauts  #使用框架传过来的头

			#把框架的所有头字段拼接
			for temp in self.params:
				head += "%s:%s\r\n"%(temp[0],temp[1])




			#数据拼接
			content = head + "\r\n" + body

			new_socket.send(content.encode("utf-8"))

		else:

			# 2. 返回http格式的数据,给浏览器

			try:
				f = open("./html" + file_name, "rb")
			except:
				response = "HTTP/1.1 404 NOT FOUND\r\n"
				response += "\r\n"
				response += "------file not found-----"
				new_socket.send(response.encode("utf-8"))
			else:
				html_content = f.read()
				f.close()
				# 2.1 准备发送给浏览器的数据---header
				response = "HTTP/1.1 200 OK\r\n"
				response += "\r\n"
				# 2.2 准备发送给浏览器的数据---boy
				# response += "hahahhah"

				# 将response header发送给浏览器
				new_socket.send(response.encode("utf-8"))
				# 将response body发送给浏览器
				new_socket.send(html_content)

		# 关闭套接
		new_socket.close()

	def run_server(self):
		"""用来完成整体的控制"""

		while True:
			# 4. 等待新客户端的链接
			new_socket, client_addr = self.tcp_server_socket.accept()

			# 5. 为这个客户端服务
			p = multiprocessing.Process(target=self.service_client, args=(new_socket,))
			p.start()

			new_socket.close()

		# 关闭监听套接字
		tcp_server_socket.close()

	#这里定义一个函数
	def head_fun(self,stauts,params):
		#把框架传的值存起来
		self.stauts = stauts
		self.params = params


def main():
	# 创建一个对象
	server = WebServer()
	# 开启服务
	server.run_server()


if __name__ == "__main__":
	main()
           

三.对应上述服务器编写的实现wsgi协议的框架.

#创建一个空字典
import re

func_dic = dict()

def route(file_name):
    print("file_name",file_name)
    def set_fun(func):
        print("函数")
        def call_fun(*args,**kwargs):
            return func(*args,**kwargs)

        #让系统自动把地址 跟引用关联起来
        func_dic[file_name] =  call_fun
        return call_fun

    return set_fun

@route("/index.py")
def index():
    return "首页"

@route("/regedit.py")
def regeid():
    return "注册"



@route("/center.py")
def center():
    return "个人中心"

@route("/login.py")
def login():
    return "登陆 "


@route("/add/(\d+).py")#/add/0908.py
def add_fun():
    return "添加"

#aop切面编程

#这个就是wsgi协议
#environ:这个参数就是服务器给框架传参数,这个服务器传框架有可能会有多个参数,我们使用字典
#start_response:给服务器传数据
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8'),("author","yzm")])

    file_name = environ['file_name']  #得到路径

    #去我们地址字典中去用正则去查找对应的地址
    for key,func in func_dic.items():
        match = re.match(key, file_name)#用地址正则去匹配路径
        if match:
            #匹配到了
            return func()

    #匹配完了还有没有找到
    body = "not page is find!"

    return body #返回到我们的页面内容