C#控制台程序通过Socket向Python Telegram Bot传数据遇端口占用错误求助
解决WinError 10048端口占用问题
问题根源
你遇到的错误是因为多次触发start_button回调时,重复创建并绑定了同一个端口5000,而之前的socket连接关闭后,系统会保留端口一段时间(TIME_WAIT状态),导致新的绑定请求失败。另外,Python代码在异步回调里使用阻塞的socket.accept()和time.sleep,也会加剧资源释放不及时的问题。
修复方案
1. 允许端口复用+优化异步逻辑
在绑定端口前设置SO_REUSEADDR选项,让系统允许同一端口被快速复用,同时替换阻塞的time.sleep为异步版本,避免卡死事件循环:
import socket import asyncio from telegram import CallbackQuery from telegram.ext import Router stop_output = False server_socket = None # 全局存储socket实例 @router.callback_query(lambda c: c.data == "start_button") async def start_bots(call: CallbackQuery): global stop_output, server_socket stop_output = False await call.answer() # 先关闭之前可能存在的socket实例 if server_socket: try: server_socket.close() except: pass server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 开启端口复用 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(("localhost", 5000)) server_socket.listen(1) # 设置非阻塞模式,适配异步环境 server_socket.setblocking(False) while not stop_output: await asyncio.sleep(1) try: client_socket, address = server_socket.accept() data = client_socket.recv(1024).decode("utf-8") print(data) client_socket.close() except BlockingIOError: # 无新连接时忽略错误 continue # 循环结束后释放端口 server_socket.close()
2. 避免重复绑定(更稳定的方案)
把socket初始化逻辑移到回调外部,只创建一次,回调仅控制启停状态:
import socket import asyncio from telegram import CallbackQuery from telegram.ext import Router stop_output = False # 提前初始化socket,仅绑定一次 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(("localhost", 5000)) server_socket.listen(1) server_socket.setblocking(False) async def socket_listener(): global stop_output while not stop_output: await asyncio.sleep(1) try: client_socket, address = server_socket.accept() data = client_socket.recv(1024).decode("utf-8") print(data) client_socket.close() except BlockingIOError: continue @router.callback_query(lambda c: c.data == "start_button") async def start_bots(call: CallbackQuery): global stop_output stop_output = False await call.answer() # 启动独立的监听任务 asyncio.create_task(socket_listener()) # 可选:添加停止按钮回调 @router.callback_query(lambda c: c.data == "stop_button") async def stop_bots(call: CallbackQuery): global stop_output stop_output = True await call.answer()
3. C#端代码优化(可选)
当前代码的using语句已经能自动释放资源,可添加异常处理提升稳定性:
try { using (TcpClient clients = new TcpClient("localhost", 5000)) { using (NetworkStream stream = clients.GetStream()) { string message = JsonConvert.SerializeObject(ArbitragVnytribirgevoi); byte[] buffer = Encoding.UTF8.GetBytes(message); stream.Write(buffer, 0, buffer.Length); stream.Flush(); // 确保数据完全发送 } } } catch (Exception ex) { Console.WriteLine($"发送失败:{ex.Message}"); }
关键注意事项
- 异步环境中避免使用阻塞的socket方法,要么设置非阻塞模式配合
asyncio,要么把监听逻辑放到单独线程。 - 全局维护socket实例,避免重复创建和绑定操作。
SO_REUSEADDR选项可以绕过TIME_WAIT状态的端口占用限制,是解决这类问题的核心配置。
内容的提问来源于stack exchange,提问作者Xlebushek
相关产品推荐
相关产品推荐

