Python实例题:简单的 Web 服务器

目录

Python实例题

题目

要求:

解题思路:

代码实现:

Python实例题

题目

简单的 Web 服务器

要求

  • 使用 Python 的 socket 模块实现一个简单的 HTTP 服务器。
  • 支持以下功能:
    • 处理 GET 和 POST 请求
    • 静态文件服务(HTML、CSS、JavaScript、图片等)
    • 简单的路由系统
    • 错误处理(404、500 等)
  • 添加多线程支持,以处理并发请求。

解题思路

  • 使用 socket 建立网络连接。
  • 解析 HTTP 请求头,处理不同类型的请求。
  • 使用线程池处理并发连接。

代码实现

import socket
import threading
import os
import mimetypes
from urllib.parse import urlparse, parse_qsclass WebServer:def __init__(self, host='localhost', port=8080, document_root='www'):self.host = hostself.port = portself.document_root = document_rootself.routes = {'GET': {},'POST': {}}self.server_socket = Noneself.running = Falsedef route(self, method, path, handler):"""注册路由处理函数"""self.routes[method][path] = handlerdef start(self):"""启动服务器"""self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.server_socket.bind((self.host, self.port))self.server_socket.listen(5)self.running = Trueprint(f"服务器运行中: http://{self.host}:{self.port}")try:while self.running:client_socket, client_address = self.server_socket.accept()print(f"接受来自 {client_address} 的连接")# 创建线程处理请求client_handler = threading.Thread(target=self.handle_client,args=(client_socket,))client_handler.start()except KeyboardInterrupt:self.stop()def stop(self):"""停止服务器"""self.running = Falseif self.server_socket:self.server_socket.close()print("服务器已停止")def handle_client(self, client_socket):"""处理客户端请求"""try:# 接收请求数据request_data = client_socket.recv(1024).decode('utf-8')if not request_data:return# 解析请求request_lines = request_data.splitlines()request_line = request_lines[0]method, path, _ = request_line.split(' ', 2)# 解析查询参数parsed_url = urlparse(path)path = parsed_url.pathquery_params = parse_qs(parsed_url.query)# 处理 POST 请求体post_data = {}if method == 'POST':# 找到请求头和请求体的分隔线body_index = request_data.find('\r\n\r\n')if body_index != -1:body = request_data[body_index + 4:]post_data = parse_qs(body)# 处理路由if path in self.routes[method]:response = self.routes[method][path](query_params, post_data)else:# 静态文件服务response = self.serve_static_file(path)# 发送响应client_socket.sendall(response)except Exception as e:print(f"处理请求时出错: {e}")error_response = self.generate_error_response(500)client_socket.sendall(error_response)finally:# 关闭连接client_socket.close()def serve_static_file(self, path):"""提供静态文件服务"""# 处理根路径if path == '/':path = '/index.html'# 构建文件路径file_path = os.path.join(self.document_root, path[1:])# 检查文件是否存在if not os.path.exists(file_path):return self.generate_error_response(404)# 检查是否是目录if os.path.isdir(file_path):return self.generate_error_response(403)try:# 读取文件内容with open(file_path, 'rb') as file:content = file.read()# 确定 MIME 类型content_type, _ = mimetypes.guess_type(file_path)if not content_type:content_type = 'application/octet-stream'# 生成响应头response_headers = (f'HTTP/1.1 200 OK\r\n'f'Content-Type: {content_type}\r\n'f'Content-Length: {len(content)}\r\n'f'\r\n').encode('utf-8')return response_headers + contentexcept Exception as e:print(f"读取文件时出错: {e}")return self.generate_error_response(500)def generate_error_response(self, status_code):"""生成错误响应"""status_messages = {404: 'Not Found',403: 'Forbidden',500: 'Internal Server Error'}status_message = status_messages.get(status_code, 'Error')# 生成错误页面error_page = (f'<html><body><h1>{status_code} {status_message}</h1></body></html>').encode('utf-8')# 生成响应头response_headers = (f'HTTP/1.1 {status_code} {status_message}\r\n'f'Content-Type: text/html\r\n'f'Content-Length: {len(error_page)}\r\n'f'\r\n').encode('utf-8')return response_headers + error_pagedef main():# 创建服务器实例server = WebServer(document_root='www')# 注册动态路由def home_handler(query_params, post_data):response_body = '<html><body><h1>欢迎来到我的网站!</h1></body></html>'.encode('utf-8')response_headers = ('HTTP/1.1 200 OK\r\n''Content-Type: text/html\r\n'f'Content-Length: {len(response_body)}\r\n''\r\n').encode('utf-8')return response_headers + response_bodydef echo_handler(query_params, post_data):message = query_params.get('message', [''])[0]response_body = f'<html><body><p>你发送的消息是: {message}</p></body></html>'.encode('utf-8')response_headers = ('HTTP/1.1 200 OK\r\n''Content-Type: text/html\r\n'f'Content-Length: {len(response_body)}\r\n''\r\n').encode('utf-8')return response_headers + response_bodyserver.route('GET', '/', home_handler)server.route('GET', '/echo', echo_handler)# 启动服务器try:server.start()except KeyboardInterrupt:passif __name__ == "__main__":main()

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

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

相关文章

3.Stable Diffusion WebUI本地部署和实践

本文看了(68 封私信) 逼真的图片生产 | Stable Diffusion WebUI本地部署看这一篇就够了 - 知乎和(68 封私信) Stable Diffusion WebUI 实践: 基本技法及微调 - 知乎&#xff0c;本人根据它们部署了一遍&#xff0c;中间遇到一些报错&#xff0c;但根据报错提示解决了问题&#…

阿里最新开源:Mnn3dAvatar 3D数字人框架, 无需联网,本地部署可离线运行,支持多模态实时交互

Mnn3dAvatar 3D数字人框架是基于阿里巴巴开源的轻量级深度学习推理框架MNN&#xff08;Mobile Neural Network&#xff09;开发的全新3D数字人框架。Aibot亲测这是一个可以在本地运行、完全离线、支持多模态实时交互的智能数字人App。可以在本地私有部署。感兴趣的同学可以拿来…

03【C++ 入门基础】函数重载

文章目录 引言函数重载函数重载的使用函数重载的原理extern “C” 静态多态 总结 引言 通过00【C 入门基础】前言得知&#xff0c;C是为了解决C语言在面对大型项目的局限而诞生&#xff1a; C语言面对的现实工程问题&#xff08;复杂性、可维护性、可扩展性、安全性&#xff0…

改写一个小项目: flask -------------------> next js

现在&#xff0c;请把上面改写代码的过程中&#xff0c;所有的过程&#xff0c;都写下来&#xff0c;写为文章的形式&#xff0c;内容比较长&#xff0c;你可以分多次输出。而且要求语言幽默&#xff0c;苦中作乐的心态。分条理&#xff0c;要清晰。一场从 Flask 到 Next.js 的…

线性相关和线性无关

在线性代数中&#xff0c;线性相关和线性无关是刻画向量组性质的核心概念&#xff0c;以下是关于它们的重要结论总结&#xff1a; 一、基本定义与核心判定 线性相关的定义 向量组 { α 1 , α 2 , … , α m } \{\alpha_1, \alpha_2, \dots, \alpha_m\} {α1​,α2​,…,αm​…

非常有科技感的wpf GroupBox 控件

效果 样式 <Style TargetType="GroupBox"><Setter Property="Margin" Value="10,5" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="GroupBox"><Grid>&l…

【Java--SQL】${}与#{}区别和危害

目录 一区别 二SQL${}注入问题 一区别 在MyBatis中&#xff0c;#{}和${}是两种不同的参数占位符&#xff0c;用于在SQL语句中引用变量或参数。它们的区别如下&#xff1a; 1.#{}占位符&#xff08;预编译&#xff09;&#xff1a;#{}是MyBatis中的预编译占位符&#xff0c;…

【科技核心期刊推荐】计算机与数字工程

【论文发表利器】《计算机技术与工程应用》——工程技术领域的学术新天地&#xff01; 作为计算机技术与工程应用交叉领域的前沿期刊&#xff0c;《计算机技术与工程应用》期刊&#xff0c;聚焦算法、系统结构、信息融合与安全、图像处理等方向&#xff0c;为学术界提供了一个…

导出docker-compse.yml中docker镜像成tar文件

#!/bin/bash # 确保脚本在正确的目录下运行 SCRIPT_DIR$(dirname "$(realpath "$0")") cd "$SCRIPT_DIR" || exit 1 # 定义docker-compose文件路径 COMPOSE_FILE"${SCRIPT_DIR}/docker-compose.yml" # 创建导出目录 EXPORT_DIR"$…

ECMAScript 2019(ES2019):数组与对象操作的精细化升级

1.版本背景与发布 发布时间&#xff1a;2019年6月&#xff0c;由ECMA International正式发布&#xff0c;标准编号为ECMA-262 10th Edition。历史意义&#xff1a;作为ES6之后的第四次年度更新&#xff0c;ES2019聚焦于数组、对象和字符串操作的精细化改进&#xff0c;提升开发…

2.1.1 配置堡垒机以控制Linux资产文件传输

文章目录 一、试题及考试说明二、操作步骤1. 启动JumpServer服务&#xff0c;浏览器登录&#xff08;admin/Sjtu1896&#xff09;2. 创建堡垒机用户&#xff0c;用户名为“ops01”格式命名&#xff0c;邮箱以为“ops01jumpserver.cn”&#xff0c;使用密码“admin123”&#xf…

react ant-design通用页面自适应适配不同分辨率屏幕的方法工具类

该方法会根据 目标分辨率&#xff08;options.width/height&#xff09; 和 当前窗口尺寸&#xff08;innerWidth/innerHeight&#xff09; 计算缩放比例&#xff0c;并保持 等比例缩放&#xff08;Math.min(scaleX, scaleY)&#xff09;&#xff0c;确保内容不变形&#xff1a…

基于IEC61499实现的工业机器视觉方案

1.什么是机器视觉 机器视觉就是赋予机器看懂图像的能力。它是一门涉及人工智能、计算机科学、图像处理、光学、机械工程和自动化的交叉技术领域。核心目标是&#xff1a;通过摄像头或其他成像设备获取图像或视频&#xff0c;然后利用计算机算法对这些图像进行分析和理解&#x…

机电一体化论文写作实战指南:从创新设计到工程验证的完整路径

机电论文的“技术-表达”鸿沟 某高校团队研发的智能抓取系统实物表现优异&#xff0c;却被审稿人质疑&#xff1a; “未说明机电耦合设计对性能的影响”——这揭示了机电一体化研究的核心痛点&#xff1a;强工程弱理论。本文基于217篇高影响力论文&#xff0c;拆解从技术到写作…

MySQL 配置参数调优:根据工作负载调整服务器设置

MySQL 数据库的默认配置参数是为了适应各种通用场景而设定的,它们通常无法最大化发挥服务器硬件的潜力,也无法完全匹配特定应用程序的工作负载。一个未优化的 MySQL 配置,在面对高并发、大数据量或特定查询模式时,很容易成为系统性能的瓶颈。 配置参数调优,就是根据你的服…

嵌入式Linux驱动开发基础-2 LED驱动

imx6ull中GPIO涉及寄存器 1&#xff1a;CCM寄存器 GPIOx 要用 CCM_CCGRy 寄存器中的 2 位来决定该组 GPIO 是否使能。哪组 GPIO 用哪个 CCM_CCGR 寄存器来设置。 CCM_CCGR 寄存器中某 2 位的取值含义如下&#xff1a; 00 &#xff1a;该 GPIO 模块全程被关闭 01 &…

深度解析】使用Go语言实现JWT:从原理到实践

JWT&#xff08;JSON Web Token&#xff09;已成为现代Web应用中身份验证的基石。本文深入剖析如何用Go语言实现JWT&#xff0c;从基础概念、底层机制到完整代码实践&#xff0c;助你全面掌握。 一、JWT概述 JWT是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;用…

深入解读 DeepSeek-V3 架构及落地的挑战

从多专家架构&#xff08;MoE&#xff09;到模型落地实战的一线观察 一、引言&#xff1a;DeepSeek-V3 是什么&#xff1f; 在大模型百花齐放的今天&#xff0c;DeepSeek-V3 作为 DeepSeek 系列的第三代开源模型&#xff0c;不仅延续了高质量对话能力&#xff0c;还在架构上迈…

前端进阶之路-从传统前端到VUE-JS(第二期-VUE-JS框架结构分析)

经过上期内容的学习&#xff0c;我们已经可以构建一个VUE-CLI框架了&#xff0c;接下来我们分析一下这个框架&#xff0c;毕竟知己知彼&#xff0c;百战百胜 我们创建完成后可以看到以下内容 接下来我们分析一下他的文件结构 node_modules用于存放项目所依赖的第三方模块和包…

网络协议 / 加密 / 签名总结

加密方式&#xff1a; 对称加密&#xff1a;key 不可公开。 非对称加密&#xff1a;公钥加密的信息只有私钥能解密。私钥加密的信息只有公钥能解密&#xff0c;且公钥只能解密私钥加密的信息&#xff08;用于签名&#xff09;。 非对称加密应用&#xff1a; 签名&#xff1a…