Python Socket服务启动后仅打印监听信息即阻塞、404页读取问题求解
Python Socket HTTP服务停滞问题修复方案
核心停滞原因
listen() 方法的作用仅仅是将Socket标记为被动监听模式、初始化待处理连接队列,本身不会主动接收、处理任何客户端请求。你当前的代码执行到listen()后,缺失了「阻塞等待客户端连接 -> 读取请求数据 -> 构造HTTP响应 -> 发送响应并关闭连接」的完整处理链路,所以打印完启动日志后要么直接退出进程,要么卡在无意义的阻塞调用上,完全无法响应请求。
另外两个常见的附加问题:
- 手动获取本机IP的逻辑容易取到虚拟网卡IP、IPv6地址,导致地址绑定失败或仅能部分网段访问
- 没有异常捕获、连接超时配置,只要单个请求异常就会导致整个服务崩溃
修复后可直接运行的代码
这个版本实现了本地读取404页面、全链路异常处理、端口复用、连接超时控制,直接复制即可用:
import socket import os # 基础配置 PORT = 9000 # 绑定0.0.0.0表示监听所有网卡地址,无需手动获取本机IP,避免IP识别错误 BIND_HOST = "0.0.0.0" BUFFER_SIZE = 1024 def load_404_page(): """从本地文件读取404页面内容,读取失败返回兜底文本""" try: # 404.html放在脚本同目录即可 file_path = os.path.join(os.path.dirname(__file__), "404.html") with open(file_path, "r", encoding="utf-8") as f: return f.read() except Exception: return "<h1>404 Not Found</h1>" def main(): # 初始化Socket实例 server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 配置端口复用,必须在bind前调用,避免重启时端口占用报错 server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 绑定地址并开启监听,队列最大长度设为128 server_sock.bind((BIND_HOST, PORT)) server_sock.listen(128) print(f"服务已启动,监听端口: {PORT}") print(f"绑定主机地址: {BIND_HOST},可通过127.0.0.1或本机局域网IP访问") # 启动时一次性加载404页面到内存,避免每次请求重复读磁盘 page_404 = load_404_page() resp_404 = f"HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=utf-8\r\n\r\n{page_404}".encode("utf-8") # 主循环:持续等待客户端连接(这是之前缺失的核心逻辑) while True: conn = None try: # 阻塞等待客户端连接 conn, client_addr = server_sock.accept() # 设置单连接5秒超时,避免无效连接长期占用资源 conn.settimeout(5) print(f"收到来自{client_addr}的请求") # 读取请求数据 req_data = conn.recv(BUFFER_SIZE).decode("utf-8", errors="ignore") if not req_data: conn.close() continue # 简单解析请求路径 req_line = req_data.split("\r\n")[0] method, path, _ = req_line.split(" ") # 示例路由:访问根路径返回200首页,其余路径返回404 if path == "/": resp_body = "<h1>Hello Socket HTTP Server</h1>" resp = f"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n{resp_body}".encode("utf-8") conn.sendall(resp) else: conn.sendall(resp_404) conn.close() except Exception as e: print(f"处理请求出错: {str(e)}") # 出错时也要保证连接正常关闭 if conn: try: conn.close() except: pass continue if __name__ == "__main__": main()
本地404页面实现说明
- 在脚本所在文件夹新建
404.html文件,写入自定义的404页面内容即可,完全不需要在代码里硬编码HTML字符串 - 代码启动时会一次性读取404页面内容加载到内存,相比每次请求读磁盘性能更高
- 内置兜底逻辑:如果
404.html被误删,服务会自动返回默认的404纯文本提示,不会直接崩溃
稳定性&安全优化建议
- 不要手动获取本机IP做绑定,直接绑定
0.0.0.0即可同时监听本机回环、局域网、公网所有网卡的请求,避免IP识别错误 - 每次
recv()读取长度限制在1024字节即可(仅够读取HTTP请求头),避免恶意构造的大请求占满服务器内存 - 处理完请求必须主动关闭连接,不然会出现大量TIME_WAIT状态的连接占满端口资源
- 如果需要对外提供公网服务,不要直接用裸Socket实现HTTP服务,建议用成熟的HTTP框架(比如Flask、FastAPI),自带路径校验、请求解析、并发处理能力,避免路径遍历、请求注入等安全问题
内容的提问来源于stack exchange,提问作者Sami Abu Rmaileh
相关产品推荐
相关产品推荐

