Python Socket客户端运行报[WinError 10053]连接被主机软件中止错误
问题背景
运行环境为Python 3.10、Windows 10 64位,开发游戏配套Socket通信客户端与服务端时,服务端运行无报错,但客户端启动后触发ConnectionAbortedError: [WinError 10053],错误提示为:
An established connection was aborted by the software in your host machine
完整错误回溯:
Traceback (most recent call last): File "C:\Users\---\Desktop\---\---\testClient.py", line 19, in <module> data = s.recv(1024) ConnectionAbortedError: [WinError 10053] An established connection was aborted by the software in your host machine
附原始问题代码:
原始server.py代码
import socket import sys import threading import os import random as rand HOST = '' PORT = 7474 os.system('title GunLord server vBETA') s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('# Socket created') try: s.bind((HOST, PORT)) except socket.error as msg: print('# Bind failed. ') sys.exit() print('# Socket bind complete') s.listen(100) print('# Socket now listening') def clientThread(conn, addr, playerID): global PlayerLocationData print('# Connected to ' + addr[0] + ':' + str(addr[1])) try: while True: data = conn.recv(1024) line = data.decode('UTF-8') clientData = line.split('&') PlayerLocationData[playerID] = str(clientData[0]) +'.'+str(clientData[1])+'.'+str(clientData[2]) responsePlayerLocationData = '' for i in range(len(PlayerLocationData)): responsePlayerLocationData +=PlayerLocationData[i]+'%%' try: conn.send(str(responsePlayerLocationData).encode()) except: PlayerLocationData[playerID] = None except: conn.close() threads = [] global PlayerLocationData PlayerLocationData = [] while True: conn, addr = s.accept() playerID = rand.randint(1, 1000) t = threading.Thread(target=clientThread(conn, addr, playerID)) t.start() threads.append(t) s.close()
原始client.py代码
import socket import random as rand import time as t host = '127.0.0.1' port = 7474 s = socket.socket() s.connect((host, port)) global PlayerLocations PlayerLocations = [] def recvDecoder(recvText): global PlayerLocations PlayerLocations = recvText.split('%%') while True: testX = rand.randint(1, 10) testY = rand.randint(1, 10) testZ = rand.randint(1, 10) print('test coords: {}, {}, {}' .format(testX, testY, testZ)) s.send('{}&{}&{}'.format(testX, testY, testZ).encode()) data = s.recv(1024) line = data.decode('UTF-8') recvDecoder(line) t.sleep(.3)
错误原因
共3个核心问题直接触发连接被服务端主动关闭:
- 线程创建写法完全错误:原代码写
target=clientThread(conn, addr, playerID)时,会在主线程直接同步执行clientThread函数,根本没有创建新的子线程。主线程会直接阻塞在客户端处理循环里,外层的accept逻辑完全无法运行,只要函数内触发任何异常,就会直接关闭连接。 - 列表索引越界触发异常断连:
PlayerLocationData初始化为空列表,却用1~1000的随机数作为索引直接赋值,Python列表不支持对超出当前长度的索引直接赋值,第一次收到客户端坐标数据执行赋值操作时就会抛出IndexError,直接进入except块执行conn.close(),客户端侧就会收到连接被中止的错误。 - 附加逻辑缺陷:playerID用无去重的随机数生成,多客户端连接时会出现ID冲突、位置数据互相覆盖的问题;没有处理
recv返回空字节(对端正常断开)的场景,会触发解码异常。
修复方案
按以下步骤修改代码即可解决问题:
- 修正线程创建语法:
target参数只传函数引用,函数参数通过args参数以元组形式传入,不要直接在target位置调用函数。 - 将
PlayerLocationData从列表改为字典,不需要连续索引即可存储任意playerID对应的位置数据,彻底避免索引越界问题。 - 增加playerID去重逻辑,确保每个连接的玩家ID唯一。
- 增加recv空值判断,收到空数据时主动退出连接循环,清理对应玩家的位置数据。
修复后server.py代码
import socket import sys import threading import os import random as rand HOST = '' PORT = 7474 os.system('title GunLord server vBETA') s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('# Socket created') try: s.bind((HOST, PORT)) except socket.error as msg: print('# Bind failed. ') sys.exit() print('# Socket bind complete') s.listen(100) print('# Socket now listening') # 改用字典存储玩家位置,避免列表索引越界 PlayerLocationData = {} used_player_ids = set() def clientThread(conn, addr, playerID): global PlayerLocationData print('# Connected to ' + addr[0] + ':' + str(addr[1]) + f', playerID: {playerID}') try: while True: data = conn.recv(1024) # 处理对端断开的情况 if not data: break line = data.decode('UTF-8') clientData = line.split('&') # 过滤长度不对的非法数据包 if len(clientData) <3: continue PlayerLocationData[playerID] = f"{clientData[0]}.{clientData[1]}.{clientData[2]}" responsePlayerLocationData = '' # 遍历字典拼接所有玩家位置 for pos in PlayerLocationData.values(): responsePlayerLocationData += pos +'%%' conn.send(responsePlayerLocationData.encode()) except Exception as e: print(f"Connection with {addr} error: {e}") finally: # 清理断开连接的玩家数据,关闭连接 if playerID in PlayerLocationData: del PlayerLocationData[playerID] used_player_ids.remove(playerID) conn.close() print(f"# Disconnected from {addr[0]}:{addr[1]}, playerID: {playerID}") threads = [] while True: conn, addr = s.accept() # 生成不重复的playerID while True: playerID = rand.randint(1, 1000) if playerID not in used_player_ids: used_player_ids.add(playerID) break # 修正线程传参写法,不要直接调用目标函数 t = threading.Thread(target=clientThread, args=(conn, addr, playerID)) t.daemon = True t.start() threads.append(t) s.close()
修复后client.py代码(增加断连异常捕获)
import socket import random as rand import time as t host = '127.0.0.1' port = 7474 s = socket.socket() s.connect((host, port)) PlayerLocations = [] def recvDecoder(recvText): global PlayerLocations # 过滤末尾空字符串 PlayerLocations = [pos for pos in recvText.split('%%') if pos] try: while True: testX = rand.randint(1, 10) testY = rand.randint(1, 10) testZ = rand.randint(1, 10) print('test coords: {}, {}, {}' .format(testX, testY, testZ)) s.send(f'{testX}&{testY}&{testZ}'.encode()) data = s.recv(1024) if not data: print("Server closed connection") break line = data.decode('UTF-8') recvDecoder(line) print(f"All player locations: {PlayerLocations}") t.sleep(.3) except Exception as e: print(f"Connection error: {e}") finally: s.close()
修改后重新运行服务端和客户端即可正常通信,不会再触发10053错误。
内容的提问来源于stack exchange,提问作者Qweru
相关产品推荐
相关产品推荐

