Discord WebSocket连接语音频道后自动断开问题求助
Discord WebSocket语音频道连接自动断开问题
我按照Discord官方文档实现WebSocket连接以加入语音频道,但连接会在30-40秒后无报错自动断开。已设置10秒ping间隔并配置对应ping payload,问题仍未解决。
我的代码
import json import time from websocket import WebSocket from websocket import WebSocketApp class ConnectWebSocket(WebSocketApp): """Class Inherited From `WebSocketApp`""" def __init__( self, token: str, guild_id: str, channel_id: str ): super().__init__( header=[ "Accept-Language: en-US", "Connection: Upgrade", "Host: gateway.discord.gg", "Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9153 Chrome/124.0.6367.243 Electron/30.1.0 Safari/537.36" ], url="wss://gateway.discord.gg/?v=9&encoding=json", on_open=self.on_connection, on_message=self.on_message ) self._token = token self._guild = guild_id self._channel = channel_id def on_connection(self, ws): print("Opened a connection...") ws.send(json.dumps({ "op": 2, "d": { "token": self._token, "intents": 513, "properties": { "os": "windows 10", "browser": "Google Chrome", "device": "Windows" } } })) print("First Payload Sent") ws.send(json.dumps({ "op": 4, "d": { "guild_id": self._guild, "channel_id": self._channel, "self_mute": False, "self_deaf": False } } )) print("Second Payload Sent") def on_message(self, ws, message): print(f"Received message") def run_forever(self, proxy): username_password, proxy_address_port = proxy.split('@') username, password = username_password.split(':') proxy_address, port = proxy_address_port.split(':') return super().run_forever( reconnect=5, ping_interval=10, proxy_type="http", http_proxy_host=proxy_address, http_proxy_port=int(port), http_proxy_auth=(username, password), ping_payload={"op": 6, "d": int(time.time() * 1000)}, ) def on_error(self, ws, error): print(error) def on_close(self, ws, close_status_code, close_msg): print("Closed con")
问题排查与修复方案
1. 错误的心跳机制实现
Discord Gateway的心跳规则不是客户端主动发送OP 6,而是:
- 服务器会先发送OP 10(Hello)包,包含
heartbeat_interval字段,客户端需要按照这个间隔发送OP 1心跳包 - 服务器会主动发送OP 1心跳请求,客户端必须回复相同的OP 1和对应时间戳
你硬编码的10秒间隔和OP 6格式不符合Discord规范,这是连接断开的核心原因。
2. 未处理关键Gateway事件
你的on_message只打印收到消息,完全忽略了维持连接必需的事件:
- OP 10(Hello):获取心跳间隔,启动心跳定时器
- OP 1(心跳请求):回复心跳以维持连接
- OP 0(事件):处理语音状态更新等关键事件
3. 修复后的代码
import json import time import threading from websocket import WebSocketApp class ConnectWebSocket(WebSocketApp): def __init__(self, token: str, guild_id: str, channel_id: str): super().__init__( header=[ "Accept-Language: en-US", "Connection: Upgrade", "Host: gateway.discord.gg", "Sec-Websocket-Extensions: permessage-deflate; client_max_window_bits", "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.9153 Chrome/124.0.6367.243 Electron/30.1.0 Safari/537.36" ], url="wss://gateway.discord.gg/?v=9&encoding=json", on_open=self.on_connection, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close ) self._token = token self._guild = guild_id self._channel = channel_id self.heartbeat_interval = None self.heartbeat_thread = None self.last_sequence = None def _send_heartbeat(self): """定时发送心跳包""" while self.heartbeat_interval and self.sock.connected: self.send(json.dumps({"op": 1, "d": self.last_sequence})) time.sleep(self.heartbeat_interval / 1000) def on_connection(self, ws): print("连接已建立...") # 发送身份验证Payload ws.send(json.dumps({ "op": 2, "d": { "token": self._token, "intents": 513, "properties": { "os": "windows 10", "browser": "Google Chrome", "device": "Windows" } } })) print("身份验证Payload已发送") def on_message(self, ws, message): data = json.loads(message) op = data.get("op") self.last_sequence = data.get("s") if op == 10: # 处理Hello包,获取心跳间隔 self.heartbeat_interval = data["d"]["heartbeat_interval"] print(f"收到Hello包,心跳间隔: {self.heartbeat_interval}ms") # 启动心跳线程 self.heartbeat_thread = threading.Thread(target=self._send_heartbeat, daemon=True) self.heartbeat_thread.start() # 心跳启动后再发送语音频道加入请求 ws.send(json.dumps({ "op": 4, "d": { "guild_id": self._guild, "channel_id": self._channel, "self_mute": False, "self_deaf": False } })) print("语音频道加入Payload已发送") elif op == 1: # 响应服务器的心跳请求 ws.send(json.dumps({"op": 1, "d": data["d"]})) print("发送心跳响应") elif op == 0: # 处理事件,比如语音状态更新 print(f"收到事件: {data['t']}") def run_forever(self, proxy): username_password, proxy_address_port = proxy.split('@') username, password = username_password.split(':') proxy_address, port = proxy_address_port.split(':') return super().run_forever( reconnect=5, proxy_type="http", http_proxy_host=proxy_address, http_proxy_port=int(port), http_proxy_auth=(username, password), # 移除错误的ping配置,改用自定义心跳逻辑 ) def on_error(self, ws, error): print(f"错误: {error}") def on_close(self, ws, close_status_code, close_msg): print(f"连接关闭,状态码: {close_status_code},消息: {close_msg}")
关键修复说明
- 遵循Discord Gateway规范,使用OP 1心跳包替代OP 6
- 根据服务器返回的
heartbeat_interval动态调整心跳间隔,不再硬编码 - 处理Hello包后再发送语音频道加入请求,保证连接初始化完成
- 跟踪
last_sequence参数,这是维持连接和重连的必要数据
内容的提问来源于stack exchange,提问作者mohammad hassan
相关产品推荐
相关产品推荐

