Python Socket客户端崩溃求助:连接建立后无响应且断开
问题描述
启动服务器后启动客户端,服务器能接收数据,但客户端无法获取响应并崩溃,报错信息如下:
data = sock.recv(1024)
ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。
服务端代码
import pygame, socket, time pygame.init() main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) main_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) main_socket.bind(("localhost", 10000)) main_socket.setblocking(0) main_socket.listen(5) players_sockets = [] while True: try: new_socket, addr = main_socket.accept() print("Connect", addr) new_socket.setblocking(0) players_sockets.append(new_socket) except: pass for i in players_sockets: try: data = i.recv(1024) data = data.decode() except: pass for i in players_sockets: try: i.send("server data").encode() except: players_sockets.remove(i) print("Disconnect") i.close() time.sleep(1)
客户端代码
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) sock.connect(("localhost", 10000)) while True: sock.send("Command".encode()) data = sock.recv(1024) data = data.decode() print(data)
问题原因及修复方案
核心问题1:服务端发送数据的语法错误
服务端中i.send("server data").encode()是错误写法:应该先对字符串编码再发送,正确格式为i.send("server data".encode())。原代码会直接尝试发送未编码的字符串,触发异常后服务端会关闭客户端连接,这就是客户端收到连接中止错误的直接原因。
核心问题2:遍历列表时修改列表引发的异常
服务端在for i in players_sockets:循环中直接执行players_sockets.remove(i),会破坏列表的遍历结构,导致后续遍历出错,可能误删其他连接或引发索引异常。
核心问题3:非阻塞Socket的异常处理不严谨
服务端使用非阻塞Socket,recv在没有数据时会抛出BlockingIOError,原代码捕获所有异常但未区分情况;当客户端主动断开时,recv会返回空字节串,原代码未处理该场景,导致无效连接残留。
修复后的服务端代码
import pygame, socket, time pygame.init() main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) main_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) main_socket.bind(("localhost", 10000)) main_socket.setblocking(0) main_socket.listen(5) players_sockets = [] while True: # 处理新连接:仅捕获无新连接的BlockingIOError try: new_socket, addr = main_socket.accept() print("Connect", addr) new_socket.setblocking(0) players_sockets.append(new_socket) except BlockingIOError: pass # 处理接收数据:遍历列表副本避免修改原列表 for sock in players_sockets.copy(): try: data = sock.recv(1024) if not data: # 客户端断开时recv返回空 players_sockets.remove(sock) sock.close() print("Disconnect (client closed)") continue data = data.decode() print(f"Received from client: {data}") except BlockingIOError: pass # 无数据时忽略 except Exception as e: # 其他异常,移除并关闭连接 players_sockets.remove(sock) sock.close() print(f"Disconnect: {str(e)}") # 处理发送数据:遍历列表副本,先编码再发送 for sock in players_sockets.copy(): try: sock.send("server data".encode()) except Exception as e: players_sockets.remove(sock) sock.close() print(f"Disconnect (send failed): {str(e)}") time.sleep(1)
客户端代码优化(可选,避免无提示崩溃)
import socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) try: sock.connect(("localhost", 10000)) except Exception as e: print(f"连接服务器失败: {str(e)}") exit() while True: try: sock.send("Command".encode()) data = sock.recv(1024) if not data: print("服务器已断开连接") break data = data.decode() print(data) except Exception as e: print(f"客户端错误: {str(e)}") break sock.close()
内容的提问来源于stack exchange,提问作者MrBelor
相关产品推荐
相关产品推荐

