一、静态web服务器-多任务

多任务web服务器:使用多线程,比进程更节省资源,支持多用户同时访问,可以同时处理多个客户端请求

  • 实现步骤
    • 若客户端与服务端建立连接,则创建子线程,使用子线程处理客户端请求,防止主线程阻塞
    • 将创建的子线程设置为守护主线程,防止主线程无法退出

实现代码

import socket
import threading
def handle_client_request(comm_socket):    # 处理客户端请求
    recv_data = comm_socket.recv(4096)  # 接收请求的二进制数据
    if len(recv_data) == 0:
        print('未获取到请求数据!')
        comm_socket.close()
        return
    recv_content = recv_data.decode('utf-8')  # 对二进制数据解码
    print('获取到的数据内容为:', recv_content)
    request_list = recv_content.split(" ", maxsplit=2)  # 根据指定字符串空格进行分割,最大分割次数为2
    request_path = request_list[1]  # 获取请求资源路径
    print('请求路径为:', request_path)
    if request_path == "/":  # 判断请求的是否是根目录,若是则返回首页指定数据
        request_path = "/index.html"
    try:
        with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file:  # 动态打开指定文件
            file_data = file.read()  # 读取指定文件数据
    except Exception as e:  # 请求异常,资源不存在,返回指定404错误数据
        with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file:  # 打开指定错误文件
            error_data = file.read()  # 读取指定错误数据
        response_line = "HTTP/1.1 404 Not Found!!\r\n"  # 响应行
        response_header = "Server: PWS1.0 服务器名称及版本……\r\n"  # 响应头
        response_body = error_data  # 响应体
        response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body  # 拼接响应报文
        comm_socket.send(response_data)  # 发送数据给浏览器
    else:
        response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
        response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
        response_body = file_data
        response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
        comm_socket.send(response_data)
    finally:
        comm_socket.close()  # 关闭服务于客户端的套接字

def main():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    # 创建TCP服务端套接字
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)   # 设置端口号复用,程序退出端口号立即释放
    server_socket.bind(("", 9000))   # 绑定端口号
    server_socket.listen(128)   # 设置监听
    while True:
        comm_socket, ip_port = server_socket.accept()   # 等待接受客户端连接请求
        thread = threading.Thread(target=handle_client_request, args=(comm_socket,))  # 若客户端和服务器连接成功,创建子线程
        thread.setDaemon(True)   # 设置守护主线程
        thread.start()   # 启动子线程执行对应任务

if __name__ == '__main__':
    main()

输出如下

获取到的数据内容为: GET /index.html HTTP/1.1
Host: 127.0.0.1:9000
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrftoken=1wb7v0r0BQuokJCxRS4JAO2XApvrHXFP90t2PiYb0mz7AwWS0NoKTi0zNaIjOfTl; Hm_lvt_18f619820855042bca58b32408f44de7=1658219884


请求路径为: /index.html

浏览器响应如下 

二、静态web服务器-面向对象 

  • 实现步骤
    • 把提供服务的web服务器抽象为一个类
    • 提供web服务器初始化方法,在方法中创建socket对象
    • 提供一个开启web服务器的方法,让web服务器处理客户端请求操作

实现代码

import socket
import threading
class HttpWebServer(object):   # 定义web服务器类,将提供服务的web服务器抽象为一个类
    def __init__(self):   # 初始化服务端套接字
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    # 创建TCP套接字
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)  # 设置端口复用,程序退出端口号立即释放
        server_socket.bind(("", 9000))     # 绑定端口号
        server_socket.listen(128)    # 设置监听
        self.server_socket = server_socket

    @staticmethod
    def handle_client_request(comm_socket):
        recv_data = comm_socket.recv(4096)  # 接收请求的二进制数据
        if len(recv_data) == 0:
            print('未获取到请求数据!')
            comm_socket.close()
            return
        recv_content = recv_data.decode('utf-8')  # 对二进制数据解码
        print('获取到的数据内容为:', recv_content)
        request_list = recv_content.split(" ", maxsplit=2)  # 根据指定字符串空格进行分割,最大分割次数为2
        request_path = request_list[1]  # 获取请求资源路径
        print('请求路径为:', request_path)
        if request_path == "/":  # 判断请求的是否是根目录,若是则返回首页指定数据
            request_path = "/index.html"
        try:
            with open('C:/Users/熊世强/Desktop/ubuntu' + request_path, 'rb') as file:  # 动态打开指定文件
                file_data = file.read()  # 读取指定文件数据
        except Exception as e:  # 请求异常,资源不存在,返回指定404错误数据
            with open('C:/Users/熊世强/Desktop/ubuntu/error.html', 'rb') as file:  # 打开指定错误文件
                error_data = file.read()  # 读取指定错误数据
            response_line = "HTTP/1.1 404 Not Found!!\r\n"  # 响应行
            response_header = "Server: PWS1.0 服务器名称及版本……\r\n"  # 响应头
            response_body = error_data  # 响应体
            response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body  # 拼接响应报文
            comm_socket.send(response_data)  # 发送数据给浏览器
        else:
            response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
            response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
            response_body = file_data
            response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
            comm_socket.send(response_data)
        finally:
            comm_socket.close()  # 关闭服务于客户端的套接字
    def start(self):   # 启动web服务器
        while True:
            comm_socket, ip_port = self.server_socket.accept()   # 等待接收客户端连接请求
            thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,))   # 若客户端和服务器建立连接,则创建子线程
            thread.setDaemon(True)   # 设置守护子线程
            thread.start()   # 启动子线程执行对应任务

def main():   # 程序入口函数
    webServer = HttpWebServer()   # 创建web服务器对象
    webServer.start()   # 启动web服务器进行工作

if __name__ == '__main__':
    main()

输出如下

获取到的数据内容为: GET /index.html HTTP/1.1
Host: 127.0.0.1:9000
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: csrftoken=1wb7v0r0BQuokJCxRS4JAO2XApvrHXFP90t2PiYb0mz7AwWS0NoKTi0zNaIjOfTl; Hm_lvt_18f619820855042bca58b32408f44de7=1658219884


请求路径为: /index.html

浏览器响应如下

 三、静态web服务器-命令行启动动态绑定端口号

  • 实现步骤
    • 获取执行python程序的终端命令行参数
    • 判断参数类型,设置端口号必须是整型
    • 为web服务器类的初始化方法添加一个端口号参数,用于绑定端口号

实现代码

import socket
import threading
import sys
class HttpWebServer(object):   # 定义web服务器类,将提供服务的web服务器抽象为一个类
    def __init__(self, port):   # 初始化服务端套接字,添加端口号参数
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    # 创建TCP套接字
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)  # 设置端口复用,程序退出端口号立即释放
        server_socket.bind(("", port))     # 绑定端口号
        server_socket.listen(128)    # 设置监听
        self.server_socket = server_socket

    @staticmethod
    def handle_client_request(comm_socket):   # 处理客户端请求
        recv_data = comm_socket.recv(4096)  # 接收请求的二进制数据
        if len(recv_data) == 0:
            print('未获取到请求数据!')
            comm_socket.close()
            return
        recv_content = recv_data.decode('utf-8')  # 对二进制数据解码
        print('获取到的数据内容为:', recv_content)
        request_list = recv_content.split(" ", maxsplit=2)  # 根据指定字符串空格进行分割,最大分割次数为2
        request_path = request_list[1]  # 获取请求资源路径
        print('请求路径为:', request_path)
        if request_path == "/":  # 判断请求的是否是根目录,若是则返回首页指定数据
            request_path = "/index.html"
        try:
            with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file:  # 动态打开指定文件
                file_data = file.read()  # 读取指定文件数据
        except Exception as e:  # 请求异常,资源不存在,返回指定404错误数据
            with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file:  # 打开指定错误文件
                error_data = file.read()  # 读取指定错误数据
            response_line = "HTTP/1.1 404 Not Found!!\r\n"  # 响应行
            response_header = "Server: PWS1.0 服务器名称及版本……\r\n"  # 响应头
            response_body = error_data  # 响应体
            response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body  # 拼接响应报文
            comm_socket.send(response_data)  # 发送数据给浏览器
        else:
            response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
            response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
            response_body = file_data
            response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
            comm_socket.send(response_data)
        finally:
            comm_socket.close()  # 关闭服务于客户端的套接字
    def start(self):   # 启动web服务器
        while True:
            comm_socket, ip_port = self.server_socket.accept()   # 等待接收客户端连接请求
            thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,))   # 若客户端和服务器建立连接,则创建子线程
            thread.setDaemon(True)   # 设置守护子线程
            thread.start()   # 启动子线程执行对应任务

def main():   # 程序入口函数
    print('命令行输入的参数为:', sys.argv)
    if len(sys.argv) != 2:    # 判断命令行参数个数是否为2
        print("请执行格式为[ python3 xx.py 9000 ] 的命令")
        return
    if not sys.argv[1].isdigit():   # 判断字符串是否为数字组成,必须为整型
        print("请执行格式为[ python3 xx.py 9000 ]的命令")
        return
    port = int(sys.argv[1])   # 获取终端命令行参数
    web_server = HttpWebServer(port)
    web_server.start()

if __name__ == '__main__':
    main()

命令行执行

 浏览器响应如下 

 学习导航:http://xqnav.top/

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐