如何实现多个Discord Bot间的通信?(Python+py-cord环境)
两个Discord Bot双向Websocket通信实现方案(基于py-cord + aiohttp)
一、修复aiohttp Websocket双向通信问题
你之前遇到的单向通信问题,大概率是没在两端正确实现双向消息监听逻辑。aiohttp的Websocket本身支持双向收发,只要两端都保持消息循环即可,下面是具体实现步骤:
1. 服务器端Bot(Websocket监听方)
在Bot启动流程中嵌入aiohttp的Websocket服务,注意和py-cord的异步事件循环兼容:
import discord from discord.ext import commands import aiohttp from aiohttp import web intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) # 存储活跃的Websocket连接 active_connections = set() async def websocket_handler(request): ws = web.WebSocketResponse() await ws.prepare(request) active_connections.add(ws) print("新客户端连接") try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: # 收到客户端消息后转发到Discord频道 channel = bot.get_channel(123456789) # 替换为你的目标频道ID await channel.send(f"Bot B发来消息: {msg.data}") # 回复客户端确认消息 await ws.send_str(f"已收到消息: {msg.data}") elif msg.type == aiohttp.WSMsgType.ERROR: print(f"Websocket错误: {ws.exception()}") finally: active_connections.remove(ws) print("客户端断开连接") return ws async def start_webserver(): app = web.Application() app.add_routes([web.get('/ws', websocket_handler)]) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, '0.0.0.0', 8765) # 监听所有地址,端口自定义为8765 await site.start() print("Websocket服务器启动完成") @bot.event async def on_ready(): print(f'服务器端Bot已登录: {bot.user}') # 启动Websocket服务器 await start_webserver() # 命令示例:从Discord发消息到客户端Bot @bot.command() async def send_to_botb(ctx, *, message): for ws in active_connections: await ws.send_str(f"服务器端Bot发来消息: {message}") await ctx.send("消息已发送到Bot B") bot.run('你的服务器端Bot Token')
2. 客户端Bot(Websocket连接方)
客户端需在启动时建立Websocket连接,并开启后台任务持续监听消息,同时支持主动发送消息:
import discord from discord.ext import commands import aiohttp import asyncio intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix='!', intents=intents) ws_connection = None async def websocket_listener(): global ws_connection while True: try: async with aiohttp.ClientSession() as session: async with session.ws_connect('http://服务器IP:8765/ws') as ws: ws_connection = ws print("已连接到服务器端Bot的Websocket") async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: # 收到服务器消息后转发到Discord频道 channel = bot.get_channel(987654321) # 替换为你的目标频道ID await channel.send(f"服务器端Bot发来消息: {msg.data}") elif msg.type == aiohttp.WSMsgType.CLOSED: print("Websocket连接关闭,尝试重连") break elif msg.type == aiohttp.WSMsgType.ERROR: print(f"Websocket错误: {ws.exception()}") break except Exception as e: print(f"连接失败,10秒后重试: {e}") await asyncio.sleep(10) @bot.event async def on_ready(): print(f'客户端Bot已登录: {bot.user}') # 启动Websocket监听后台任务 bot.loop.create_task(websocket_listener()) # 命令示例:从Discord发消息到服务器端Bot @bot.command() async def send_to_bota(ctx, *, message): if ws_connection and not ws_connection.closed: await ws_connection.send_str(f"客户端Bot发来消息: {message}") await ctx.send("消息已发送到Bot A") else: await ctx.send("未连接到服务器端Bot,请稍后重试") bot.run('你的客户端Bot Token')
关键注意事项
- 两端必须在异步循环中持续监听消息:服务器端通过
async for msg in ws循环接收,客户端通过后台任务保持监听,才能实现双向触发事件。 - 添加重连机制:客户端捕获连接异常后自动重试,避免单次连接失败后无法恢复通信。
- 端口权限:若Bot部署在云服务器,需确保自定义端口(如8765)已在防火墙/安全组中开放。
二、备选高效方案(若Websocket仍受网络限制)
如果遇到网络层面的限制,可考虑以下低延迟替代方案:
- Redis Pub/Sub:利用Redis的发布订阅机制,两个Bot订阅同一个频道实现双向消息传递,稳定且延迟低,适合分布式部署场景。
- 本地内存队列:若两个Bot运行在同一机器/进程,直接用
asyncio.Queue在内存中传递消息,效率极高。
内容的提问来源于stack exchange,提问作者JL710
相关产品推荐
相关产品推荐

