web静态服务器实现

本文介绍如何使用Python构建简单的Web静态服务器,包括基本的单任务服务器实现、利用协程完成多任务处理以及面向对象的设计方式。此外,还展示了如何通过命令行参数自定义服务器端口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# web静态服务器实现
web静态服务器实现,可以通过浏览器访问
##返回指定页面数据

"""返回指定页面数据"""

from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
import re


def main():
    # 创建tcp服务端套接字
    tcp_server = socket(AF_INET, SOCK_STREAM)
    # 设置socket选项,立即释放端口,正常情况下,服务器断开连接后,需要1-2分钟才会释放端口
    tcp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, True)
    # 局域网下其他电脑可以通过 本机ip:9090访问,本机可以使用127.0.0.1:9090访问(默认是80,所以后面要加端口号)
    tcp_server.bind(("", 9090))
    # 设置监听:单任务,同一时刻只有一个客户端能建立连接,其他的都等着建立连接
    tcp_server.listen(128)
    # 循环接受可客户端的连接请求
    while True:
        # 生成一个新的套接字,专门处理这一个客户端,tcp_server就可以省下来等待其他的客户端请求
        service_client_sock, ip_port = tcp_server.accept()
        # 正常请求报文1024就足够接收了,为了防止特殊情况使用了4096
        client_request_data = service_client_sock.recv(4096)
        client_request_content = client_request_data.decode("utf-8")
        # 查找请求资源路径
        print(client_request_content)
        match_obj = re.search("r/\S*", client_request_content)
        print(match_obj)
        if not match_obj:
            print("访问路径有误")
            service_client_sock.close()
            return

        request_path = match_obj.group()
        print(request_path)
        if request_path == "/":
            request_path = "/index.html"
        # 判断访问的资源存在可以使用异常处理或者os模块的os.path.exists()
        # import os
        # os.chdir("static")
        # res = os.path.exists('index.html')
        # print(res)
        try:
            with open("static" + request_path, 'rb') as file:
                file_data = file.read()
        except Exception as e:
            # 准备响应报文数据
            # 响应行
            response_line = "HTTP/1.1 404 Not Found\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
            # 响应体 -> 打开一个404html数据把数据给浏览器
            response_body = "<h1>非常抱歉,您当前访问的网页已经不存在了</h1>".encode("utf-8")

            # 匹配响应报文数据
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            # 发送响应报文数据
            service_client_sock.send(response_data)
        else:
            # 准备响应数据
            # 响应行
            response_line = "HTTP/1.1 200 OK\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent_Type: text/html; charset=utr-8\r\n"
            # 响应体
            response_body = file_data
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body

            service_client_sock.send(response_data)
        finally:
            service_client_sock.close()


if __name__ == "__main__":
    main()

##使用协程完成多任务web服务

"""
使用协程完成多任务web服务器,节省资源,效率比较高
gevent开辟协程如果程序一直运行则不需要加上join操作,因为程序没有退出
这程序我没有使用,from socket import socket, AF_INET, SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR
因为主程序中使用socket,它识别不出来是那个socket
"""
import socket
import re
import gevent
from gevent import monkey

# 让gevent能够识别耗时操作,让协程自动切换执行,失败的耗时操作由: recv, accept, time.sleep, 网络请求延时
monkey.patch_all()


# 处理客户端的请求

def handle_client_request(service_client_socket):
    # 获取客户端的请求报文数据
    client_request_data = service_client_socket.recv(4096)
    print(client_request_data)
    # GET /index2.html HTTP/1.1xxxxxxx
    client_request_conent = client_request_data.decode("utf-8")
    # 通过正则查找请求的资源路径
    match_obj = re.search("/\S*", client_request_conent)

    if not match_obj:
        print("访问路径有误")
        service_client_socket.close()
        return

    # 获取匹配结果
    request_path = match_obj.group()
    print(request_path)

    if request_path == "/":
        # 如果用户没有指定资源路径那么默认访问的数据是首页的数据
        request_path = "/index.html"

    # 读取指定文件数据
    # 使用rb的原因是浏览器也有可能请求的是图片
    try:
        with open("static" + request_path, "rb") as file:
            # 读取文件数据
            file_data = file.read()
    except Exception as e:
        # 准备响应报文数据
        # 响应行
        response_line = "HTTP/1.1 404 Not Found\r\n"
        # 响应头
        response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
        # 响应体 -> 打开一个404html数据把数据给浏览器
        response_body = "<h1>非常抱歉,您当前访问的网页已经不存在了</h1>".encode("utf-8")

        # 匹配响应报文数据
        response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
        # 发送响应报文数据
        service_client_socket.send(response_data)
    else:
        # 准备响应报文数据
        # 响应行
        response_line = "HTTP/1.1 200 OK\r\n"
        # 响应头
        response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
        # 响应体
        response_body = file_data

        # 匹配响应报文数据
        response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
        # 发送响应报文数据
        service_client_socket.send(response_data)
    finally:
        service_client_socket.close()


def main():
    # 创建tcp服务端套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置socket选项,立即释放端口
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 绑定端口号
    tcp_server_socket.bind(("", 9090))
    # 设置监听
    tcp_server_socket.listen(128)
    # 循环接收客户端的连接请求
    while True:
        service_client_socket, ip_port = tcp_server_socket.accept()
        # handle_client_request(service_client_socket)
        # 开辟协程并执行对应的任务
        gevent.spawn(handle_client_request, service_client_socket)
        # 不需要加上join,主要原有是我们的进程不会退出
        # g1.join()


if __name__ == '__main__':
    main()

使用面向对象的方式实现web静态服务器

"面向对象服务器开发"

import socket
import re
import gevent
from gevent import monkey

# 让gevent能够识别耗时操作,让协程自动切换执行,失败的耗时操作由: recv, accept, time.sleep, 网络请求延时
monkey.patch_all()


class HttpWebServer(object):
    def __init__(self):
        # 创建tcp服务端套接字
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置socket选项,立即释放端口
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定端口号
        tcp_server_socket.bind(("", 9090))
        # 设置监听
        tcp_server_socket.listen(128)
        self.tcp_server_socket = tcp_server_socket

    @staticmethod
    def handle_client_request(service_client_socket):
        # 获取客户端的请求报文数据
        client_request_data = service_client_socket.recv(4096)
        print(client_request_data)
        # GET /index2.html HTTP/1.1xxxxxxx
        client_request_conent = client_request_data.decode("utf-8")
        # 通过正则查找请求的资源路径
        match_obj = re.search("/\S*", client_request_conent)

        if not match_obj:
            print("访问路径有误")
            service_client_socket.close()
            return

        # 获取匹配结果
        request_path = match_obj.group()
        print(request_path)

        if request_path == "/":
            # 如果用户没有指定资源路径那么默认访问的数据是首页的数据
            request_path = "/index.html"

        # 读取指定文件数据
        # 使用rb的原因是浏览器也有可能请求的是图片
        try:
            with open("static" + request_path, "rb") as file:
                # 读取文件数据
                file_data = file.read()
        except Exception as e:
            # 准备响应报文数据
            # 响应行
            response_line = "HTTP/1.1 404 Not Found\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
            # 响应体 -> 打开一个404html数据把数据给浏览器
            response_body = "<h1>非常抱歉,您当前访问的网页已经不存在了</h1>".encode("utf-8")

            # 匹配响应报文数据
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            # 发送响应报文数据
            service_client_socket.send(response_data)
        else:
            # 准备响应报文数据
            # 响应行
            response_line = "HTTP/1.1 200 OK\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
            # 响应体
            response_body = file_data

            # 匹配响应报文数据
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            # 发送响应报文数据
            service_client_socket.send(response_data)
        finally:
            service_client_socket.close()

    def start(self):

        # 循环接收客户端的连接请求
        while True:
            service_client_socket, ip_port = self.tcp_server_socket.accept()
            # handle_client_request(service_client_socket)
            # 开辟协程并执行对应的任务
            gevent.spawn(self.handle_client_request, service_client_socket)
            # 不需要加上join,主要原有是我们的进程不会退出
            # g1.join()


def main():
    server = HttpWebServer()
    server.start()


if __name__ == '__main__':
    main()

通过命令行启动服务器,可以自动设置端口号

import sys
import socket
import re
import gevent
from gevent import monkey

# 让gevent能够识别耗时操作,让协程自动切换执行,失败的耗时操作由: recv, accept, time.sleep, 网络请求延时
monkey.patch_all()


class HttpWebServer(object):
    def __init__(self, port):
        # 创建tcp服务端套接字
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置socket选项,立即释放端口
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 绑定端口号
        tcp_server_socket.bind(("", port))
        # 设置监听
        tcp_server_socket.listen(128)
        self.tcp_server_socket = tcp_server_socket

    @staticmethod
    def handle_client_request(service_client_socket):
        # 获取客户端的请求报文数据
        client_request_data = service_client_socket.recv(4096)
        print(client_request_data)
        # GET /index2.html HTTP/1.1xxxxxxx
        client_request_conent = client_request_data.decode("utf-8")
        # 通过正则查找请求的资源路径
        match_obj = re.search("/\S*", client_request_conent)

        if not match_obj:
            print("访问路径有误")
            service_client_socket.close()
            return

        # 获取匹配结果
        request_path = match_obj.group()
        print(request_path)

        if request_path == "/":
            # 如果用户没有指定资源路径那么默认访问的数据是首页的数据
            request_path = "/index.html"

        # 读取指定文件数据
        # 使用rb的原因是浏览器也有可能请求的是图片
        try:
            with open("static" + request_path, "rb") as file:
                # 读取文件数据
                file_data = file.read()
        except Exception as e:
            # 准备响应报文数据
            # 响应行
            response_line = "HTTP/1.1 404 Not Found\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
            # 响应体 -> 打开一个404html数据把数据给浏览器
            response_body = "<h1>非常抱歉,您当前访问的网页已经不存在了</h1>".encode("utf-8")

            # 匹配响应报文数据
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            # 发送响应报文数据
            service_client_socket.send(response_data)
        else:
            # 准备响应报文数据
            # 响应行
            response_line = "HTTP/1.1 200 OK\r\n"
            # 响应头
            response_header = "Server: PWS1.0\r\nContent-Type: text/html;charset=utf-8\r\n"
            # 响应体
            response_body = file_data

            # 匹配响应报文数据
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            # 发送响应报文数据
            service_client_socket.send(response_data)
        finally:
            service_client_socket.close()

    def start(self):

        # 循环接收客户端的连接请求
        while True:
            service_client_socket, ip_port = self.tcp_server_socket.accept()
            # handle_client_request(service_client_socket)
            # 开辟协程并执行对应的任务
            gevent.spawn(self.handle_client_request, service_client_socket)
            # 不需要加上join,主要原有是我们的进程不会退出
            # g1.join()


def main():
    print(sys.argv)
    # 端口号可以自定义
    if len(sys.argv) != 2:
        print("启动命令如下: python3 command_parameter_server.py 9090")
        return
    if not sys.argv[1].isdigit():
        print("启动命令如下: python3 command_parameter_server.py 9090")
        return
    port = int(sys.argv[1])
    print(port)

    server = HttpWebServer(port)
    server.start()


if __name__ == '__main__':
    main()

最后一个程序的运行已及一个界面的截图
这里写图片描述
这里写图片描述

传送门

https://download.youkuaiyun.com/download/vivian_wanjin/10661512

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值