【问题标题】:why the mqtt client reconnect broker with an unique clientId?为什么 mqtt 客户端使用唯一的 clientId 重新连接代理?
【发布时间】:2021-06-03 08:00:16
【问题描述】:

当我只是运行一个程序来测试与 mqtt 代理的连接时,客户端总是会丢失。 这是我的代码


var messagePubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
    fmt.Printf("Received message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}

var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) {
    fmt.Println("Connected")
}

var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) {
    fmt.Printf("Connect lost: %v\n", err)
}

var messageSubHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
    fmt.Printf("Sub message: %s from topic: %s\n", msg.Payload(), msg.Topic())
}

func main() {
    opts := mqtt.NewClientOptions()
    opts.AddBroker("tcp://broker.emqx.io:1883")
    opts.SetClientID("go_mqtt_client")
    opts.SetResumeSubs(true)
    opts.SetAutoReconnect(true)
    opts.SetOrderMatters(false)
    opts.SetCleanSession(false)
    // opts.SetTLSConfig()
    opts.SetDefaultPublishHandler(messagePubHandler)
    opts.OnConnect = connectHandler
    opts.OnConnectionLost = connectLostHandler
    client := mqtt.NewClient(opts)
    if token := client.Connect(); token.Wait() && token.Error() != nil {
        panic(token.Error())
    }

    sub(client)

    s := make(chan os.Signal, 1)
    signal.Notify(s, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
    select {
    case <-s:
        glog.Infoln(`quit`)
        glog.Flush()
    }
}

func sub(client mqtt.Client) {
    topic := "topic/test"
    token := client.Subscribe(topic, 2, messageSubHandler)
    token.Wait()
    fmt.Printf("Subscribed to topic: %s\n", topic)
}

结果是

$ go run cmd/client/client.go 
Connected
Subscribed to topic: topic/test
Connect lost: EOF
Connected
Connect lost: EOF
Connected
...

我知道这是因为 clientId。但是现在我只是运行一个叫go_mqtt_client的客户端,不知道是不是配置的原因。我遇到过两次这个问题。第一次我不记得发生了什么变化,它可以工作。但是第二次(现在),我无法修复它。 It just can work if I change the ClientId...

【问题讨论】:

  • MQTT 规范要求代理在另一个客户端使用相同的客户端 ID 连接时断开会话。鉴于go_mqtt_client 在他们的demo code 中使用,您发出的问题很可能只是由于其他人使用相同的ID 连接(并且可能在断开连接时自动重新连接);有什么理由不能使用不同的 ID? (即更改opts.SetClientID("go_mqtt_client"))。
  • 当然我可以使用另一个 ClientID 来代替go_mqtt_client。我只是想知道为什么它一直在重新连接(这个时候有人在用这个ID吗?)
  • 最有可能;由于broker.emqx.io 是免费的公共 MQTT 代理,因此无法确定。但是,鉴于 go_mqtt_client 在示例代码中用作客户端 ID,因此很有可能有人在使用它(或者可能在代理的集成测试中使用它)。
  • go_mqtt_client 是否可能由于选项而被保存?
  • 不确定你的意思;客户端 ID 将是您设置的任何值(它不会存储在代码中以外的任何地方;代理将保留该客户端 ID 的会话记录,但这在这里并不真正相关)。

标签: go mqtt paho


【解决方案1】:

根据 cmets,MQTT spec 要求:

如果 ClientId 代表一个已经连接到服务器的客户端,那么服务器必须断开现有的客户端 [MQTT-3.1.4-2]。

因此,如果您有一个使用 ClientId go_mqtt_client 的连接,而另一个连接使用相同的 ClientId,您的连接将被丢弃(导致您看到的消息)。

您使用的代理 (broker.emqx.io) 是一个 free, public broker,带有“切勿在生产中使用它”的建议。由于其性质,您无法知道还有谁在使用它或他们正在使用什么 ClientId(如果您订阅 #,您将看到所有消息都发布到代理!)。

EMQX Demo code 使用 ClientID go_mqtt_client;这意味着很有可能其他人正在使用具有相同 ID 的 EMQX 公共代理;事实上,page with the demo code底部的评论(来自“EMQ X”帐户)中提到了这一点。

鉴于演示代码使用默认选项,如果连接断开,它将自动重新连接。这意味着您会得到一系列事件,例如:

  1. 您连接;导致用户 2(具有相同 ClientId)的连接被丢弃)
  2. 用户 2 自动重新连接,导致您的连接断开。
  3. 您会自动重新连接,导致用户 2 的连接断开。
  4. 等等……

虽然无法 100% 确定这是您所看到的问题的原因,但它肯定是最可能的原因。由于这是一个免费提供的公共经纪人,这只是您需要忍受的东西;使用随机 ClientId 将最大限度地减少(与随机 23 个字符的 ID 发生冲突的风险很小)发生这种情况的机会。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 2019-02-11
    相关资源
    最近更新 更多