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

Python Socket出现ConnectionResetError: [Errno 54]错误的原因及咨询

问题分析与解决方案

错误原因

  1. 线程仅处理一次请求就退出,导致TCP连接被关闭
    服务器的on_new_client函数只执行一次conn.recv(1024)就结束线程,线程退出后对应的TCP连接会被系统强制关闭。此时第一个客户端仍尝试向已关闭的连接发送数据,直接触发ConnectionResetError。

  2. TCP套接字错误使用sendto方法
    sendto是UDP套接字专属方法,TCP套接字应使用send或sendall。错误调用sendto会破坏TCP连接的状态逻辑,引发异常。

  3. 用户映射与消息处理逻辑存在多处缺陷

    • user_mapping存储(addr, username),但TCP客户端的addr包含随机分配的端口,每个连接的端口都不同,后续无法通过addr匹配用户;应改为存储(conn, username),用连接对象直接发送消息。
    • 查找发送方用户的循环逻辑错误:只要有一个用户的addr不匹配就发送"user not found",且未处理from_user未定义的边界情况。
    • 消息解析存在语法错误:user_mapping[data[1:data.find(":")](0)]应为user_mapping[data[1:data.find(":")]][0],且未处理目标用户不存在的情况,会直接抛出KeyError。

修复后的代码示例

Server.py

import socket
import _thread as thread

HOST = "127.0.0.1"
PORT = 1237
user_mapping = {}  # 结构: {username: (conn, addr)}

def on_new_client(conn, addr):
    try:
        # 接收用户名注册
        data = conn.recv(1024).decode().strip()
        if data.startswith("username:"):
            username = data.split(":")[1].strip()
            user_mapping[username] = (conn, addr)
            print(f"用户 {username} 已连接,地址: {addr}")
        else:
            conn.send("请先注册用户名".encode())
            conn.close()
            return
        
        # 持续监听该客户端的消息
        while True:
            data = conn.recv(1024).decode().strip()
            if not data:
                # 客户端断开连接
                del user_mapping[username]
                print(f"用户 {username} 已断开连接")
                break
            
            # 处理@目标用户的消息
            if data.startswith("@"):
                # 解析消息格式: @目标用户名: 消息内容
                if ":" not in data:
                    conn.send("消息格式错误,请使用: @用户名: 消息内容".encode())
                    continue
                target_username = data[1:data.find(":")].strip()
                message_content = data[data.find(":")+1:].strip()
                
                if target_username in user_mapping:
                    target_conn, _ = user_mapping[target_username]
                    send_msg = f"{username}: {message_content}"
                    target_conn.send(send_msg.encode())
                else:
                    conn.send(f"用户 {target_username} 不存在".encode())
            else:
                # 扩展为广播消息
                broadcast_msg = f"{username}: {data}"
                for user_conn, _ in user_mapping.values():
                    if user_conn != conn:
                        user_conn.send(broadcast_msg.encode())
    except Exception as e:
        print(f"连接 {addr} 出现错误: {e}")
        # 清理断开的用户
        for uname, (c, a) in list(user_mapping.items()):
            if a == addr:
                del user_mapping[uname]
                break
    finally:
        conn.close()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(10)

print(f"服务器已启动,监听 {HOST}:{PORT}")
while True:
    conn, addr = s.accept()
    thread.start_new_thread(on_new_client, (conn, addr))

s.close()

Client.py

import socket
import _thread as thread

HOST = "127.0.0.1"
PORT = 1237

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

username = input("Enter user name: ").strip()
s.send(f"username: {username}".encode())

def recv_messages():
    while True:
        try:
            data = s.recv(1024).decode()
            if not data:
                print("服务器已断开连接")
                break
            print(f"\n收到消息: {data}")
            print(f"{username}>", end="", flush=True)
        except:
            break

thread.start_new_thread(recv_messages, ())

while True:
    message = input(f"{username}>").strip()
    if not message:
        continue
    if message.lower() == "quit":
        s.close()
        break
    s.send(message.encode())

Python消息服务开发学习建议

  • 吃透Python标准库socket模块,重点区分TCP与UDP的API差异、连接状态管理逻辑。
  • 学习多线程/异步IO在网络编程中的应用,比如threading、asyncio模块的网络编程部分。
  • 了解HTTP、WebSocket、MQTT等常用消息协议,掌握对应Python库(如websockets、paho-mqtt)的使用。
  • 学习Redis Pub/Sub、RabbitMQ(pika库)等消息中间件,理解消息队列的核心概念与应用场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 00:40:41