mini-web框架的实现

mini-web

  • 一、面向对象的多进程web服务器
  • 二、让web服务器支持动态解析
  • 三、将服务器与逻辑处理分开实现解耦
  • 四、让框架支持WSGI协议
    • 1.WSGI协议
    • 2. 版本一
    • 2.版本二:解决WSGI中字典参数并返回响应请求
  • 五、实现模板的替换
  • 六、在运行服务器之前指定框架和端口号
  • 七、让框架支持读取配置文件

一、面向对象的多进程web服务器

"""
webserver.py
使用面向对象的方法来做多进程的web server
"""

import socket
import re
import multiprocessing


class WSGIServer(object):
    """服务器对象"""
    def __init__(self):
        # 创建套接字
        self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定ip和port
        self.tcp_server.bind(("", 8080))
        # 设置成监听模式
        self.tcp_server.listen(128)

    def service_client(self, new_socket):
        # 接受数据
        data = new_socket.recv(1024).decode("utf-8")
        # print(data.decode("utf-8"))
        data_list = data.splitlines()
        # print(data_list[0])

        # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
        ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
        print(ret)
        file_name = ""
        if ret:
            file_name = ret.group(1)
            print(file_name)
            if file_name == "/":
                file_name = "/index.html"
        try:
            # 打开文件
            f = open("..//..//static/html/Trave" + file_name, "rb")
        except:

            response = "HTTP/1.1 404 NOT FOUND\r\n"
            response += "\r\n"
            response += "Not Found"
            # 发送文件 header
            new_socket.send(response.encode("utf-8"))
        else:
            # 传递数据
            response = "HTTP:/1.1 200 OK\r\n"
            response += "\r\n"
            data_contend = f.read()
            f.close()
            # 发送文件 header
            new_socket.send(response.encode("utf-8"))
            # 发送文件body
            new_socket.send(data_contend)
        # 关闭套接字
        new_socket.close()

    def run_forerver(self):
        """使程序一直运行"""
        while True:
            # 等待客户端连接
            new_client, addr = self.tcp_server.accept()
            p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
            # 接受客户端的消息  回复客户端的消息
            # service_client(new_client)
            p.start()
            new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
        self.tcp_server.close()


def main():
    """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
    wsgi_server = WSGIServer()
    wsgi_server.run_forerver()


if __name__ == "__main__":
    main()

二、让web服务器支持动态解析

  1. 解释:当浏览器请求文件以.py结尾的就当做动态网页

  2. 代码

    """
    webserver.py
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", 8080))
            # 设置成监听模式
            self.tcp_server.listen(128)
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    f = open("..//..//static/html/Trave" + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                header = "HTTP:/1.1 200 OK\r\n"
                header += "\r\n"
                
                body = "nihao : %s" % time.ctime()
    
                response = header + body
                # 发送消息
                new_socket.send(response.encode("utf-8"))
            # 关闭套接字
            new_socket.close()
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        wsgi_server = WSGIServer()
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    

三、将服务器与逻辑处理分开实现解耦

  1. 版本一:
    1. webserver.py 服务器代码

      """
      
      使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
      当请求文件结尾以.py结尾的为动态网页
      
      将web框架与逻辑处理的代码分开
      
      """
      
      import socket
      import re
      import multiprocessing
      import time
      import mini_frame
      
      
      class WSGIServer(object):
          """服务器对象"""
          def __init__(self):
              # 创建套接字
              self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
              self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
              # 绑定ip和port
              self.tcp_server.bind(("", 8080))
              # 设置成监听模式
              self.tcp_server.listen(128)
      
          def service_client(self, new_socket):
              # 接受数据
              data = new_socket.recv(1024).decode("utf-8")
              # print(data.decode("utf-8"))
              data_list = data.splitlines()
              # print(data_list[0])
      
              # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
              ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
              print(ret)
              file_name = ""
              if ret:
                  file_name = ret.group(1)
                  print(file_name)
                  if file_name == "/":
                      file_name = "/index.html"
      
              if not file_name.endswith('.py'):
                  try:
                      # 打开文件
                      f = open("..//..//static/html/Trave" + file_name, "rb")
                  except:
      
                      response = "HTTP/1.1 404 NOT FOUND\r\n"
                      response += "\r\n"
                      response += "Not Found"
                      # 发送文件 header
                      new_socket.send(response.encode("utf-8"))
                  else:
                      # 传递数据
                      response = "HTTP:/1.1 200 OK\r\n"
                      response += "\r\n"
                      data_contend = f.read()
                      f.close()
                      # 发送文件 header
                      new_socket.send(response.encode("utf-8"))
                      # 发送文件body
                      new_socket.send(data_contend)
              else:
                  # 以.py结尾的则为动态的获取的页面
                  header = "HTTP:/1.1 200 OK\r\n"
                  header += "\r\n"
                  
                  # body = "nihao : %s" % time.ctime()
                  body = mini_frame.login()
      
                  response = header + body
                  # 发送消息
                  new_socket.send(response.encode("utf-8"))
              # 关闭套接字
              new_socket.close()
      
          def run_forerver(self):
              """使程序一直运行"""
              while True:
                  # 等待客户端连接
                  new_client, addr = self.tcp_server.accept()
                  p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                  # 接受客户端的消息  回复客户端的消息
                  # service_client(new_client)
                  p.start()
                  new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
              self.tcp_server.close()
      
      
      def main():
          """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
          wsgi_server = WSGIServer()
          wsgi_server.run_forerver()
      
      
      if __name__ == "__main__":
          main()
      
    2. mini_frame.py 框架代码

      import time
      
      def login():
      	return "welcom to login this time is : %s" % time.ctime()
      
  2. 版本二
    将框架再一次的分离
    import time
    
    def login():
    	return "welcom to login this time is : %s" % time.ctime()
    
    
    def register():
    	return "welcom to register this time is : %s" % time.ctime()
    
    
    def profile():
    	return "welcom to profile this time is : %s" % time.ctime()
    
    
    def application(file_name):
    	if file_name == "/login.py":
    		return login()
    	elif file_name == "/register.py":
    		return register()
    	elif file_name == "/profile.py":
    		return profile()
    	else:
    		return "no  found file page time: %s" % time.ctime()
    

四、让框架支持WSGI协议

1.WSGI协议

wsgi有两方,服务器方 和 应用程序
服务器方:其调用应用程序,给应用程序提供(环境信息)和(回调函数), 这个回调函数是用来将应用程序设置的http header和status等信息传递给服务器方.
应用程序:用来生成返回的header,body和status,以便返回给服务器方。

2. 版本一

  1. webserver.py

    """
    
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    import mini_frame
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", 8080))
            # 设置成监听模式
            self.tcp_server.listen(128)
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    f = open("..//..//static/html/Trave" + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                # body = "nihao : %s" % time.ctime()
                envs = dict()
                body = mini_frame.application(envs, self.set_response_header)
    
                header = "HTTP:/1.1 %s\r\n" % self.status
                for temp in self.hearers:
                    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, status, headers):
            self.status = status
            self.hearers = [("server:","mini_server v8.8")]
            self.hearers += headers
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        wsgi_server = WSGIServer()
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    
  2. mini_frame.py

    import time
    
    
    def application(environ, start_response):
    	start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    	return ' 中国 hello word time: %s' % time.ctime()
    
    

2.版本二:解决WSGI中字典参数并返回响应请求

  1. webserver.py

    """
    
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    import mini_frame
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", 8080))
            # 设置成监听模式
            self.tcp_server.listen(128)
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    f = open("..//..//static/html/Trave" + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                # body = "nihao : %s" % time.ctime()
                envs = dict()
                envs["PATH_INFO"] = file_name
                # print(envs)
                # 传递一个字典{"PATH_INFO":file_name}
                body = mini_frame.application(envs, self.set_response_header)
    
                header = "HTTP:/1.1 %s\r\n" % self.status
                for temp in self.hearers:
                    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, status, headers):
            self.status = status
            self.hearers = [("server:","mini_server v8.8")]
            self.hearers += headers
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        wsgi_server = WSGIServer()
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    
  2. mini_frame.py

    import time
    
    
    def index():
    	return "这里是首页,时间: %s" % time.ctime()
    
    
    def login():
    	return "这里是登录页面,时间: %s" % time.ctime()
    
    
    
    def application(environ, start_response):
    	start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    	# print(environ)
    	file_name = environ["PATH_INFO"]
    	if file_name == "/index.py":
    		return index()
    	elif file_name == "/login.py":
    		return login()
    	else:
    		return ' 中国 hello word time: %s' % time.ctime()
    
    

五、实现模板的替换

  1. 将mini_frame.py放到dynamic文件夹中

  2. 目录结构 (html可以在网上下载一个就好了)

    │  webserver.py
    │
    ├─dynamic
    │  │  mini_frame.py
    │  │  __init__.py
    │  │
    │  └─__pycache__
    │          mini_frame.cpython-37.pyc
    │          __init__.cpython-37.pyc
    │
    ├─static
    │  ├─css
    │  │      about.css
    │  │      basic.css
    │  │      home.css
    │  │      information.css
    │  │      order.css
    │  │      preview.css
    │  │
    │  └─img
    │      ├─about
    │      │      trea1.png
    │      │      trea2.png
    │      │      trea3.png
    │      │      trea4.png
    │      │
    │      ├─home
    │      │      adver.jpg
    │      │      logo.png
    │      │      tour1.jpg
    │      │      tour2.jpg
    │      │      tour3.jpg
    │      │      tour4.jpg
    │      │      tour5.jpg
    │      │      tour6.jpg
    │      │      tour7.jpg
    │      │      tour8.jpg
    │      │      tour9.jpg
    │      │
    │      ├─information
    │      │      disc.png
    │      │      headline.jpg
    │      │      hot1.jpg
    │      │      hot2.jpg
    │      │      hot3.jpg
    │      │      hot4.jpg
    │      │      hot5.jpg
    │      │      hot6.jpg
    │      │      hot7.jpg
    │      │      hot8.jpg
    │      │      logo.png
    │      │      tour1.jpg
    │      │      tour2.jpg
    │      │      tour3.jpg
    │      │      tour4.jpg
    │      │      tour5.jpg
    │      │      tour6.jpg
    │      │      tour7.jpg
    │      │      tour8.jpg
    │      │      tour9.jpg
    │      │
    │      └─ticket
    │              headline.jpg
    │              hot1.jpg
    │              hot2.jpg
    │              hot3.jpg
    │              hot4.jpg
    │              hot5.jpg
    │              hot6.jpg
    │              hot7.jpg
    │              hot8.jpg
    │              logo.png
    │
    └─templates
            about.html
            index.html
            information.html
            order.html
            preview.html
    
  3. webserver.py

    """
    
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    import dynamic.mini_frame
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", 8080))
            # 设置成监听模式
            self.tcp_server.listen(128)
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    f = open("./static/" + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                # body = "nihao : %s" % time.ctime()
                envs = dict()
                envs["PATH_INFO"] = file_name
                # print(envs)
                # 传递一个字典{"PATH_INFO":file_name}
                body = dynamic.mini_frame.application(envs, self.set_response_header)
    
                header = "HTTP:/1.1 %s\r\n" % self.status
                for temp in self.hearers:
                    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, status, headers):
            self.status = status
            self.hearers = [("server:","mini_server v8.8")]
            self.hearers += headers
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        wsgi_server = WSGIServer()
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    
  4. mini_frame.py

    import time
    
    
    def index():
    	with open("./templates/index.html", encoding='utf-8') as f:
    		return f.read()
    
    
    def order():
    	with open("./templates/order.html", encoding='utf-8') as f:
    		return f.read()
    
    
    def information():
    	with open("./templates/information.html", encoding='utf-8') as f:
    		return f.read()
    
    
    def preview():
    	with open("./templates/preview.html", encoding='utf-8') as f:
    		return f.read()
    
    
    def about():
    	with open("./templates/about.html", encoding='utf-8') as f:
    		return f.read()
    
    
    def application(environ, start_response):
    	start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    	# print(environ)
    	file_name = environ["PATH_INFO"]
    	if file_name == "/index.py":
    		return index()
    	elif file_name == "/order.py":
    		return order()
    	elif file_name == "/information.py":
    		return information()
    	elif file_name == "/preview.py":
    		return preview()
    	elif file_name == "/about.py":
    		return about()
    	else:
    		return ' 中国 hello word time: %s' % time.ctime()
    
    

六、在运行服务器之前指定框架和端口号

  1. 修改webserver.py

    """
    
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    # import dynamic.mini_frame
    import sys
    import re
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self, port, app):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", port))
            # 设置成监听模式
            self.tcp_server.listen(128)
            self.app = app
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    f = open("./static/" + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                # body = "nihao : %s" % time.ctime()
                envs = dict()
                envs["PATH_INFO"] = file_name
                # print(envs)
                # 传递一个字典{"PATH_INFO":file_name}
                # body = dynamic.mini_frame.application(envs, self.set_response_header)
                body = self.app(envs, self.set_response_header)
    
                header = "HTTP:/1.1 %s\r\n" % self.status
                for temp in self.hearers:
                    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, status, headers):
            self.status = status
            self.hearers = [("server:","mini_server v8.8")]
            self.hearers += headers
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        # 执行代码的操作  python server.py 7780 mini_frame:application   -->端口名和框架中的函数
        if len(sys.argv) == 3:
            try:
                port = int(sys.argv[1])  # 7780
                frame_app_name = sys.argv[2]  # mini_frame:application
            except Exception as ret:
                print("端口错误")
                return
        else:
            print("请用以下方式执行程序:")
            print("python m8-server.py 7780 mini_frame:application   -->  程序后加入端口号和框架中的main函数名")
            return  # 结束函数
        # mini_frame:application
        ret = re.match(r"([^:]+):(.*)", frame_app_name)
        if ret:
            frame_name = ret.group(1)  # mini_frame
            app_name = ret.group(2)  # application
        else:
            print("请用以下方式执行程序:")
            print("python m8-server.py 7780 mini_frame:application   -->  程序后加入端口号和框架中的main函数名")
            return  # 结束函数
        sys.path.append("./dynamic")
        # import frame_name  -->  找的是 frame_name.py
        frame = __import__(frame_name)  # 导入函数  以变量名的函数  返回值标记了这个导入的模板
        app = getattr(frame, app_name)  # 此时app指向了./dynamic/mini_frame.application
    
        wsgi_server = WSGIServer(port, app)
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    

七、让框架支持读取配置文件

  1. 现在webserver.py的同级目录下创建一个webserver.conf文件储存要配置的文件,文件中存放一下内容 html文件的存放路径和框架的存放路径

    {
    	"static_path":"./static",
    	"dynamic_path":"./dynamic"
    }
    
    
  2. 修改的webserver.py代码

    """
    
    使用面向对象的方法来做多进程的web server 继承了动态的解析功能 
    当请求文件结尾以.py结尾的为动态网页
    
    """
    
    import socket
    import re
    import multiprocessing
    import time
    # import dynamic.mini_frame
    import sys
    import re
    
    
    class WSGIServer(object):
        """服务器对象"""
        def __init__(self, port, app, static_path):
            # 创建套接字
            self.tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            # 绑定ip和port
            self.tcp_server.bind(("", port))
            # 设置成监听模式
            self.tcp_server.listen(128)
            self.app = app
            self.static_path = static_path
    
        def service_client(self, new_socket):
            # 接受数据
            data = new_socket.recv(1024).decode("utf-8")
            # print(data.decode("utf-8"))
            data_list = data.splitlines()
            # print(data_list[0])
    
            # 正则匹配出文件名   'GET /img/home/tour8.jpg HTTP/1.1',
            ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
            print(ret)
            file_name = ""
            if ret:
                file_name = ret.group(1)
                print(file_name)
                if file_name == "/":
                    file_name = "/index.html"
    
            if not file_name.endswith('.py'):
                try:
                    # 打开文件
                    # f = open("./static/" + file_name, "rb")
                    f = open(self.static_path + file_name, "rb")
                except:
    
                    response = "HTTP/1.1 404 NOT FOUND\r\n"
                    response += "\r\n"
                    response += "Not Found"
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                else:
                    # 传递数据
                    response = "HTTP:/1.1 200 OK\r\n"
                    response += "\r\n"
                    data_contend = f.read()
                    f.close()
                    # 发送文件 header
                    new_socket.send(response.encode("utf-8"))
                    # 发送文件body
                    new_socket.send(data_contend)
            else:
                # 以.py结尾的则为动态的获取的页面
                # body = "nihao : %s" % time.ctime()
                envs = dict()
                envs["PATH_INFO"] = file_name
                # print(envs)
                # 传递一个字典{"PATH_INFO":file_name}
                # body = dynamic.mini_frame.application(envs, self.set_response_header)
                body = self.app(envs, self.set_response_header)
    
                header = "HTTP:/1.1 %s\r\n" % self.status
                for temp in self.hearers:
                    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, status, headers):
            self.status = status
            self.hearers = [("server:","mini_server v8.8")]
            self.hearers += headers
    
        def run_forerver(self):
            """使程序一直运行"""
            while True:
                # 等待客户端连接
                new_client, addr = self.tcp_server.accept()
                p = multiprocessing.Process(target=self.service_client, args=(new_client, ))
                # 接受客户端的消息  回复客户端的消息
                # service_client(new_client)
                p.start()
                new_client.close()  # 多进程中会复制一份这个变量,所以要在主进程中也要关闭
            self.tcp_server.close()
    
    
    def main():
        """控制整体流程 --> 创建一个对象 --> 调用这个对象的run_forerver方法"""
        # 执行代码的操作  python server.py 7780 mini_frame:application   -->端口名和框架中的函数
        if len(sys.argv) == 3:
            try:
                port = int(sys.argv[1])  # 7780
                frame_app_name = sys.argv[2]  # mini_frame:application
            except Exception as ret:
                print("端口错误")
                return
        else:
            print("请用以下方式执行程序:")
            print("python m8-server.py 7780 mini_frame:application   -->  程序后加入端口号和框架中的main函数名")
            return  # 结束函数
        # mini_frame:application
        ret = re.match(r"([^:]+):(.*)", frame_app_name)
        if ret:
            frame_name = ret.group(1)  # mini_frame
            app_name = ret.group(2)  # application
        else:
            print("请用以下方式执行程序:")
            print("python m8-server.py 7780 mini_frame:application   -->  程序后加入端口号和框架中的main函数名")
            return  # 结束函数
    
        # 读取配置文件中的信息
        # {
        #     "static_path":"./static",
        #     "dynamic_path":"./dynamic"
        # }
        with open("./web_server.conf") as f:
            conf_info = eval(f.read())
        # print(conf_info)
        sys.path.append(conf_info["dynamic_path"])
    
        # import frame_name  -->  找的是 frame_name.py
        frame = __import__(frame_name)  # 导入函数  以变量名的函数  返回值标记了这个导入的模板
        app = getattr(frame, app_name)  # 此时app指向了./dynamic/mini_frame.application
    
        wsgi_server = WSGIServer(port, app, conf_info["static_path"])
        wsgi_server.run_forerver()
    
    
    if __name__ == "__main__":
        main()
    
  3. 再写一个程序执行文的操作

    运行web服务器时指定端口和框架
    运行方式: python webserver.py port frame:app
    举例: python webserver.py 8080 mini_frame:application
    首先要配置web_server.conf中的文件路径
    
    

你可能感兴趣的:(python,#,python,socket,http)