You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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页面实现说明

  1. 在脚本所在文件夹新建404.html文件,写入自定义的404页面内容即可,完全不需要在代码里硬编码HTML字符串
  2. 代码启动时会一次性读取404页面内容加载到内存,相比每次请求读磁盘性能更高
  3. 内置兜底逻辑:如果404.html被误删,服务会自动返回默认的404纯文本提示,不会直接崩溃

稳定性&安全优化建议

  • 不要手动获取本机IP做绑定,直接绑定0.0.0.0即可同时监听本机回环、局域网、公网所有网卡的请求,避免IP识别错误
  • 每次recv()读取长度限制在1024字节即可(仅够读取HTTP请求头),避免恶意构造的大请求占满服务器内存
  • 处理完请求必须主动关闭连接,不然会出现大量TIME_WAIT状态的连接占满端口资源
  • 如果需要对外提供公网服务,不要直接用裸Socket实现HTTP服务,建议用成熟的HTTP框架(比如Flask、FastAPI),自带路径校验、请求解析、并发处理能力,避免路径遍历、请求注入等安全问题

内容的提问来源于stack exchange,提问作者Sami Abu Rmaileh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 08:15:35