Python简易web静态服务器程序搭建


Python自带简易静态web服务器搭建

静态web服务器程序指的是可以根据浏览器的请求报文,在响应报文中返回对应静态文件的程序

静态文件是指数据不需要动态生成的文件。
天气预报网站的数据会实时更新,这种网页就是动态网页。静态web服务器程序为静态网页服务。

http.server模块

http.server是Python自带的一个模块

在终端中进入想要作为web服务器静态文件集的文件夹,运行

python -m http.server port

就可以快速搭建一个简单的静态web服务器

其中

  • -m代表运行模块
  • port是端口号

如:
在这里插入图片描述

将8000作为静态web服务器程序的端口号

在浏览器中输入http://localhost:8000进入/主页。因为没有特别指定页面,所以显示如下

在这里插入图片描述

输入http://localhost:8000/welcome.html获取welcome页面。

在这里插入图片描述

可以看到响应行中服务器名称为SimpleHTTP/0.6 Python/3.10.3.

在这里插入图片描述


DIY简易静态web服务器程序搭建

其实静态web服务器程序也仅仅只是一个服务端程序而已。它的功能也是接受客户端程序的数据,并向客户端程序发送数据。它也基于TCP协议。只不过比较特殊的是,静态web服务器程序接受和发送的数据格式已经被HTTP协议规定好了。

浏览器程序发送类似以下格式的请求报文:

POST / HTTP/1.1\r\n   (请求行)
Host: www.baidu.com\r\n   (请求头信息)
....
\r\n  (空行)
username=hello&pass=hello\r\n   (请求体)

静态web服务器程序回之以类似以下格式的响应报文:

HTTP/1.1 200 OK\r\n   (响应行)
Server: BWS/1.1\r\n    (响应头信息)
...
\r\n   (空行)
<!DOCTYPE html><html lang=“en”> …</html>    (响应体)
普通版
步骤
  1. 创建静态web服务器程序的套接字并绑定端口号

  2. 设置监听

  3. 循环接受浏览器连接请求

  4. 一旦成功建立连接,创建一个子线程

  5. 在子线程中接受浏览器发送的请求报文

  6. 在子线程中分析请求报文并编写对应响应报文

  7. 在子线程中向浏览器发送响应报文

  8. 在子线程中断开与浏览器的连接

具体代码
import socket
import threading


def handle(handle_socket: "socket.socket"):
    """与浏览器进行数据通信的子线程"""
    # 5.在子线程中接受浏览器发送的请求报文
    request_data = handle_socket.recv(4096)

    # 6.在子线程中分析请求报文并编写对应响应报文
    if len(request_data) == 0:
        print("浏览器已断开连接...")
        handle_socket.close()
        return

    request_content = request_data.decode("utf-8")
    print(request_content)
    # 以\r\n分割各项信息
    request_list = request_content.split("\r\n")
    # 提取请求的资源路径
    request_line = request_list[0]
    request_line_list = request_line.split(" ")
    request_method, request_path, request_version = request_line_list

    # 首页
    if request_path == "/":
        request_path = "/welcome.html"

    # 响应行与响应头信息置空
    response_line = response_header = ""

    # 根据请求路径准备好响应行和响应体
    try:
        with open("." + request_path, "rb") as request_file:
            response_body = request_file.read()

    except (FileExistsError, FileNotFoundError):
        response_line += f"{request_version} 404 Not Found\r\n"
        with open("./404.html", "rb") as request_file:
            response_body = request_file.read()

    else:
        response_line += f"{request_version} 200 OK\r\n"

    finally:
        # 准备好响应头信息
        response_header += "Server: MyWebServer1.0\r\n"
        # 7.在子线程中向浏览器发送响应报文
        response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
        handle_socket.send(response_data)
        # 8.在子线程中断开与浏览器的连接
        handle_socket.close()


def main():
    # 1.创建静态web服务器程序的套接字并绑定端口号
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    server_socket.bind(("localhost", 8888))

    # 2.设置监听
    server_socket.listen(128)

    # 3.循环接受浏览器连接请求
    while True:
        new_socket, address = server_socket.accept()
        print("已连接", address, sep=" from ")

        # 4.一旦成功建立连接,创建一个子线程
        sub_thread = threading.Thread(target=handle, args=(new_socket,), daemon=True)
        sub_thread.start()


if __name__ == "__main__":
    main()
面向对象版

对普通版进行抽象即可。

代码
import socket
import threading


class MyWebServer(object):
    def __init__(self,port):
        """初始化:创建套接字"""
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        self.server_socket.bind(("localhost", port))
        self.server_socket.listen(128)

    def start(self):
        """启动:建立连接,并开启子线程"""
        while True:
            new_socket, address = self.server_socket.accept()
            print("已连接", address, sep=" from ")

            # 4.一旦成功建立连接,创建一个子线程
            sub_thread = threading.Thread(target=self.handle, args=(new_socket,), daemon=True)
            sub_thread.start()

    @staticmethod
    def handle(handle_socket):
        """利用子线程收发http格式数据"""
        request_data = handle_socket.recv(4096)

        if len(request_data) == 0:
            print("浏览器已断开连接...")
            handle_socket.close()
            return

        request_content = request_data.decode("utf-8")
        print(request_content)
        # 以\r\n分割各项信息
        request_list = request_content.split("\r\n")
        # 提取请求的资源路径
        request_line = request_list[0]
        request_line_list = request_line.split(" ")
        request_method, request_path, request_version = request_line_list

        # 首页
        if request_path == "/":
            request_path = "/welcome.html"

        # 响应行与响应头信息置空
        response_line = response_header = ""

        # 根据请求路径准备好响应行和响应体
        try:
            with open("." + request_path, "rb") as request_file:
                response_body = request_file.read()

        except (FileExistsError, FileNotFoundError):
            response_line += f"{request_version} 404 Not Found\r\n"
            with open("./404.html", "rb") as request_file:
                response_body = request_file.read()

        else:
            response_line += f"{request_version} 200 OK\r\n"

        finally:
            # 准备好响应头信息
            response_header += "Server: MyWebServer1.0\r\n"
            # 向浏览器发送响应报文
            response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
            handle_socket.send(response_data)
            # 断开与浏览器的连接
            handle_socket.close()


def main():
    my_web_server=MyWebServer(8888)
    my_web_server.start()


if __name__ == "__main__":
    main()

命令行版

我们可以在终端中通过命令行执行python文件

命令行参数
python 参数1 参数2 参数3...
  • python代表用python解释器进行执行,Linux系统可能需要特意指定python3
  • 参数1一般是要执行的python文件名
  • 参数2,3…一般是传给要运行的python程序的参数。

如我们的案例需要的:

python MyWebServer.py 8888
在代码中访问
import sys

print(sys.argv)
#["MyWebServer.py","8888"]
  • 用到了sys模块的argv变量(argument values),它是一个由运行时实际的命令行参数组成的列表。
代码

为了像Python自带的http.server模块一样可以在命令行中运行,我们对main函数作如下改变:

import sys

...

def main()
    #命令行参数个数不对
    if len(sys.argv) != 2:
        print("执行错误。正确格式为python MyWebServer.py 8888(参数个数应为2...)")
        return

    # 端口号是否为整数
    if not sys.argv[1].isdigit():
        print("执行错误。正确格式为python MyWebServer.py 8888(端口号应为整数...)")
        return
    
    port=int(sys.argv[1])
    my_web_server=MyWebServer(port)
    my_web_server.start()
    
...

在这里插入图片描述

在这里插入图片描述

效果

不输入请求资源地址,默认进入主页(welcome.html)

在这里插入图片描述

输入指定资源路径,进入指定页面(advantages.html)

在这里插入图片描述

输入不存在资源路径,进入404页面

在这里插入图片描述


  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
一个简易web服务器通常包括以下几个步骤: 1. 创建一个TCP socket并绑定到指定的IP地址和端口号。 2. 监听来自客户端的连接请求,使用accept()函数接受客户端的连接请求。一旦接受请求,服务器将创建一个新的线程或进程来处理该连接。 3. 接收来自客户端的HTTP请求,解析请求头和请求体。 4. 处理客户端的请求,例如读取文件或执行CGI程序,并生成HTTP响应。HTTP响应包括响应头和响应体。 5. 发送HTTP响应给客户端,关闭连接。 以下是一个简单Python代码实现: ```python import socket HOST = '127.0.0.1' # 指定服务器IP地址 PORT = 8000 # 指定服务器端口号 def handle_request(client_socket): request_data = client_socket.recv(1024) print(request_data.decode()) response_body = '<html><body><h1>Hello, World!</h1></body></html>' response_header = f'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {len(response_body)}\r\n\r\n' response = response_header.encode() + response_body.encode() client_socket.sendall(response) def run_server(): listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) listen_socket.bind((HOST, PORT)) listen_socket.listen(1) print(f'Server is listening on {HOST}:{PORT}...') while True: client_socket, client_address = listen_socket.accept() handle_request(client_socket) client_socket.close() if __name__ == '__main__': run_server() ``` 这个简单web服务器监听8000端口,一旦接收到客户端的连接请求,就会生成一个HTTP响应,其中包含一个简单的HTML页面。这个服务器只能处理一个客户端请求并返回响应,如果需要支持多个客户端同时连接,需要使用多线程或异步IO等技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子希卡利

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值