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

Python子线程执行socket.accept()时阻塞挂起无法接收连接

问题根因

你的代码里有几个直接导致accept()持续阻塞的问题,还有几个严重干扰排查的逻辑错误:

  • 绑定地址错误:你将HOST设置为具体静态IPv4地址的做法存在很高概率绑定失效。如果该地址没有直接配置在运行程序的本机网卡上(比如家用宽带的公网IP配在光猫/路由器上、云服务器公网IP映射在网关侧),即使bind()不报错,socket也无法接收到发往该地址的连接请求,accept()会永久等待。
  • 日志位置错误造成误导:你把"Client found, getting connection..."日志放在了s.listen()调用之后、s.accept()之前,完全不符合实际逻辑。s.listen()的作用只是将socket标记为被动监听模式、初始化连接等待队列,根本不会检测是否有客户端接入,这条日志打印时程序还没开始等待客户端连接,直接误导了你对阻塞位置的判断。
  • 异常捕获逻辑吞掉有效信息:你用裸except捕获所有异常,且没有打印具体异常栈,就算socket出现超时、被意外关闭、被系统回收等问题,你也只能拿到一句无意义的No clients found...日志,完全无法定位具体错误。
  • 未正确配置socket超时:你在函数参数里传入了socket_timeout但没有调用s.settimeout()给socket设置超时时间,accept()会进入永久阻塞模式,只要没有合法连接到达就会一直等待,这本身是阻塞socket的正常行为,不是线程挂死。
  • 额外排查点:如果本地测试能连通但外部无法连接,大概率是系统防火墙、云服务器安全组、NAT端口映射没有放开对应端口的入站规则,连接请求被网络设备直接丢弃,根本到达不了你的服务进程。
修复后代码

Socket服务端逻辑

import socket
import threading
import logging
from collections import deque

# 监听本机所有网卡接口,无需填写具体IP
HOST = '0.0.0.0'
PORT = 10063
conn_queue = []
threads = deque()
socket_timeout = 10  # 按需调整超时时间,单位秒

def get_connection(address=HOST, port=PORT, socket_timeout=socket_timeout, conn_queue=conn_queue):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        # 开启端口复用,避免服务重启时出现端口占用报错
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((address, port))
        # listen参数指定未完成连接队列的最大长度
        s.listen(5)
        logging.warning("Socket start listening on %s:%s", address, port)
        # 给socket设置超时,避免无连接时永久阻塞无任何日志输出
        s.settimeout(socket_timeout)
        while True:
            try:
                conn, addr = s.accept()
                logging.warning("Get connection from %s, push to queue", addr)
                conn_queue.append({'conn': conn, 'address': addr})
            except socket.timeout:
                # 超时为正常等待周期,打印调试日志即可,无需报错
                logging.debug("No connection in %s seconds, continue listening", socket_timeout)
                continue
            except Exception as e:
                # 其他异常必须打印完整错误栈
                logging.error("Accept connection failed: %s", str(e), exc_info=True)
                break

线程启动与主逻辑

注意:主线程如果执行完所有代码直接退出,作为守护线程的socket处理线程会被直接强制终止,必须保证主线程持续运行。

if __name__ == '__main__':
    socket_handler = threading.Thread(
            target=get_connection, daemon=True)
    socket_handler.start()
    threads.append(socket_handler)
    
    # 主线程保持运行,处理队列中的连接
    while True:
        if conn_queue:
            conn_item = conn_queue.pop(0)
            conn = conn_item['conn']
            addr = conn_item['address']
            # 在这里写你的连接处理逻辑
            conn.sendall(b"Connected to server successfully")
            conn.close()
验证步骤
  1. 替换HOST为0.0.0.0重启服务,先在本机执行telnet 127.0.0.1 10063测试,如果能连通说明socket服务本身工作正常
  2. 本地连通后外部仍无法访问的,依次检查本机防火墙、云服务器安全组、路由器端口映射规则,放开10063端口的TCP入站权限
  3. 去掉s.listen()后误导性的客户端已发现日志,所有连接相关日志放在accept()调用返回后打印

内容的提问来源于stack exchange,提问作者William Huynh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:09:30