Search code examples
gomqttpaho

why the mqtt client reconnect broker with an unique clientId?


When I just run a program to test connection with mqtt broker, client will always be lost. Here is my code


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)
}

the result is

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

I know it's because of the clientId. But now I just run a client called go_mqtt_client, I don't know if it's because of the configuration. I've had this problem twice. First time I don't remember what was changed and it can work. But the second time (Right now), I can't fix it. It just can work if I change the ClientId...


Solution

  • As per the comments the MQTT spec requires that:

    If the ClientId represents a Client already connected to the Server then the Server MUST disconnect the existing Client [MQTT-3.1.4-2].

    So if you have a connection using the ClientId go_mqtt_client and another connection comes in with the same ClientId your connection will be dropped (leading to the message you are seeing).

    The broker you are using (broker.emqx.io) is a free, public broker that comes with the advice to "Never use it in production". Due to its nature you have no way of knowing who else is using it or what ClientId's they are using (and if you subscribe to # you will see all of the messages being published to the broker!).

    The EMQX Demo code uses the ClientID go_mqtt_client; this means that there is a good chance that someone else is using the EMQX public broker with the same ID; in fact this is mentioned in a comment (from the "EMQ X" account) at the bottom of the page with the demo code.

    Given that the demo code uses the default options it will automatically reconnect if the connection is dropped. This means you get a sequence of events something like:

    1. You connect; causing the connection for user 2 (with same ClientId) to be dropped)
    2. User 2 automatically reconnects causing your connection to be droped.
    3. You automatically reconnect causing User 2's connection to be dropped.
    4. etc...

    While there is no way to be 100% certain that this is the cause of the issue you are seeing, it is certainly the most likely cause. As this is a freely available public broker this is just something you need to live with; using a random ClientId will minimise (the risk of collisions with a random 23 character ID are tiny) the chance of this happening.