Python 之web动态服务器

webServer.py代码如下:

import socket
import sys
from multiprocessing import Process


class WSGIServer(object):
    addressFamily = socket.AF_INET
    socketType = socket.SOCK_STREAM
    requestQueueSize = 100

    server_response_header = ""

    def __init__(self, server_info, application):

        server_socket = socket.socket(self.addressFamily, self.socketType)
        # 允许重复使用上次的套接字绑定的port
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # 绑定
        server_socket.bind(server_info)
        # 变为被动,并制定队列的长度
        server_socket.listen(self.requestQueueSize)
        self.server_socket = server_socket
        self.application = application

    def wait_client(self):
        '循环运行web服务器,等待客户端的链接并为客户端服务'
        while True:
            # 等待新客户端到来
            new_socket, address = self.server_socket.accept()
            # 多进程服务器,并发服务器于多个客户端
            process = Process(target=self.handle_client, args=(new_socket,))
            process.start()
            # 因为创建的新进程中,会对这个套接字+1,所以需要在主进程中减去依次,即调用一次close
            new_socket.close()

    def handle_client(self, new_socket):
        '用一个新的进程,为一个客户端进行服务'
        get_client_data = new_socket.recv(2048)
        lines = str(get_client_data).splitlines()
        request_data = str(lines[0]).split(" ")
        try:
            file_name = request_data[1]
            method = request_data[0]
        except IndexError as e:
            print(e)
            return False
        # 根据接收到的请求头构造环境变量字典
        env = {
            "PATH_INFO": file_name,
            "METHOD": method
        }
        # 调用应用的相应方法,完成动态数据的获取
        response_body = self.application(env, self.start_response)
        response = self.server_response_header + response_body
        new_socket.send(response.encode("utf-8"))
        new_socket.close()

    def start_response(self, status, header):
        headers = "HTTP/1.0 " + status + " \r\n"
        for h in header:
            headers += "%s : %s\r\n" % h
        self.server_response_header = headers + "\r\n"


def main():
    if len(sys.argv) < 2:
        sys.exit('请按照要求,指定模块名称:应用名称,例如 module:callable')

        # 获取module:callable
    appPath = sys.argv[1]
    # 根据冒号切割为module和callable
    module, application = appPath.split(':')
    module_root = "./module"
    # 添加路径套sys.path
    sys.path.insert(0, module_root)
    # 动态导入module变量中指定的模块
    module = __import__(module)
    # 获取module变量中指定的模块的,application变量指定的属性
    application = getattr(module, application)
    wsgi_server = WSGIServer(("", 8081), application)
    wsgi_server.wait_client()


if __name__ == '__main__':
    main()

start.py代码如下:

class Application(object):
    def __init__(self, urls):
        self.urls = urls

    def __call__(self, env, start_response):
        path = env.get("PATH_INFO", "/")
        if str(path).startswith("/static"):
            file_name = path[7:]
            try:
                f = open(html_root + file_name, 'r')
            except IOError as e:
                headers = []
                status = "404 Not Found"
                start_response(status, headers)
                return "not found"
            else:
                headers = []
                status = "200 OK"
                start_response(status, headers)
                return str(f.read())
        for url, handle in self.urls:
            if path == url:
                return handle(env, start_response)
            status = "404 Not Found"
            headers = []
            start_response(status, headers)
            return "not found"


def test(env, start_response):
    status = "200 OK"
    headers = [("Content-type", "text/plain")]
    start_response(status, headers)
    return "test is ok"

html_root = "./html/"
urls = [("/test", test)]
app = Application(urls)

运行效果如下:

 

posted @ 2019-05-21 21:01  样子2018  阅读(668)  评论(1编辑  收藏  举报