python-web

概述

本文是简单web服务程序,采用进程发并发实现请求处理,采用进程队列保证数据一致性,即完成不同进程间的同步

  1. 监听socket,用于监听并接受http请求的tcp连接
  2. 服务程序,用于处理http请求
  3. 通信socket用于与请求浏览器通信
  4. 多进程调度并发处理请求
    效果如下图:
    python-web_第1张图片
    python-web_第2张图片

服务程序

  1. 对请求头进行分析,采用re正则表达式取出请求内容
		# GET /index.html HTTP/1.1
        ret = re.match(r"[^/]+(/[^ ]*)", request_line[0])
        flie_name = ret.group(1)
  1. 判断请求类型是否为静态文件,若为静态文件则在静态文件夹寻找该文件,将该文件通过socket发送给客户端,若为动态请求则查询路由表找到对应请求的服务
		#访问静态文件
        if not flie_name.endswith(".py"):
        	#读取静态文件并发送
        	pass
        #get访问
        else:
         func = URL_FUNC_DICT[flie_name]
  1. 利用装饰器构建路由字典
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("./html/index.html") as f:
        content = f.read()
    return content

整个服务程序参考源码

'''路由'''
# _*_coding:utf-8 _*_
'''
URL_FUNC_DICT = 
{
    "/index.py":index,
    "/login.py":login
}
'''
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("./html/index.html") as f:
        content = f.read()
    return content

@route("/login.py")
def login():
    return b"logining!..."

'''服务程序'''
def server(new_socket, static,flag=False):
    # 获取浏览器数据,GET/HTTP/1.1
    overtime = 500
    if flag:overtime=0
    new_socket.setblocking(False)#解阻塞
    begin = time.time()
    while True:
        request = new_socket.recv(1024).decode("utf-8")
        print(request)
        if request == b'': break
        request_line = request.splitlines()
        print(">>>" * 50)
        # GET /index.html HTTP/1.1
        flie_name = ""
        ret = re.match(r"[^/]+(/[^ ]*)", request_line[0])
        if ret:
            flie_name = ret.group(1)
            if flie_name == "/":
                flie_name = "/index.html"
        #访问静态文件
        if not flie_name.endswith(".py"):
            try:
                f = open(static + flie_name, 'rb')
            except:
                response = "HTTP/1.1 404 NOT FOUND\r\n"
                response += "\r\n"
                new_socket.send(response.encode("utf-8"))
            else:
                response = "HTTP/1.1 200 OK\r\n\r\n"
                new_socket.send(response.encode("utf-8"))
                for each_connect in f.readlines():
                    new_socket.send(each_connect)
                f.close()
        #get访问
        else:
        	#请求头
            status = '200 OK'
            headers = ('Contene-Type', 'text/html; charset=utf-8')
            print(flie_name)
            try:
                func = URL_FUNC_DICT[flie_name]
                body = func()
                header = "HTTP/1.1 %s\r\n" % status
                for temp in headers:
                    header += "%s:%s\r\n" % (temp[0], temp[1])
                header += "\r\n"
                response = header + body
            except Exception as ret:
                response = "HTTP/1.1 404 NOT FOUND\r\n"
                response += "\r\n"
            new_socket.send(response.encode('utf-8'))
        #超时退出
        if overtime <= 0:break
        else: overtime = overtime-int(time.time() - begin)
    new_socket.close()

调度程序(wbe类)

  1. 建立进程池,用于并发服务,建立进程队列用于进程通信
 		pool = multiprocessing.Pool(5)
        queue = multiprocessing.Manager().Queue(10)

2.创建socket并进行初始化

		tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        tcp_server_socket.bind(("", port))
        tcp_server_socket.listen(128)
        #非阻塞
        tcp_server_socket.setblocking(False)

参考源码

class Web(object):
    def __init__(self, port, static):
        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.tcp_server_socket.setblocking(False)
        self.static = static#静态文件目录
        self.pool = multiprocessing.Pool(5)#进程池
        self.queue = multiprocessing.Manager().Queue(10)#进程队列
        self.__isStop = True

    def __del__(self):
        self.stop()
        self.tcp_server_socket.close()
        self.queue.clear()
        # 进程池停止接受新的任务
        self.pool.close()
        # 等待进程结束
        self.pool.join()

    def stop(self):
        self.__isStop = False
        while not self.queue.empty():
            self.pool.apply_async(server, (self.queue.get(), self.static,True))
    def run_forever(self):
        while self.__isStop:
            try:
                new_socket, client_addr = self.tcp_server_socket.accept()
                self.queue.put(new_socket)
            except Exception as e: pass
            finally:
                if not self.queue.empty():
                    work_socket = self.queue.get()
                    #进程调度
                    self.pool.apply_async(server, (work_socket, self.static, False))
                else:
                    pass

最后补上main函数调用

def main():
	#用于配置静态目录{"static":"./html",}
    with open("./server.cnf") as f:
        config_info = eval(f.read())
    if len(sys.argv) == 2:
        try:
            port = int(sys.argv[1])
            print(port)
        except Exception as ret:
            print("端口输入错误!!")
    else:
        port = 7890
        print("使用python server.py 端口号 ")
    minwbe = Web(port, config_info["static"])
    minwbe.run_forever()

你可能感兴趣的:(wbe后台原理,python并发)