问题描述
我想确保我的程序在无法连接到 MQTT 服务器时崩溃。为此,我将 ConnectTimeout
设置为 10 秒,但是当连接到不存在的服务器(名称不存在)时,对 MQTT 的调用挂起
package main
import (
"fmt"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
func main() {
timeout,_ := time.ParseDuration("10s");
opts := mqtt.NewClientOptions()
opts.Addbroker("tcp://this.does.not.resolve.example.coooom:1883")
opts.SetClientID("monitor")
opts.SetorderMatters(false)
opts.SetConnectRetry(true)
opts.SetConnectTimeout(timeout)
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(fmt.Sprintf("cannot connect to MQTT: %v",token.Error()))
}
}
如何正确设置超时时间?
解决方法
opts.SetConnectRetry(true)
似乎将连接置于循环中(没有任何错误消息)。通过将代码更改为 ...
package main
import (
"fmt"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
func main() {
timeout,_ := time.ParseDuration("10s");
opts := mqtt.NewClientOptions()
opts.AddBroker("tcp://this.does.not.resolve.example.coooom:1883")
opts.SetClientID("monitor")
opts.SetOrderMatters(false)
opts.SetConnectTimeout(timeout)
client := mqtt.NewClient(opts)
if token := client.Connect(); token.Wait() && token.Error() != nil {
panic(fmt.Sprintf("cannot connect to MQTT: %v",token.Error()))
}
opts.SetConnectRetry(true)
}
...连接正确失败(并且希望,如果连接断开,客户端仍会重新连接)
编辑:我认为在连接尝试后移动 opts.SetConnectRetry(true)
不会使其自动重新连接(因为选项已经被使用)。这是一个 catch-22 的情况。
SetConnectRetry 设置连接函数是否会在失败时自动重试连接(当为真时,连接函数返回的令牌将不会完成,直到连接建立或被取消)如果 ConnectRetry 为真,则订阅应该在 OnConnect 处理程序中请求 将此设置为 TRUE 允许在建立连接之前发布消息。
所以当 SetConnectRetry(true)
Connect()
将重试直到成功或您停止它。不会尝试确定错误是否是永久性的,因为这非常困难(例如,无法解决 this.does.not.resolve.example.coooom
可能是由于互联网连接中断)。
注意:有一个单独的选项 SetAutoReconnect
控制断开的连接(在初始连接成功建立后)是否会导致客户端自动重新建立连接。
值得注意的是,添加 ConnectRetry
选项的主要原因是允许用户在连接出现之前发布消息(它们会在连接建立时自动发送)。这个想法是您应该能够调用 Connect
然后使用库而不必担心网络状态(显然,如果网络关闭,您将不会收到消息!)。
就如何与 SetConnectRetry
交互而言,SetConnectTimeout
docs 可能不那么清楚:
SetConnectTimeout 限制客户端在超时前尝试打开与 MQTT 服务器的连接时将等待的时间。持续时间 0 永远不会超时。默认 30 秒。目前仅适用于 TCP/TLS 连接。
所以这控制了我们等待单个连接尝试完成的时间。当 SetConnectRetry (true)
时,每次尝试连接时都会使用此间隔(每次尝试重新开始)。没有 RetryConnectionsFor
类型设置。
来自自我回答:
...连接正确失败(并且希望,如果连接断开,客户端仍会重新连接)
一旦调用了 NewClient(o *ClientOptions)
,您就无法更改选项(NewClient
获取选项的副本)。这样做是因为在操作正在进行时更改选项会导致不可预测的结果(例如,如果您在调用 opts.SetConnectRetry(true)
之后调用 Connect
,那么结果将取决于 Connect
调用是否已完成与否,这是不可预测的)。
我不太确定您所说的“确保我的程序在无法连接到 MQTT 服务器时崩溃”是什么意思,但我使用的方法类似于以下内容(将适当的操作替换为 {{1} } 语句) - 请注意,我还没有编译/测试这个:
fmt.PrintLn