用Python做一个Web服务器和Web框架

首先说下这个程序的整体设计思想

程序的分为三大块
Web服务器,web框架,还有模板
Web服务器是由socket模块做的
Web框架和web服务器之间的数据传送是基于WSGI协议
由于web服务器要同时能接受多个用户的访问 ,所以就用了进程

不知道大家独一WSGI协议了解不了解这里简单说下
Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。
他的工作流程是这样的
在这里插入图片描述

就是说当一个浏览器访问这个网站时,首先给这个网站服务器发送一个请求,然后服务器接收到这个请求后,服务器调用application这个函数,这个函数接受两个参数,一个是字典,一个是一个服务器中的一个start_response函数的引用,env字典中装的是浏览器发过来的路径,这个函数中有两个参数需要传递,一个状态码,一个是内容类型,当服务器调用application这个函数时,就会运行web框架中的application函数 ,然后web框架中的application根据env字典中的路径找到相应的模板,start_response中这个函数需要接受两个参数,此时传递给他,然后将模板中的内容和start_response接受到的两个参数传递给服务器,然后服务器在发送给浏览器

```python、
# Web服务器
import socket
import re
import multiprocessing
import time, sys
# from danamic import mini_frame


class WSGIServer(object):

    def __init__(self, port, app, conf_info):
        # 创建套接字
        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.application = app
        self.conf_info = conf_info

    def service_client(self, new_socket):
        # 接受浏览器发送过来的请求
        request = new_socket.recv(1024).decode("utf-8")

        request_lines = request.splitlines()
        print("")
        print(">"*20)
        print(request_lines)
        file_name = ""
        ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
        print(ret, "+"*20)
        if ret:
            file_name = ret.group(1)
            if file_name == "/":
                file_name = "/index.html"

        # 返回HTTP格式的数据,给浏览器
        if not file_name.endswith(".py"):
            print(file_name, "+"*50)
            try:
                 f = open(self.conf_info + file_name, "rb")
                 print(f, "+"*50)
            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()
                #  返回HTTP格式的数据给浏览器
                response = "HTTP/1.1 200 OK\r\n"
                response += "\r\n"
                # 将response.header 发送给浏览器
                new_socket.send(response.encode("utf-8"))
                new_socket.send(html_content)
        else:
            env = dict()
            env["PATH_INFO"] = file_name
            body = self.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
            new_socket.send(response.encode("utf-8"))

        new_socket.close()

    def set_response_header(self, starts, headers):
        self.status = starts
        self.headers = [("Server","mini_web v8.8")]
        self.headers += headers

    def server_run(self):
        while True:
            #   等待新的客户端连接
            new_socket, client_addr = self.tcp_server_socket.accept()
            # 为这个客户端服务
            p = multiprocessing.Process(target=self.service_client, args=(new_socket,))
            p.start()
            new_socket.close()

        self.tcp_server_socket.close()


def main():

    if len(sys.argv) == 3:
        try:
            port = int(sys.argv[1])
            frame_app_name = sys.argv[2]
        except Exception as ret:
            print("端口输入错误")
            return
    else:
        print("请以一下方式运行")
        print("python web_server.py 7890 mini_frame:application")
        return

    ret = re.match(r"([^:]+):(.*)", frame_app_name)
    if ret:
        frame_name = ret.group(1)
        app_name = ret.group(2)
    else:
        print("请以一下方式运行")
        print("python web_server.py 7890 mini_frame:application")
        return

    with open("./web_conf.conf") as f:
        conf_info = eval(f.read())

    sys.path.append(conf_info['danamic_path'])
    frame = __import__(frame_name)
    app = getattr(frame, app_name)

    wsgi_server = WSGIServer(port, app, conf_info["static_path"])
    wsgi_server.server_run()


if __name__ == '__main__':
    main()
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("./template/index.html", encoding="utf-8") as f:
        content = f.read()
    return content


@route("/login.py")
def login():
    return "这个是登录页"

# URL_FUNC_DICT = {
#     "/index.py": index,
#     "/login.py": login,
# }


def application(env, start_response):
    start_response("200 OK", [("Content-Type", "text/html;charset=utf-8")])
    file_name = env["PATH_INFO"]

    # if file_name == "/index.py":
    #     return index()
    # elif file_name == "/login.py":
    #     return login()
    # else:
    #     return "Hello World 我爱你"
    try:
        # func = URL_FUNC_DICT[file_name]
        # return func()
        return URL_FUNC_DICT[file_name]()
    except Exception as ret:

        print("产生异常%s" % str(ret))
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值