Python3.9使用websocket连接Discord网关运行断连报错问题排查
错误原因
WinError 10053是Windows系统下TCP连接被本地网络栈主动终止抛出的错误,结合你的Discord网关对接场景,具体触发原因如下:
- 网关参数配置错误:你使用的网关接口版本v6已经被Discord官方废弃,且请求参数拼写错误(
encording应为encoding),网关识别到无效请求后会主动断开连接 - 心跳逻辑不符合规范:
- Discord要求第一次心跳需要在收到hello包后,间隔
heartbeat_interval * 0~1之间的随机数后发送,你的代码直接休眠完整的心跳间隔才发第一次心跳,很容易触发心跳超时被断连 - 心跳payload的
d字段固定填写字符串"null",不符合协议要求:首次心跳无序列号时应填JSON null(对应Python的None),后续心跳需要填写上一次收到的网关事件的s字段值,无效的心跳包会被网关直接拒绝并断连
- Discord要求第一次心跳需要在收到hello包后,间隔
- 无事件消费逻辑:你的代码仅在连接建立时调用了一次
recv获取hello包,后续没有消费网关推送的任何事件,socket缓冲区满后网关会主动断开连接 - 无异常捕获和重连逻辑:网络波动、运营商限流、Discord网关例行切换连接都会导致正常连接中断,你没有对这类异常做捕获和重连处理
修复方案
1. 修正基础参数
将网关连接地址替换为官方支持的版本,修正参数拼写:
ws.connect('wss://gateway.discord.gg/?v=10&encoding=json')
2. 新增事件消费逻辑,维护心跳序列号
启动单独线程循环消费网关事件,同步更新最新的事件序列号供心跳使用:
# 多账号场景可以按token存字典,示例简化为全局值 last_seq = None def event_consumer(ws): global last_seq while True: try: event = recieve_json_response(ws) if event and event.get('s'): last_seq = event['s'] # 此处可添加自定义事件处理逻辑 except Exception as e: print(f"事件消费异常: {e}") break
3. 修正心跳逻辑
import random def heartbeat(interval, ws): print('Heartbeat begin') # 第一次心跳等待随机比例的间隔,符合Discord协议要求 time.sleep(interval * random.random()) while True: try: heartbeatJSON = { "op": 1, "d": last_seq } send_json_request(ws, heartbeatJSON) print("Heartbeat sent") time.sleep(interval) except Exception as e: print(f"心跳发送异常: {e}") break
4. 添加重连逻辑
将每个账号的连接逻辑封装为函数,检测到连接断开后自动重试:
def run_account(token): while True: try: ws = websocket.WebSocket() ws.connect('wss://gateway.discord.gg/?v=10&encoding=json', timeout=30) event = recieve_json_response(ws) heartbeat_interval = event['d']['heartbeat_interval'] / 1000 # 启动心跳和事件消费线程 threading._start_new_thread(heartbeat, (heartbeat_interval, ws)) threading._start_new_thread(event_consumer, (ws,)) # 发送鉴权payload payload = { 'op': 2, "d": { "token": token, "properties": { "$os": "windows", "$browser": "chrome", "$device": 'pc' } } } send_json_request(ws, payload) # 阻塞等待连接异常,避免频繁重连 while True: time.sleep(10) except Exception as e: print(f"连接异常,5秒后重试: {e}") time.sleep(5) # 原循环改为启动每个账号的独立运行线程 for index, v in enumerate(token_list): threading._start_new_thread(run_account, (v,))
5. 补充异常捕获
在所有ws.send、ws.recv调用处添加对应连接异常的捕获,避免程序直接崩溃。
内容的提问来源于stack exchange,提问作者Joon1313
相关产品推荐
相关产品推荐

