Python Socket出现ConnectionResetError: [Errno 54]错误的原因及咨询
问题分析与解决方案
错误原因
线程仅处理一次请求就退出,导致TCP连接被关闭
服务器的on_new_client函数只执行一次conn.recv(1024)就结束线程,线程退出后对应的TCP连接会被系统强制关闭。此时第一个客户端仍尝试向已关闭的连接发送数据,直接触发ConnectionResetError。TCP套接字错误使用
sendto方法sendto是UDP套接字专属方法,TCP套接字应使用send或sendall。错误调用sendto会破坏TCP连接的状态逻辑,引发异常。用户映射与消息处理逻辑存在多处缺陷
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
相关产品推荐
相关产品推荐

