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

Python单客户端Socket问答游戏转多客户端改造求助

多客户端问答游戏服务端问题修复

你的代码核心问题是混合使用多线程与非阻塞Selector模型,再加上逻辑漏洞,导致出现ResourceIO错误和连接限制异常。以下是具体问题分析和修复方案:

核心问题点

  • 非阻塞套接字在多线程中调用recv()/send()会直接抛出BlockingIOError(即你遇到的ResourceIO错误),因为非阻塞模式下无数据时不会等待,直接报错。
  • 全局变量CURR_CLIENTS仅在新连接时递增,客户端断开时未递减,导致服务端达到3个连接后,即便有客户端退出也不再接受新请求。
  • handle_client函数外层冗余的while True会重复发送欢迎消息;同时未处理客户端主动断开的场景(recv()返回空字节串)。
  • 冗余的Selector代码完全未实际使用,反而造成逻辑混乱。

修复后的完整代码

import sys
import threading
import socket

MAX_CLIENTS = 3
CURR_CLIENTS = 0
# 用锁保证客户端计数的线程安全
client_lock = threading.Lock()

class ClientData:
    def __init__(self, conn, addr):
        self.conn = conn
        self.addr = addr
        self.money = 0
        self.phase = 0
        self.life_saver = True
        self.question_num = 0
        self.chaser_phase = 0
        self.status = 1
        
def initialize_client_data(client_data):
    # 初始化玩家数据逻辑
    pass

def handle_client(client_data):
    global CURR_CLIENTS
    try:
        print(f"[NEW CONNECTION] - {client_data.addr}")
        # 发送初始欢迎消息
        client_data.conn.send("Welcome to the game!\nDo you want to play? y/n \n>>".encode())
        connected = True
        while connected:
            # 多线程下用阻塞接收更稳定
            msg = client_data.conn.recv(1024).decode().strip()
            if not msg:
                # 客户端主动断开连接
                print(f"[DISCONNECTED] - {client_data.addr}")
                connected = False
                break
            print(f"[{client_data.addr}] {msg}")
            if msg.lower() == 'n':  
                connected = False
                client_data.conn.send("Bye Bye".encode())
                print(f"[DISCONNECTED] - {client_data.addr}")
            else:
                initialize_client_data(client_data)
                phase_A(client_data)
                # 游戏主循环:检查玩家状态
                while client_data.status == 1:
                    # 游戏结束判定逻辑
                    pass
    except Exception as e:
        print(f"[ERROR] {client_data.addr}: {str(e)}")
    finally:
        # 确保连接关闭,更新客户端计数
        client_data.conn.close()
        with client_lock:
            CURR_CLIENTS -= 1
        print(f"[ACTIVE CONNECTIONS] {CURR_CLIENTS}")

def send_question(client_data):
    # 向客户端发送问题逻辑
    pass

def chaser_answer(client_data, question_num):
    # 电脑随机回答逻辑
    pass

def client_answer(client_data, question_num):
    # 发送问题并接收玩家回答逻辑
    pass

def phase_A(client_data):
    # 游戏Phase A逻辑
    pass

def phase_B(client_data):
    # 游戏Phase B逻辑
    pass

def start():
    global CURR_CLIENTS
    server.listen()
    print(f"Listening on {host}:{port}")
    while True:
        try:
            conn, addr = server.accept()
            with client_lock:
                if CURR_CLIENTS >= MAX_CLIENTS:
                    # 达到最大连接数,拒绝新请求
                    conn.send("Server is full, try later.".encode())
                    conn.close()
                    print(f"[REJECTED CONNECTION] - {addr}")
                    continue
                CURR_CLIENTS += 1
            print(f"[ACTIVE CONNECTIONS] {CURR_CLIENTS}")
            # 每个客户端启动独立线程处理
            client_data = ClientData(conn, addr)
            thread = threading.Thread(target=handle_client, args=(client_data,), daemon=True)
            thread.start()
        except Exception as e:
            print(f"[SERVER ERROR] {str(e)}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("Usage: python server.py <host> <port>")
        sys.exit(1)
    host, port = sys.argv[1], int(sys.argv[2])
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 允许端口快速复用,避免服务重启后端口占用
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((host, port))
    start()

关键修改说明

  1. 移除冗余Selector逻辑:改用纯多线程模型,每个客户端对应独立线程,逻辑更简洁稳定。
  2. 线程安全计数:通过threading.Lock保证客户端计数的原子操作,避免多线程下的计数错误。
  3. 阻塞套接字:去掉非阻塞设置,多线程环境下阻塞接收/发送更可靠,不会触发IO异常。
  4. 完善断开处理:检测客户端主动断开的场景,并在finally块中确保连接关闭和计数更新。
  5. 超额连接拒绝:达到最大连接数时,直接拒绝新请求并返回提示。
  6. 守护线程设置:客户端线程设为守护线程,服务端退出时自动销毁线程,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:05:23