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

Python在线聊天程序重连时出现ConnectionResetError[WinError10054]问题

Hey Rasmus, let's break down what's happening here and fix this connection issue.

问题根源

You’re absolutely right—old client connections aren’t being properly removed from the server’s clients dictionary. When you broadcast messages, the server still tries to send data to sockets that have already been closed (from the previous client session), triggering that ConnectionResetError.

This happens for two key reasons:

  • If you close the client window directly (instead of typing {stop}), the {stop} signal might not reach the server reliably (especially if there’s any network blip).
  • When a client disconnects unexpectedly, the server’s client.recv(BUFSIZ) returns an empty byte string (b''), but your original code only checks for the {stop} message—so the thread gets stuck in the loop, leaving the dead socket in the clients dict.

解决方案

We need to update the server code to handle all client disconnection scenarios, ensuring dead sockets are always cleaned up. Here’s the revised code with explanations:

Updated server.py Key Functions

def handle_client(client):
    name = ""
    try:
        name = client.recv(BUFSIZ).decode("utf8")
        if not name:  # Handle case where client disconnects right after connecting
            return
        
        welcome = 'Welcome %s! Type {stop} to exit.' % name
        client.send(bytes(welcome, "utf8"))
        msg = "%s connected to the chat!" % name
        broadcast(bytes(msg, "utf8"))
        clients[client] = name

        while True:
            msg = client.recv(BUFSIZ)
            if not msg:  # Empty bytes mean client disconnected unexpectedly
                break
            if msg != bytes("{stop}", "utf8"):
                broadcast(msg, name+": ")
            else:
                client.send(bytes("{stop}", "utf8"))
                break
    except Exception as e:
        print(f"Error with client {addresses.get(client)}: {e}")
    finally:
        # Guarantee cleanup no matter how the client exits
        client.close()
        if client in clients:
            del clients[client]
            if name:
                broadcast(bytes("%s left the chat." % name, "utf8"))

def broadcast(msg, prefix=""):
    # Iterate over a copy of clients to avoid errors if dict changes mid-loop
    for sock in list(clients.keys()):
        try:
            sock.send(bytes(prefix, "utf8") + msg)
        except Exception as e:
            # Clean up any dead sockets encountered during broadcast
            print(f"Failed to send to {clients[sock]}: {e}")
            sock.close()
            del clients[sock]

Why This Works

  • finally block: Ensures socket cleanup runs whether the client exits normally, disconnects unexpectedly, or throws an error. No more leftover dead connections.
  • Check for empty msg: Catches the standard TCP signal for a closed connection (when recv() returns b'').
  • Broadcast with a dict copy: Prevents errors if we remove a client while broadcasting to others.
  • Per-socket error handling in broadcast: If one client is dead, the rest still get messages—no more crashing the broadcast thread.

Quick Client-side Tweak

To make client exits more reliable, update the on_closing function to ensure the window closes properly:

def on_closing(event=None):
    try:
        my_msg.set("{stop}")
        send()
    finally:
        top.destroy()

With these changes, reconnecting clients will work smoothly, and the server won’t throw errors when old connections are left behind.

内容的提问来源于stack exchange,提问作者Rasmus A. C.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 23:43:13