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

Docker中Python TCP对接PLC偶发Errno 99无法分配请求地址问题求助

问题成因
  • 核心原因是本地临时端口耗尽:你当前的代码逻辑每次发送数据都会新建一个TCP连接,发送完成后主动调用close()关闭连接,主动关闭连接的一方会进入TIME_WAIT状态,默认会持续2MSL(通常为1-2分钟),该状态下对应的本地端口会被占用,无法分配给新连接。按照你每小时300次连接的运行频率,长期运行后端口释放速度跟不上新建速度,就会抛出[Errno 99] Cannot assign requested address错误。
  • 代码缺少异常兜底逻辑:如果connect()、send()执行过程中抛出异常,当前代码不会执行到socket.close(),会直接导致socket资源泄漏,进一步加快端口耗尽的速度。
  • 由于Docker使用了--network host参数,容器和宿主机共享网络栈,端口耗尽问题会直接作用在宿主机网络层,重启设备/插拔网线会重置所有网络连接,释放占用的端口,因此可以临时恢复业务。
解决方案

最优方案:改用TCP长连接复用

从根源上避免频繁新建/关闭连接产生的大量TIME_WAIT,初始化一次连接后重复使用,连接断开后自动重连即可,参考修改逻辑:

# 全局或类成员变量保存socket实例
socket = None
def init_connection():
    global socket
    try:
        if socket:
            socket.close()
        socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        socket.setsockopt(socket.SOL_SOCKET, 25, str("enp6s0" + '\0').encode('utf-8'))
        socket.connect(('192.168.1.123', 2000))
    except Exception as e:
        socket = None
        # 可根据需要添加重试逻辑

# 发送数据逻辑
if some_boolean:
    if not socket:
        init_connection()
    try:
        sent1 = socket.send(lane_id.to_bytes(2, 'little'))
        sent2 = socket.send(delay.to_bytes(2, 'little'))
        sent3 = socket.send(open_lane.to_bytes(2, 'little'))
        total_bytes = sent1 + sent2 + sent3
    except Exception as e:
        # 连接出错重置,下次发送自动重连
        socket = None

临时方案:优化短连接逻辑+调整内核参数

如果业务必须保留短连接逻辑,可做两项优化:

  1. 新增try-finally结构,确保无论请求是否成功,socket都会被关闭:
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    socket.setsockopt(socket.SOL_SOCKET, 25, str("enp6s0" + '\0').encode('utf-8'))
    socket.connect((TCP_IP_Client, TCP_PORT_Client))
    if some_boolean:
        sent1 = socket.send(lane_id.to_bytes(2, 'little'))
        sent2 = socket.send(delay.to_bytes(2, 'little'))
        sent3 = socket.send(open_lane.to_bytes(2, 'little'))
        total_bytes = sent1 + sent2 + sent3
finally:
    socket.close()
  1. 修改宿主机/etc/sysctl.conf配置,加速TIME_WAIT回收、扩大可用端口范围:
# 开启TIME_WAIT套接字快速回收
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
# 扩大本地临时端口范围
net.ipv4.ip_local_port_range = 1024 65535

修改完成后执行sysctl -p即可生效。

内容的提问来源于stack exchange,提问作者Tim Treurniet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 21:00:03