You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:13:40