【Go】MQTT的发布和订阅

背景

MQTT(Message Queue Telemetry Transport)是一种轻量级的消息传递协议,支持发布-订阅模式。在MQTT中,发布者将消息发布到主题(topic),而订阅者可以订阅一个或多个主题以接收相关消息。

要发布消息,客户端需要连接到MQTT代理(broker)并指定要发布的主题和消息内容。代理将消息转发给所有已经订阅该主题的客户端。

要订阅主题,客户端需要连接到MQTT代理并指定要订阅的主题。代理将根据订阅信息,向客户端发送所订阅主题下的所有消息。

可以使用不同QoS(Quality of Service)等级来控制消息传递的可靠性和效率。QoS级别越高,消息传递越可靠但是也会增加网络开销。

实现原理

MQTT的发布和订阅模式是基于代理(broker)来实现的。客户端通过连接到代理并发送相应的消息,代理将根据主题(topic)将消息转发给所有已经订阅该主题的客户端。

当客户端发布一个消息时,它需要指定要发布的主题和消息内容,并将消息发送到代理。代理会记录下该消息并向所有已经订阅该主题的客户端转发该消息。

当客户端订阅一个主题时,它需要指定所需的QoS(Quality of Service)等级和订阅主题的名称。代理会将此信息记录下来,并将该主题的所有未读消息发送给该客户端。在此之后,代理将继续向该客户端发送任何新的与该主题相关的消息。

注意:当客户端订阅主题时,可以使用通配符来匹配多个主题。例如,使用“+”订阅“a/+”将匹配所有以“a/”开头的主题。或者使用“#”订阅“a/#”将匹配所有以“a/”开头的主题及其子主题。

代码实现

初始化

package start

import (
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	log "github.com/sirupsen/logrus"
	"xxxx/common/config"
	mqttService "xxxx/common/mqtt"
	"time"
)

var MqttClient mqtt.Client

// 初始化MQTT
func MQTT() {
	opts := mqtt.NewClientOptions().AddBroker(config.MqttUrl)
	clientId := fmt.Sprintf("xxxx/xxxx/%d", time.Now().Unix())
	log.Info("clientId:", clientId)
	opts.SetClientID(clientId).
		SetUsername(config.MqttUsername).
		SetPassword(config.MqttPassword)

	// 重连订阅
	opts.SetReconnectingHandler(mqttService.Subscribe)
	opts.SetAutoReconnect(true)
	opts.SetKeepAlive(30 * time.Second)
	opts.SetPingTimeout(5 * time.Second)
	opts.SetDefaultPublishHandler(mqttService.Receive)

	MqttClient = mqtt.NewClient(opts)
	if token := MqttClient.Connect(); token.Wait() && token.Error() != nil {
		log.Fatalf("连接mqtt失败: %v", token.Error())
	}
	log.Info("Connect mqtt server successfully")
	// 订阅
	mqttService.Subscribe(MqttClient, opts)
}

 发布、接收、订阅

package mqttService

import (
	"encoding/json"
	"fmt"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"xxxx/common/config"
	"os"
	"strings"
)

// Send 发送MQTT
func Send(client mqtt.Client, topic string, body interface{}) bool {
	bytes, err := json.Marshal(body)
	if err != nil {
		log.Error("序列化失败", err)
		return false
	}

	if token := client.Publish(topic, 1, false, bytes); token.Wait() && token.Error() != nil {
		log.Error("发送 MQTT 失败", string(bytes), err)
		return false
	}
	return true
}

// Receive 接收 MQTT
func Receive(client mqtt.Client, msg mqtt.Message) {
	message := &vo.ReceiveVO{}
	if err := json.Unmarshal(msg.Payload(), message); err != nil {
		log.Errorf("Unmarshal mqtt message from %s failed, err = %s", msg.Topic(), err)
		return
	}
	log.Info("message = ", message)
	body := message.Body
	if &body == nil {
		return
	}
	log.Info("body = ", body)
}

// Subscribe 订阅
func Subscribe(client mqtt.Client, clientOptions *mqtt.ClientOptions) {
	topic := fmt.Sprintf("%s", config.MqttServerTopic)
	if token := client.Subscribe(fmt.Sprintf("$queue/%s", topic), 2, Receive); token.Wait() && token.Error() != nil {
		log.Fatalf("Subscribe topic %s failed, err: %s", topic, token.Error())
	}
	log.Infof("Subscribe topic %s successfully", topic)
}

 配置信息

package config

const (
	// mqtt 地址
	MqttUrl = "tcp://xxxxx:1883"
	// mqtt 用户名
	MqttUsername = "用户名"
	// mqtt 密码
	MqttPassword = "密码"
	// mqtt topic
	MqttServerTopic = "Topic"
)

猜你喜欢

转载自blog.csdn.net/qq_38428623/article/details/130520971