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

Python简易Web服务器出现OSError: [Errno 9]错误求助

问题

用Python编写简易Web服务器,目标是通过浏览器访问HTML文件,目前功能可实现,但每次运行都会弹出OSError: [Errno 9] Bad file descriptor错误。

服务器代码

from socket import *

serverPort = 1200
serverSocket: socket = socket(AF_INET, SOCK_STREAM)

serverSocket.bind(('', serverPort))
serverSocket.listen(1)

while True:
    
    print('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    print('connectionSocket is:', connectionSocket)
    try:
        message = connectionSocket.recv(1024)
        filename: bytes = message.split()[1]
        f = open(filename[1:])
        outputdata = f.read()
        
        connectionSocket.send('HTTP/1.1 200 OK\r\n\r\n'.encode('UTF-8'))
       
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i].encode())
        connectionSocket.send("\r\n".encode())
        connectionSocket.close()
    except IOError:
       
        connectionSocket.send('HTTP/1.1 404 Not Found'.encode('UTF-8'))
        connectionSocket.send("<html><head></head><body><h1>404 Not Found</h1></body></html> ".encode('UTF-8'))
        
    serverSocket.close()
sys.exit() 

报错信息

Traceback (most recent call last):
  File "/Users/me/PycharmProjects/firstPy/proj1.py", line 15, in <module>
    connectionSocket, addr = serverSocket.accept()
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/socket.py", line 293, in accept
    fd, addr = self._accept()
OSError: [Errno 9] Bad file descriptor

已知该错误通常因访问未打开的文件导致,推测是socket连接存在问题,但困惑的是仍能正常访问HTML,也排查过Python3.9的语法适配问题,未发现异常,希望得到错误原因及解决办法。

错误原因

  1. 核心问题:监听Socket被提前关闭
    你把serverSocket.close()放在了while True循环内部,第一次处理完请求后,负责监听的serverSocket就被关闭了。当循环再次执行到serverSocket.accept()时,这个Socket已经处于关闭状态,对应的文件描述符无效,因此抛出Bad file descriptor错误。
    第一次能正常访问HTML,是因为第一次循环时serverSocket还处于正常监听状态,能接受连接并处理请求,处理完才关闭监听Socket,第二次循环才触发错误。

  2. 其他潜在问题

    • 打开文件后未调用f.close(),可能导致资源泄漏;
    • 异常分支中未关闭connectionSocket,会导致客户端连接无法正常释放;
    • 逐个字符发送outputdata效率极低,完全没必要循环单个字符发送。

解决办法

修正后的代码

from socket import *
import sys

serverPort = 1200
serverSocket: socket = socket(AF_INET, SOCK_STREAM)

serverSocket.bind(('', serverPort))
serverSocket.listen(1)

print('Server is running on port', serverPort)
while True:
    print('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    print('Connected from:', addr)
    try:
        message = connectionSocket.recv(1024)
        # 处理空请求(比如浏览器/favicon.ico请求或异常请求)
        if not message:
            connectionSocket.close()
            continue
        filename: bytes = message.split()[1]
        # 打开文件时指定编码,避免读取中文等字符出现乱码
        with open(filename[1:], encoding='utf-8') as f:
            outputdata = f.read()
        
        # 发送响应头和响应体
        response_header = 'HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\n\r\n'
        connectionSocket.send(response_header.encode('UTF-8'))
        # 直接发送整个响应体,无需循环单个字符
        connectionSocket.send(outputdata.encode('UTF-8'))
    except IOError:
        # 发送404响应
        response = 'HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=utf-8\r\n\r\n'
        response += '<html><head></head><body><h1>404 Not Found</h1></body></html>'
        connectionSocket.send(response.encode('UTF-8'))
    finally:
        # 无论是否异常,都关闭连接Socket
        connectionSocket.close()

# 以下代码只有在循环被手动终止时才会执行
serverSocket.close()
sys.exit()

关键修改点说明

  • 将serverSocket.close()和sys.exit()移到while True循环外部,确保监听Socket在服务器运行期间始终保持打开状态,能持续接受新的连接请求;
  • 使用with open(...)语句自动管理文件资源,无需手动调用f.close();
  • 增加空请求的判断,避免message.split()抛出索引错误;
  • 优化响应头,添加Content-Type指定编码,避免页面乱码;
  • 直接发送整个响应体,提升传输效率;
  • 使用finally块确保connectionSocket无论是否发生异常都会被关闭,避免连接资源泄漏。

内容的提问来源于stack exchange,提问作者erem

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 02:50:03