HTTP服务器--面向对象

import socket
import gevent
import time
from gevent import monkey


class WebServer(object):
    """把http服务器的功能都封装在WebServer类中"""

    DOCUMENTS_ROOT = './html'  # 这里配置服务器,配置服务端的文档根路径

    def __init__(self):

        monkey.patch_all()  # 打gevent补丁
        # 创建监听套接字
        self.http_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # 当套接字四次挥手,可立即复用地址端口
        self.http_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

        # 服务端绑定端口
        self.http_server_socket.bind(('', 7788))

        # 开启监听
        self.http_server_socket.listen(128)

    def __del__(self):

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

    def startup(self):

        # 等待接受浏览器客户端的请求
        while True:
            client_socket, client_addr = self.http_server_socket.accept()

            # 开启gevent协程处理请求
            g1 = gevent.spawn(self.handle_client, client_socket)
            g1.join()

    def handle_client(self, client_socket):
        """为客户端服务"""

        print("当前gevent协程对象:", gevent.getcurrent())
        # 接收从客户端发送的数据
        recv_data = client_socket.recv(4096)

        if not recv_data:
            return  # 假如服务端没有收到请求数据,直接返回

        # 解码
        request_data = recv_data.decode("utf-8")

        # 按行分离字符串
        request_lines = request_data.splitlines()

        print("客户端的请求报文数据如下:")
        for line in request_lines:
            print(line)

        # 请求行: GET /index.html HTTP/1.1
        request_line = request_lines[0]

        # 通过请求行取得请求路径,即要求的页面路径
        get_file_name = request_line.split(" ")[1]
        print("客户端要求的页面是: ===>%s" % get_file_name)

        # 如果没有指定访问哪个页面,默认指定index.html
        # GET / HTTP/1.1
        if get_file_name == "/":
            get_file_name = WebServer.DOCUMENTS_ROOT + "/index.html"
        else:
            get_file_name = WebServer.DOCUMENTS_ROOT + get_file_name

        print("服务端回传的页面是: ===>%s" % get_file_name)

        # 按照http 响应报文格式去回复客户端
        """http 响应报文格式
         1. 响应行 : HTTP/1.1 200 OK
         2. 响应头 Server: mimiweb1.0    Connection: Keep-alive
         3. 分隔符 \r\n
         4. 响应体  网页的具体内容
        """
        try:
            f = open(get_file_name, "rb")
        except IOError:
            """请求异常"""
            # 404表示没有这个页面
            response_line = "HTTP/1.1 404 Not Found\r\n"  # 响应行,必写
            response_headers = "Server: mimiweb1.0\r\n"  # 设置响应头
            split = "\r\n"  # 分割线
            response_body = "====sorry ,file not found===="  # 设置响应体
            response_body = response_body.encode('utf-8')  # 注意,一定要重新赋值,否则response_body还是字符串,而不是字节串
        else:
            """请求成功"""
            response_line = "HTTP/1.1 200 OK\r\n"  # 响应行,必写
            response_headers = "Server: mimiweb1.0\r\n"  # 设置响应头
            split = "\r\n"  # 分割线

            # 设置响应体
            response_body = f.read()
            f.close()
        finally:
            # 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送
            # 先发送response的头信息
            client_socket.send((response_line + response_headers + split).encode('utf-8'))
            # 再发送body
            client_socket.send(response_body)
            # 关闭套接字
            client_socket.close()


def main():
    """程序主控制入口"""
    web_server = WebServer()
    web_server.startup()


if __name__ == '__main__':
    main()
posted @ 2021-03-15 23:00  涛子17180  阅读(70)  评论(0编辑  收藏  举报