Python 实现 Web 静态服务器(HTTP 协议)

目录

  • 一、在本地启动 HTTP 服务器
    • 1. Windows 下安装 node.js
      • 1)下载安装包
      • 2)配置环境变量
      • 3)安装镜像
      • 4)node.js 的常用命令
    • 2. 安装 http-server 服务
    • 3. 使用 http-server 开启服务
      • 1)使用 http-server
      • 2)详解 http-server [path] [options]
  • 二、Web 静态服务器
    • 1. 显示固定的页面
      • 1)Python 代码
      • 2)结果展示
    • 2. 显示请求的页面
      • 1)Python 代码
      • 2)结果展示
    • 3. 多进程显示页面
    • 4. 多线程显示页面
    • 5. 非阻塞模式显示页面
    • 6. 利用 epoll 显示页面(Linux 下运行)
    • 7. 利用 gevent 显示页面


有关 HTTP 的基础知识:【应用层 IV(万维网WWW)【★★】】

一、在本地启动 HTTP 服务器

1. Windows 下安装 node.js

1)下载安装包

node.js 下载网址:【node.js 中文网】

  • 进入官网,根据需求下载安装包,注意:

    • .msi 是 Windows 系统下的一种安装包文件格式,这种文件类型包含了某个软件或程序的所有安装信息和必要文件,用户只需按照提示进行安装,即可成功将软件或程序部署到 Windows 系统中。

    • .zip 是程序的压缩包,不需要进行安装,解压即可。

  • 根据下图安装软件,可以自行修改安装路径。


  • 安装好后,Win + X 点击 “系统” → “高级系统设置” → “环境变量(N)…” 并双击 “系统变量(S)” 下的 PATH 可以看到新增了一项 D:\nodejs\(设置的安装路径)。

  • Win + R 输入 cmd 进入命令提示符,输入 node -vnpm -v ,如果输出版本号,则说明 node.js 安装成功。

2)配置环境变量

  • 在安装路径 D:\nodejs\ 下新建两个文件夹 “node_global” 和 “node_cache” ,并复制它们的路径。

  • 以管理员身份运行 cmd ,输入以下两条指令:

npm config set prefix "D:\nodejs\node_global"
npm config set cache "D:\nodejs\node_cache"
  • 可以通过以下两条指令查看配置的路径:
npm config get prefix
npm config get cache
  • Win + X 点击 “系统” → “高级系统设置” → “环境变量(N)…”

    1. 双击 “用户变量(U)” 下的 PATH ,将 C:\Users\[用户名]\AppData\Roaming\npm 修改成 D:\nodejs\node_global

    2. 双击 “系统变量(S)” 下的 PATH ,新建 D:\nodejs\node_global\node_modulesD:\nodejs\node_cache ,最后一路点击确定即可。

注:此时 node_global 文件夹下并无 node_modules 文件夹,没有关系,先进行设置即可。

  • 配置完成后,全局安装一个 express 模块进行测试是否配置成功:以管理员身份运行 cmd ,输入指令 npm install express -g ,其中 -g 代表全局安装,此时 node_global 文件夹下才会自动创建一个名为 node_modules 的文件夹。

3)安装镜像

  • 以管理员身份运行 cmd ,输入指令 npm config set registry https://registry.npmmirror.com 安装淘宝镜像。

  • 输入指令 npm config get registry 查看是否安装成功。

【可选】如果想要使用 cnpm 命令行工具代替默认的 npm ,则进行以下操作:

  • 以管理员身份运行 cmd ,输入指令 npm install -g cnpm --registry=https://registry.npmmirror.com

  • 输入指令 cnpm -v 查看是否安装成功。

4)node.js 的常用命令

  • 检查版本
# 检查 Node.js 版本
node -v# 检查 npm 版本
npm -v
  • 初始化项目
# 初始化一个新的 Node.js 项目
npm init
  • 安装和卸载包
# 安装特定版本的 Node.js 包
npm install <package-name>@<version># 全局安装 Node.js 包
npm install -g <package-name># 卸载 Node.js 包
npm uninstall <package-name>
  • 查看已安装的包
# 查看全局安装的 Node.js 包
npm list -g --depth 0# 查看已安装的本地包
npm ls
  • 更新包
# 更新所有全局安装的 Node.js 包
npm update -g# 更新特定 Node.js 包
npm update <package-name>
  • 运行代码和启动应用程序
# 运行 Node.js 文件
node <filename.js># 使用 nodemon 启动应用程序(自动重启)
nodemon <filename.js># 在浏览器中打开应用程序
npm start# 指定环境变量启动应用程序
NODE_ENV=production node <filename.js>

参考文章:
【node.js安装及环境配置超详细教程【Windows系统安装包方式】】
【2024最新版Node.js下载安装及环境配置教程【保姆级】】
【Node.js安装及环境配置超详细教程【Windows系统】】

2. 安装 http-server 服务

http-server 是一个简单且快速的零配置命令行静态文件服务器,主要用于本地快速启动一个静态文件服务,它通常用于开发和测试环境。

  • 以管理员身份运行 cmd ,输入指令 npm install http-server -g 进行全局安装 http-server 服务。

  • 输入命令 http-server -v 可查看该服务是否安装成功。

3. 使用 http-server 开启服务

1)使用 http-server

  • Win + R 输入 cmd 进入命令提示符,通过 cd 操作将磁盘路径改至需要开启服务的路径下。

  • 输入命令 http-server -p 7890 指定端口开启服务器。

默认的访问地址是:http://127.0.0.1:8080

  • 启动成功可以通过 http://127.0.0.1:7890 进行访问。

  • 按下 Ctrl + C 终止服务。

2)详解 http-server [path] [options]

以下是 http-server 常用的一些命令和参数:

参数说明示例
[path]指定服务器根目录,默认当前目录http-server ./public
-p or --port <port>指定监听端口,默认 8080http-server -p 3000
-a or --address <address>绑定的地址,默认 0.0.0.0(所有地址)http-server -a 127.0.0.1
-c or --cache <time>缓存时间(秒)http-server -c 3600
-c-1-1 表示禁用缓存http-server -c-1
-d or --directory启用目录列表显示http-server -d
-i or --index <file>指定默认首页文件http-server -i index.html
-h or --help显示帮助信息http-server -h
-o or --open启动时自动在浏览器打开http-server -o
-g or --gzip启用 gzip 压缩http-server -g
-e or --ext <extension>设置默认扩展名,默认 htmlhttp-server -e htm
-s or --silent静默模式,不输出任何日志信息http-server -s
-r or --robots <file>指定 robots.txt 文件位置http-server -r ./robots.txt
--cors启用 CORS 跨域http-server --cors
-S or --ssl启用 HTTPShttp-server --ssl --cert ./cert.pem --key ./key.pem
-C or --cert <file>SSL 证书文件路径http-server -S -C ./cert.pem -K ./key.pem
-K or --key <file>SSL 私钥文件路径http-server -S -C ./cert.pem -K ./key.pem
-U or --utf8对 URL 使用 UTF-8 编码http-server -U
-P or --proxy <url>代理未找到的请求到指定 URLhttp-server -P http://example.com

参考文章:【http-server使用,启动本地服务器 & 使用serve包本地启动】

二、Web 静态服务器

1. 显示固定的页面

1)Python 代码

# 服务器端
import socketdef service_client(client_socket):# 1. 接收浏览器发送过来的请求 ,即 http 请求recv_data = client_socket.recv(4096).decode("utf-8")request_header_lines = recv_data.splitlines()for line in request_header_lines:print(line)# 2. 返回 http 格式的数据,给浏览器response_headers = "HTTP/1.1 200 OK\r\n"  # 200 表示找到这个资源response_headers += "\r\n"  # 用一个空的行与 body 进行隔开response_body = "hello world"# 将 response header 和 response body 发送给浏览器response = response_headers + response_bodyclient_socket.send(response.encode("utf-8"))client_socket.close()def main():# 1. 创建 TCP 套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用# 设置服务器端 4 次挥手之后资源能够立即释放,这样就保证下次运行程序时 可以立即绑定 8888 端口server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号,127.0.0.1 是本机对自己的网络地址,即本地回环地址ip = "127.0.0.1"port = 8888server_socket.bind((ip, port))print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))# 3. 变为监听套接字server_socket.listen(128)while True:# 4. 等待新客户端的链接client_socket, client_addr = server_socket.accept()# print(f'---Client [{client_addr[0]}:{client_addr[1]}] Link Success---')# 5. 为这个客户端服务service_client(client_socket)if __name__ == "__main__":main()

实现步骤:

  1. 运行上述服务器端代码。
  2. 在浏览器的地址栏里输入 “http://127.0.0.1:8888” 并回车。

2)结果展示

、

右击浏览器页面,选择 “检查” → “网络” ,输入 Ctrl + R 刷新纪录,再单击想要查看的名称就可以查看详细的标头信息。

2. 显示请求的页面

1)Python 代码

import socket
import re
import time# 服务器端
def service_client(new_socket, time_start):# 1. 接收浏览器发送过来的请求 ,即 http 请求request = new_socket.recv(4096).decode("utf-8")# 得到头部的每一行request_lines = request.splitlines()if request_lines:# 使用正则表达式获取请求的 urlret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])# 例如:'GET /how-to-learn-qt.html HTTP/1.1'if ret:file_name = ret.group(1)# 例如:/how-to-learn-qt.htmlif file_name == "/":file_name = "/index.html"print(">" * 30, file_name)  # 输出请求的 urlfor request_line in request_lines:print(request_line)  # 输出请求# 2. 返回 http 格式的数据,给浏览器try:f = open("./../html" + file_name, "rb")  # 打开请求的资源# 找不到资源就返回 404 Not Foundexcept FileNotFoundError:response = "HTTP/1.1 404 NOT FOUND\r\n"  # headerresponse += "\r\n"response += "------File Not Found-----"  # bodynew_socket.send(response.encode("utf-8"))else:response = "HTTP/1.1 200 OK\r\n"  # headerresponse += "\r\n"html_content = f.read()  # bodyf.close()new_socket.settimeout(5)try:# 2.1 将 response header 发送给浏览器new_socket.send(response.encode("utf-8"))# 2.2 将 response body 发送给浏览器new_socket.send(html_content)# 发送超时except socket.timeout:response = "HTTP/1.1 504 Gateway Timeout\r\n"  # headerresponse += "\r\n"response += "------Send Timeout-----"  # bodynew_socket.send(response.encode("utf-8"))# 关闭套接字new_socket.close()time_end = time.time()print(f'The total time spent is {time_end - time_start} seconds.')print('-' * 50)def main():# 1. 创建 TCP 套接字tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号ip = "127.0.0.1"port = 7890tcp_server_socket.bind((ip, port))print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))# 3. 变为监听套接字tcp_server_socket.listen(128)while True:# 4. 等待新客户端的链接new_socket, client_addr = tcp_server_socket.accept()# print(f'---Client [{client_addr[0]}:{client_addr[1]}] Link Success---')time_start = time.time()# 5. 为这个客户端服务service_client(new_socket, time_start)# 关闭监听套接字# tcp_server_socket.close()if __name__ == "__main__":main()

HTML 资源下载:【Python 实现 Web 静态服务器中需要使用到的 HTML 资源】

实现步骤:

  1. Win + R 输入 cmd 进入命令提示符,通过 cd 操作将磁盘路径改至需要开启服务的路径下,并输入命令 http-server -p 7890 指定 7890 端口开启服务器。
  2. 运行上述服务器端代码。
  3. 在浏览器的地址栏里输入 “http://127.0.0.1:7890” 并回车。

2)结果展示

3. 多进程显示页面

Python 代码:

import socket
import re
import multiprocessing
import time# 服务器端
def service_client(new_socket, time_start):# 1. 接收浏览器发送过来的请求 ,即 http 请求request = new_socket.recv(4096).decode("utf-8")# 得到头部的每一行request_lines = request.splitlines()if request_lines:# 使用正则表达式获取请求的 urlret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])# 例如:'GET /how-to-learn-qt.html HTTP/1.1'if ret:file_name = ret.group(1)# 例如:/how-to-learn-qt.htmlif file_name == "/":file_name = "/index.html"print(">" * 30, file_name)  # 输出请求的 urlfor request_line in request_lines:print(request_line)  # 输出请求# 2. 返回 http 格式的数据,给浏览器try:f = open("./../html" + file_name, "rb")  # 打开请求的资源# 找不到资源就返回 404 Not Foundexcept FileNotFoundError:response = "HTTP/1.1 404 NOT FOUND\r\n"  # headerresponse += "\r\n"response += "------File Not Found-----"  # bodynew_socket.send(response.encode("utf-8"))else:response = "HTTP/1.1 200 OK\r\n"  # headerresponse += "\r\n"html_content = f.read()  # bodyf.close()new_socket.settimeout(5)try:# 2.1 将 response header 发送给浏览器new_socket.send(response.encode("utf-8"))# 2.2 将 response body 发送给浏览器new_socket.send(html_content)# 发送超时except socket.timeout:response = "HTTP/1.1 504 Gateway Timeout\r\n"  # headerresponse += "\r\n"response += "------Send Timeout-----"  # bodynew_socket.send(response.encode("utf-8"))# 关闭子进程new_socket.close()time_end = time.time()print(f'The total time spent is {time_end - time_start} seconds.')print('-' * 50)def main():# 1. 创建 TCP 套接字tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号ip = "127.0.0.1"port = 7890tcp_server_socket.bind((ip, port))print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))# 3. 变为监听套接字tcp_server_socket.listen(128)while True:# 4. 等待新客户端的链接new_socket, client_addr = tcp_server_socket.accept()# print(f'---Client [{client_addr[0]}:{client_addr[1]}] Link Success---')time_start = time.time()# 5. 为这个客户端服务p = multiprocessing.Process(target=service_client, args=(new_socket, time_start))p.start()# 关闭父进程new_socket.close()# 关闭监听套接字# tcp_server_socket.close()if __name__ == "__main__":main()

实现步骤:

  1. 运行上述服务器端代码。
  2. 在浏览器的地址栏里输入 “http://127.0.0.1:7890” 并回车。

4. 多线程显示页面

Python 代码:

import socket
import re
import threading
import time# 服务器端
def service_client(new_socket, time_start):# 1. 接收浏览器发送过来的请求 ,即 http 请求request = new_socket.recv(4096).decode("utf-8")# 得到头部的每一行request_lines = request.splitlines()if request_lines:# 使用正则表达式获取请求的 urlret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])# 例如:'GET /how-to-learn-qt.html HTTP/1.1'if ret:file_name = ret.group(1)# 例如:/how-to-learn-qt.htmlif file_name == "/":file_name = "/index.html"print(">" * 30, file_name)  # 输出请求的 urlfor request_line in request_lines:print(request_line)  # 输出请求# 2. 返回 http 格式的数据,给浏览器try:f = open("./../html" + file_name, "rb")  # 打开请求的资源# 找不到资源就返回 404 Not Foundexcept FileNotFoundError:response = "HTTP/1.1 404 NOT FOUND\r\n"  # headerresponse += "\r\n"response += "------File Not Found-----"  # bodynew_socket.send(response.encode("utf-8"))else:response = "HTTP/1.1 200 OK\r\n"  # headerresponse += "\r\n"html_content = f.read()  # bodyf.close()new_socket.settimeout(5)try:# 2.1 将 response header 发送给浏览器new_socket.send(response.encode("utf-8"))# 2.2 将 response body 发送给浏览器new_socket.send(html_content)# 发送超时except socket.timeout:response = "HTTP/1.1 504 Gateway Timeout\r\n"  # headerresponse += "\r\n"response += "------Send Timeout-----"  # bodynew_socket.send(response.encode("utf-8"))# 关闭子线程new_socket.close()time_end = time.time()print(f'The total time spent is {time_end - time_start} seconds.')print('-' * 50)def main():# 1. 创建 TCP 套接字tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号tcp_server_socket.bind(("127.0.0.1", 7890))# 3. 变为监听套接字tcp_server_socket.listen(128)while True:# 4. 等待新客户端的链接new_socket, client_addr = tcp_server_socket.accept()# print(f'---Client [{client_addr[0]}:{client_addr[1]}] Link Success---')time_start = time.time()# 5. 为这个客户端服务p = threading.Thread(target=service_client, args=(new_socket, time_start))p.start()# 多线程时,new_socket 传递给子线程以后,主线程不能关闭# new_socket.close()# 关闭监听套接字# tcp_server_socket.close()if __name__ == "__main__":main()

实现步骤:

  1. 运行上述服务器端代码。
  2. 在浏览器的地址栏里输入 “http://127.0.0.1:7890” 并回车。

5. 非阻塞模式显示页面

Python 代码:

import time
import socket
import sys
import re# 定义一个 WSGI 服务器的类
class WSGIServer(object):def __init__(self, ip, port, documents_root):# 1. 创建套接字self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定本地信息self.server_socket.bind((ip, port))# 3. 变为监听套接字self.server_socket.listen(128)# 4. 设置非阻塞self.server_socket.setblocking(False)# 客户列表self.client_socket_list = list()# 静态资源的路径self.documents_root = documents_rootdef run_forever(self):  # 运行服务器while True:# 等待对方链接try:new_socket, new_addr = self.server_socket.accept()# 未有浏览器链接except BlockingIOError:passelse:time_start = time.time()# 设置非阻塞new_socket.setblocking(False)# 添加客户至客户列表self.client_socket_list.append([new_socket, new_addr, time_start])print(f'New client ({new_addr[0]} : {new_addr[1]}) link success')# 遍历列表中的连接,如果有浏览器发过来数据,那么就处理for client_socket in self.client_socket_list:try:request = client_socket[0].recv(4096).decode('utf-8')except BlockingIOError:passelse:if request:  # 有数据就处理数据print(f'Client [{client_socket[1][1]}] is working')self.deal_with_request(request, client_socket[0])else:  # 客户与浏览器断开client_socket[0].close()time_end = time.time()print(f'Client [{client_socket[1][1]}] finish request')print(f'The total time spent is {time_end - client_socket[2]} seconds.')self.client_socket_list.remove(client_socket)def deal_with_request(self, request, client_socket):  # 处理数据request_lines = request.splitlines()# 例如:'GET /how-to-learn-qt.html HTTP/1.1'ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])if ret:# 例如:/how-to-learn-qt.htmlfile_name = ret.group(2)if file_name == "/":file_name = "/index.html"print(">" * 30, file_name)for i, line in enumerate(request_lines):print(i, line)# 读取文件数据try:f = open(self.documents_root + file_name, "rb")except PermissionError:response_body = "file not found,Please enter the correct URL"response_header = "HTTP/1.1 404 not found\r\n"response_header += "Content-Type: text/html; charset=utf-8\r\n"response_header += "Content-Length: %d\r\n" % (len(response_body))response_header += "\r\n"# 将 header 返回给浏览器client_socket.send(response_header.encode('utf-8'))# 将 body 返回给浏览器client_socket.send(response_body.encode("utf-8"))else:content = f.read()f.close()response_body = contentresponse_header = "HTTP/1.1 200 OK\r\n"response_header += "Content-Length: %d\r\n" % (len(response_body))response_header += "\r\n"# 将 header 和 body 返回给浏览器client_socket.send(response_header.encode('utf-8') + response_body)# 设置服务器服务静态资源时的路径
DOCUMENTS_ROOT = "./../html"def main():  # 控制 web 服务器整体if len(sys.argv) == 3:ip = sys.argv[1]port = sys.argv[2]if port.isdigit():port = int(port)print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))http_server = WSGIServer(ip, port, DOCUMENTS_ROOT)http_server.run_forever()else:print('The port number was entered incorrectly')else:print("Run the command : python3 4.non-blocking.py 127.0.0.1 7890")if __name__ == "__main__":main()

实现步骤:

  1. 图形化界面或命令行传参 “127.0.0.1 7890”
  2. 运行上述服务器端代码。
  3. 在浏览器的地址栏里输入 “http://127.0.0.1:7890” 并回车。

“BlockingIOError: [WinError 10035] 无法立即完成一个非阻止性套接字操作” 的解决方法见:【Python BlockingIOError 阻塞错误】

6. 利用 epoll 显示页面(Linux 下运行)

Python 代码:

# !/usr/bin/python
# -*- coding:utf-8 -*-import socket
import select
import reBASE_PATH = './../html'# 服务器端
def service_client(new_socket, request):request_lines = request.splitlines()if not request_lines:returnret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])if ret:file_name = ret.group(1)if file_name == "/":file_name = "/index.html"print("*" * 50, file_name)print(request)# 2. 返回 http 格式的数据,给浏览器try:f = open(BASE_PATH + file_name, "rb")except FileNotFoundError:response = "HTTP/1.1 404 NOT FOUND\r\n"response += "\r\n"response += "------file not found-----"new_socket.send(response.encode("utf-8"))else:html_content = f.read()f.close()response_body = html_contentresponse_header = "HTTP/1.1 200 OK\r\n"response_header += "Content-Length:%d\r\n" % len(response_body)response_header += "\r\n"response = response_header.encode("utf-8") + response_bodynew_socket.send(response)def main():# 1. 创建套接字tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号ip = "192.168.200.128"port = 7890tcp_server_socket.bind((ip, port))print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))# 3. 变为监听套接字tcp_server_socket.listen(128)# 将套接字变为非堵塞tcp_server_socket.setblocking(False)# 4. 创建一个epoll对象epl = select.epoll()# 将监听套接字对应的 fd 注册到 epoll 中# 注册并监控 tcp_server_socket, select.EPOLLIN 为可读事件epl.register(tcp_server_socket.fileno(), select.EPOLLIN)fd_event_dict = dict()while True:# 默认会堵塞,直到 os 监测到数据到来 通过事件通知方式告诉这个程序,此时才会解堵塞# 轮询注册的事件fd_event_list = epl.poll()# [(fd, event), (套接字对应的文件描述符, 这个文件描述符到底是什么事件)]for fd, event in fd_event_list:# 等待新客户端的链接if fd == tcp_server_socket.fileno():new_socket, client_addr = tcp_server_socket.accept()# 注册并监控 new_socketepl.register(new_socket.fileno(), select.EPOLLIN)fd_event_dict[new_socket.fileno()] = new_socket# 判断已经链接的客户端是否有数据发送过来elif event == select.EPOLLIN:recv_data = fd_event_dict[fd].recv(4096).decode("utf-8")# 有数据则处理数据,通过不遍历来定位 socketif recv_data:service_client(fd_event_dict[fd], recv_data)# 客户与浏览器断开else:fd_event_dict[fd].close()# 取消注册epl.unregister(fd)# 从字典中移除del fd_event_dict[fd]# 关闭监听套接字# tcp_server_socket.close()if __name__ == "__main__":main()

实现步骤:

  1. 开启虚拟机,然后配置 PyCharm 连接远程服务器,并切换 Python 解释器。
  2. 将需要运行的 .py 代码和文件部署上传至 Linux 的文件夹下(右键文件 → “部署” → “上传到…”)。
  3. 运行上述服务器端代码(注意这时的 IP 地址并非本地回环地址,而是 Liunx 的 IPv4 地址)。
  4. 在浏览器的地址栏里输入 “http://192.168.200.128:7890” 并回车。

配置 PyCharm 连接远程服务器的步骤见:【Python-简单网络编程 I】

7. 利用 gevent 显示页面

Python 代码:

import gevent
from gevent import monkeymonkey.patch_all()import socket
import reBASE_PATH = './../html'def service_client(new_socket):# 接收 http 请求request = new_socket.recv(4096).decode('utf-8')if request:request_lines = request.splitlines()ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])if ret:file_name = ret.group(1)if file_name == "/":file_name = "/index.html"print(">" * 30, file_name)print(request)  # 输出请求try:f = open(BASE_PATH + file_name, "rb")except FileNotFoundError:response = "HTTP/1.1 404 NOT FOUND\r\n"response += "\r\n"response += "-------file not found-------"new_socket.send(response)else:html_content = f.read()f.close()response = "HTTP/1.1 200 OK\r\n"response += "\r\n"new_socket.send(response.encode('utf-8'))new_socket.send(html_content)new_socket.close()def main():# 1. 初始化tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 确保端口复用tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 2. 绑定 IP 和端口号ip = "127.0.0.1"port = 7890tcp_server_socket.bind((ip, port))print("The ip and port used by the HTTP server : (%s : %s)" % (ip, port))# 3. 变为监听套接字tcp_server_socket.listen(128)while True:# 4. 等待新客户端的链接new_socket, socket_addr = tcp_server_socket.accept()# print(f'New client ({socket_addr[0]} : {socket_addr[1]}) link success')# 创建一个普通的 greenlet 对象并切换gevent.spawn(service_client, new_socket)# tcp_server_socket.close()if __name__ == '__main__':main()

实现步骤:

  1. 运行上述服务器端代码。
  2. 在浏览器的地址栏里输入 “http://127.0.0.1:7890” 并回车。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/84578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MPMA:Preference Manipulation Attack Against Model Context Protocol

概要 MCP作为提供给LLM作为工具调用的标准化协议被广泛应用&#xff0c;但是MCP在安全方面还比较脆弱。本文提出了一种MPMA攻击方法通过在工具的名字或描述中插入具有操控性的文字、短语来操控LLM选择MCP server的过程。 不了解MCP的具体细节可以看看我写的这篇文章MCP 场景…

Vim 替换命令完整学习笔记

Vim 替换命令完整学习笔记 文章目录 Vim 替换命令完整学习笔记1. 核心概念2. 替换命令基本语法2.1 基本格式2.2 分隔符选择2.3 范围指定 3. 替换标志详解3.1 基础标志3.2 高级标志3.3 标志组合 4. 正则表达式在替换中的应用4.1 基础正则表达式4.2 字符类和量词4.3 分组和引用 5…

@RequestBody和@ResponseBody注解的作用是什么

@RequestBody和@ResponseBody注解的作用是什么 文章目录 @RequestBody和@ResponseBody注解的作用是什么@RequestBody和@ResponseBody注解的作用是什么SpringMVC的请求与响应模型1. 请求的处理流程1.1 DispatcherServlet作为入口1.2 Handler处理器与Controller1.3 HandlerAdapte…

质因数分解_java

什么是质因数&#xff1f; 说的通俗一点就是&#xff0c;这个数既是因数&#xff0c;又是质数。但是1不是质因数(不是质数)。然后比如122*2*3&#xff0c;里边的2&#xff0c;3都是质数&#xff0c;并且也是12的因数&#xff0c;所以2、3就是12的质因数。 因为本人很菜&#xf…

SpringDoc集成到Springboot

1.Maven引入jar包 <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1.6.14</version> </dependency> 2.新建OpenApiConfig文件&#xff0c;代码如下 package com.elan…

Memory Repair (五)

Compression Algorithm and Fuse Box Organization 通常情况下&#xff0c;这部分信息对于实现BISR&#xff08;内置自修复&#xff09;并非必需&#xff0c;但对于诊断问题可能有所帮助。 Compression and Fuse Box Organization Overview BISR controller采用的压缩算法基于两…

双系统(win+linux)根目录扩容(不掉GPU驱动)

先看效果&#xff0c;原来的根目录仅50G&#xff0c;从/home节点分出扩容后变为250GB&#xff1b; 因为根分区是系统当前运行的文件系统&#xff0c;Linux系统启动后会锁定根分区&#xff0c;防止对其进行修改。这时使用系统内的工具&#xff08;如gparted&#xff09;调整根分…

oracle 23ai对象注释新特性ANNOTATIONS

我们知道以前数据库版本注释方式是用COMMENT&#xff0c;如下 COMMENT ON COLUMN 表名.字段名 IS 字段注释; oracle 23ai对象注释有新增了ANNOTATIONS&#xff0c;比如创建如下表&#xff1a; SQL> create table test.t_user( id number, name varchar(200) ANNOTATIONS …

VMware 虚拟机开机自启动配置指南

方法一&#xff1a;通过启动文件夹设置&#xff08;简单版&#xff09; 打开启动文件夹&#xff1a; 按下 Win R 快捷键输入 shell:startup 并回车 创建启动脚本&#xff1a; 在打开的文件夹中右键新建一个文本文件命名为 vm_start.bat输入以下内容&#xff1a; echo off &…

2025pmx文件怎么打开blender和虚幻

pmx文件怎么打开blender 前言 一坑接一坑。 意思很简单&#xff0c;就是给Blender、3dsmax装插件&#xff0c;然后就可以打开了。但是报错就要多走很多错路。 记录一下。 内容 参考文章&#xff1a;https://blog.csdn.net/c858845275/article/details/144180555 我的Ble…

Kotlin基础语法五

继承与重载的open关键字 KT所有的类&#xff0c;默认是final修饰的&#xff0c;不能被继承&#xff0c;和Java相反 open&#xff1a;移除final修饰 类型转换 open class Person2(private val name: String) {fun showName() "父类 的姓名是【$name】"// KT所有的…

MySQL数据库:关系型数据库的基石

文章目录 每日一句正能量前言一、MySQL简介&#xff08;一&#xff09;什么是MySQL&#xff1f;&#xff08;二&#xff09;MySQL的历史 二、MySQL的特点&#xff08;一&#xff09;开源与免费&#xff08;二&#xff09;高性能&#xff08;三&#xff09;跨平台支持&#xff0…

【kafka】Golang实现分布式Masscan任务调度系统

要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收扫描任务信息通过调用masscan启动探测任务,获取进度和结果信息,…

ARM 和 x86_64是什么关系

什么是 ARM 和 x86_64&#xff1f; 它们都是 CPU 指令集架构&#xff08;ISA&#xff09; 指令集架构&#xff08;Instruction Set Architecture&#xff09;就是&#xff1a; CPU 能够理解和执行的“语言”和“命令格式”。 类比解释&#xff1a;指令集就像“语言” 类比对…

nginx配置中有无‘‘/’’的区别

在Nginx配置中&#xff0c;location指令末尾的斜杠/和proxy_pass目标地址末尾的斜杠/组合使用会产生显著差异。以下是四种组合的区别详解&#xff1a; ​​核心区别对比表​​ 配置方案匹配规则请求URI传递逻辑实际转发效果示例location /api/ proxy_pass ...701/仅匹配/api/…

系统安全之身份认证

本篇我们对常用的身份认证协议做简要的梳理&#xff0c;包括主流的 HTTP 相关认证协议以及证书密钥对、新兴的 WebAuthn 认证。 HTTP 协议认证 RFC 7235 中定义了 HTTP 协议的认证框架&#xff0c;要求在支持 HTTP 协议的服务器&#xff0c;如果访问服务的身份验证失败&#…

部署http服务

使用flask搭建一个http服务&#xff0c;能够通过本地的另外一个终端访问对应接口&#xff0c;拿到服务端的计算结果 服务端&#xff1a; 创建一个test_http_dtw.py并运行 from flask import Flask, request, jsonifyapp Flask(__name__)# 示例分析函数 def analysis(data):…

WLAN 技术指南:从入门到原理

文章目录 目录 文章目录 前言 一.WLAN 基本概念 有线侧组网概念 AP-AC 组网方式 AC 连接方式 CAPWAP 协议 无线侧组网概念 无线信道 ​编辑 BSS/SSID/BSSID ​编辑 VAP ESS 二.WLAN 组网架构 基本的 WLAN 组网架构 四.WLAN 工作原理 AP 上线 AP 获取 IP 地址阶段 CAP…

语言学习专用AI播放器推荐:LLPlayer

学语言&#xff0c;经常会看大量的比较优秀的视频材料&#xff0c;那么推荐一款语言学习利器&#xff0c;极大提高生产力。 LLPlayer 是一款专为语言学习者设计的独特视频播放器。 它具有许多重要功能&#xff0c;例如可同时显示文本字幕和位图字幕、使用 OpenAI Whisper 自动…

mysql 关联表查询,索引失效

来源表: ##示例 CREATE TABLE order_wide (order_id varchar(33) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 订单ID,member_id int(11) DEFAULT NULL COMMENT 用户ID,content varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 订单标签,PRIMARY KEY (order_…