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

Paho-MQTT断网后无法重连,socket.gaierror异常如何解决?

MQTT封装类网络断开后触发socket.gaierror异常的解决方法

问题描述

我实现了一个MQTT封装类,正常运行无问题,但网络断开后出现socket.gaierror: [Errno -3] Temporary failure in name resolution异常。当前使用paho-mqtt 1.6.1版本,已设置self.suppress_exceptions = True以阻止paho-mqtt抛出异常,但socket层仍报错,请问如何避免该类型异常?

封装类代码

from paho.mqtt.client import Client as mqttClient
import paho.mqtt.client as paho
from queue import Queue
import time

class mqtt_instance:
    def __init__(self, client_id, host, port, auth):
        #"mqttClient.CallbackAPIVersion.VERSION1" for paho-mqtt version 2.0.0 otherwise remove it
        self._client_id = client_id
        self._host = host
        self._port = port
        
        self.suppress_exceptions = True
        
        self.connected = False
        self._reconnect = True

        # Just as a placeholder in def
        self.do_nothing = None
        # This list is needed when client re-connects to broker to re-subscribe to topics
        self.topic_list = []
        
    # setup queue to capture messages from topic subscription
        self.q = Queue()

        # instantiate client from paho.mqtt library
        #print('MQTT WRAPPER: Instantiating mqtt client...')
        #self.client = mqttClient(mqttClient.CallbackAPIVersion.VERSION1)
        self.client = mqttClient(client_id=self._client_id, userdata=None, protocol=paho.MQTTv5)

        # Auth
        if auth is not None:
            self._user = auth[0]
            #print('MQTT WRAPPER: user:', self._user)
            self._pass = auth[1]
            #print('MQTT WRAPPER: pass:', self._pass)
            # enable TLS for secure connection
            self.client.tls_set(tls_version=paho.ssl.PROTOCOL_TLS)
            # set username and password
            self.client.username_pw_set(self._user, self._pass)

        # register callbacks
        #print('MQTT WRAPPER: registering callbacks...')
        self.client.on_connect = self._on_connect
        self.client.on_disconnect = self._on_disconnect
        self.client.on_subscribe = self._on_subscribe
        self.client.on_publish = self._on_publish
        self.client.on_unsubscribe = self._on_unsubscribe
        self.client.on_message = self._on_message

    def _on_connect(self, client, userdata, flags, rc, properties=None):
        print('MQTT WRAPPER: connected')
        #print('MQTT WRAPPER: rc = {0}'.format(rc))

        if rc == 0:
            #print('MQTT WRAPPER: MQTT connection established...')
            self.do_nothing = None
        else:
            #print('MQTT WRAPPER: MQTT connection failed...')
            self.do_nothing = None

        self.connected = True

        for topic in self.topic_list:
            self.client.subscribe(topic)

    def _on_reconnect(self):
        print('MQTT WRAPPER: reconected')
        self.connected = True

    def _on_disconnect(self, client, userdata, rc, properties=None):
        #print('MQTT WRAPPER: on disconnect')
        self.connected = False
        print('MQTT WRAPPER: disconnected!')
        
        self.client.reconnect()

    def begin(self):
        # connect the client to the mqtt broker
        while not self.check_internet_connection:
            time.sleep(30)
        #print('MQTT WRAPPER: establishing connection...')
        self.client.connect(
            host=self._host,
            port=self._port,
            keepalive=60
        )
        self.client.loop_start()

异常信息

File "/home/pi/venv-ts/lib/python3.12/site-packages/paho/mqtt/client.py", line 3685, in _create_socket_connection
return socket.create_connection(addr, timeout=self._connect_timeout, source_address=source)
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/socket.py", line 828, in create_connection
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/socket.py", line 963, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
socket.gaierror: [Errno -3] Temporary failure in name resolution

解决方法

1. 修正suppress_exceptions的设置位置

原代码仅给封装类设置了suppress_exceptions = True,并未传递给paho-mqtt客户端实例,需要把该属性绑定到客户端上:

# 在__init__方法中实例化client后添加
self.client.suppress_exceptions = True

2. 用paho自带的自动重连替代手动调用

paho-mqtt内置自动重连机制,可通过配置避免手动重连时的异常泄露。在__init__中添加自动重连参数:

# 配置自动重连的延迟范围,指数退避
self.client.reconnect_delay_set(min_delay=1, max_delay=60)

然后修改_on_disconnect方法,移除手动reconnect()调用:

def _on_disconnect(self, client, userdata, rc, properties=None):
    self.connected = False
    print('MQTT WRAPPER: disconnected!')
    # 无需手动调用重连,客户端会自动触发

3. 捕获DNS解析异常并实现退避重试(手动重连场景)

如果坚持手动重连,需要在_on_disconnect中捕获socket.gaierror并添加退避逻辑:

# 先在文件顶部导入socket模块
import socket

def _on_disconnect(self, client, userdata, rc, properties=None):
    self.connected = False
    print('MQTT WRAPPER: disconnected!')
    
    retry_delay = 1
    max_delay = 60
    while self._reconnect:
        try:
            client.reconnect()
            break
        except socket.gaierror:
            print(f'MQTT WRAPPER: DNS解析失败,{retry_delay}秒后重试')
            time.sleep(retry_delay)
            retry_delay = min(retry_delay * 2, max_delay)
        except Exception as e:
            print(f'MQTT WRAPPER: 重连失败: {str(e)}')
            time.sleep(retry_delay)
            retry_delay = min(retry_delay * 2, max_delay)

4. 修复begin方法的网络检查逻辑

原代码中check_internet_connection未定义,需要实现可靠的网络检测函数:

def check_internet_connection(self):
    try:
        socket.getaddrinfo(self._host, self._port)
        return True
    except socket.gaierror:
        return False

然后修改begin方法的调用:

def begin(self):
    while not self.check_internet_connection():
        print('MQTT WRAPPER: 网络未连接,30秒后重试')
        time.sleep(30)
    self.client.connect(
        host=self._host,
        port=self._port,
        keepalive=60
    )
    self.client.loop_start()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:04:53