简介

MQTT 全称为 Message Queuing Telemetry Transport(消息队列遥测传输)是一种基于发布/订阅范式的“轻量级”消息协议,由 IBM 发布。MQTT 可以被解释为一种低开销,低带宽占用的即时通讯协议,可以用极少的代码和带宽的为连接远程设备提供实时可靠的消息服务,它适用于硬件性能低下的远程设备以及网络状况糟糕的环境下,因此 MQTT 协议在 IoT(Internet of things,物联网),小型设备应用,移动应用等方面有较广泛的应用。

消息订阅和发布

什么是消息订阅和发布呢?我的个人理解就像客户定报纸一样,世界上那么多报纸,但是消费者只订阅自己喜欢的报纸。特别是现在信息时代,我们接收到太多的信息,我们只要订阅我们自己喜欢的,那么就相当于过滤了其他信息了。是不是还有点抽象?

不急,我们先在说下几个名词。

QoS

QoS:发布消息的服务质量,即:保证消息传递的次数,和现在的快递类似,你说一个快递容易丢失有人敢用吗?快递就有一个服务质量等级了。消息也一样。

QoS 0:服务质量 0,最多传输一次。即:<=1,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
QoS 1:服务质量1,至少传输一次。即:>=1,确保消息到达,但消息重复可能会发生。
QoS 2:服务质量2,仅仅传输一次。即:=1,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。保证消息接收者成功接收一次,造成并发性能下降以及消息传递时延增加
QoS 3:预留(不是很确定,看到有博主提到有此项,暂时未查证)

发布QoS 等级为 2 ,客户端订阅QoS 等级为 0, 那么客户端接收到的 QoS = 0

发布QoS 等级为 0 ,订阅QoS 等级为 2,那么客户端接收到的 QoS = 0

 

言归正传,我们来说

发布(publish):

我的个人理解就像媒体生产报纸一样,世界上有很多报纸,媒体很多,发布的信息也就多(消费者可以只订阅自己喜欢的报纸),那我们来写一张报纸吧,这张报纸你可以自己定义名称,这里我们叫“topic2”,当然你可以取其他名称。比如“250”,比如“2b”,嘿嘿。我们还是看开源库mosquitto源码API吧

//int mosquitto_publish(struct mosquitto *mosq, int *mid, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
// mosquitto_publish(mosq,NULL,"topic2 ",strlen(buff)+1,buff,0,0);
 mosquitto_publish(mosq,NULL,"topic2 ",strlen(“hell qmtt”)+1,“hell qmtt”,0,0);

这样我们就发布了一个一张报纸,名称叫“topic2”,里面写什么内容呢?就是内容在buff中,buff你可以填入“hello mqtt”

订阅(Subscription):

 

我们来看一个开源库mosquitto源码API,

//原型 
//int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub, int qos)
mosquitto_subscribe(mosq, NULL, "topic2 ", 2);

第一第二个参数我们可以先不管,我们先看第三个和第四个参数,第三个参数“topic2”什么意思呢?就是我们要订阅的报纸,这里报纸名称可以你自己定义,当然了这个报纸得有人出版,不然你永远无法收到报纸。这里我们订阅的报纸名称叫“topic2”,这个消息的质量等级QoS为2,就是仅仅传输一次。

主题(Topic)

什么是主题呢?主题就是我们刚刚订阅的报纸,主题名叫“topic2”。这张“topic2”报纸里面有一些消息,就是“hell qmtt”。

  • 发布消息或者订阅消息都要选定一个消息主题,消息主题可以任意定制,类似文件系统,用 “/” 进行分隔,例如主题为 /a/b/c/d 的消息
  • 客户端可以使用完全字符匹配消息,也可以使用通配符进行消息匹配
  • 通配符 + :替换任意单个层级。比如订阅 /a/b/c/d、/a/+/c/d 、+/+/+/+ 主题的消息即可收到主题为 /a/b/c/d 的消息,而 b/+/c/d 、 +/+/+ 不会匹配
  • 通配符 # :匹配任意层级,只能用于末尾, #、a/# 可以匹配上面的主题消息
  • 长度为 0 的主题层级也是允许的。比如发布主题为 a//topic 的消息,客户端可以用 a/+/topic 进行匹配。/a/topic 的主题用 +/a/topic、#、/# 可以匹配

有效载荷 Payload

消息订阅者所具体接收的内容。具体点比较通俗来讲就是这张“topic2”报纸里面的消息,就是“hell qmtt”,当然了这个是不全对的。看到一个文档是这么写的:有效载荷包含一个或多个编码的字段。包括客户端的唯一标识符,Will主题,Will消息,用户 名和密码。除了客户端标识之外,其它的字段都是可选的,基于标志位来决定可变报头中是 否需要包含这些字段。而对于 PUBLISH来说有效载荷就是应用消息。对于CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的 标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主 题,遗嘱消息,用户名,密码 [MQTT-3.1.3-1]。

 

一个QMTT协议中有三个角色会参与到整个通信过程,发布者(publisher)、代理(broker)和订阅者(subscriber)

 

由于是刚学还不是很懂,根据网上的资料,我个人理解,发布者也可以是订阅者,就像人民日报可以订阅新华日报,新华日报同样可以订阅人民日报。订阅的消息可以在一个固定的地方接收到,就像,一些城市定牛奶,门口有一个箱子,而这个箱子是你自己设计制作的,这个箱子又叫回调函数,你可以在回调函数中接收到来自发布者发布并且你订阅的消息。

void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
	
    if(message->payloadlen){
        printf("%s %s", message->topic, (char *)message->payload);
    }else{
        printf("%s (null)\n", message->topic);
    }
    fflush(stdout);
}

void my_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
    int i;
    if(!result){
        /* Subscribe to broker information topics on successful connect. */
        mosquitto_subscribe(mosq, NULL, "topic1 ", 2);
    }else{
        fprintf(stderr, "Connect failed\n");
    }
}

void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
    int i;
    printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
    for(i=1; i<qos_count; i++){
        printf(", %d", granted_qos[i]);
    }
    printf("\n");
}
 mosquitto_message_callback_set(mosq, my_message_callback);
 mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);
 int loop = mosquitto_loop_start(mosq);

消息可以在my_message_callback(这个就是装牛奶的箱子,回调函数,名字可以自己取)这个自定义函数收到(有限实验得出的结论,不一定对)。

my_subscribe_callback(这个就是装牛奶的箱子,回调函数,名字可以自己取),这个函数是你订阅后会自动执行一次(实验得出的结论,不一定对)。

另外就是如果你买报纸或者订阅牛奶可能买一份吧!如果想不停的接收到牛奶那么就得长期订阅,这时候就得用一个长期订阅的东西了,这个就是一个消息循环,int loop = mosquitto_loop_start(mosq);这样你的消息就可以不断的接收到了(有限实验得出的结论,不一定对)

 

本人是一名mqtt初学者,还不是很懂,只是根据实验和别人的博客悟出的。如果有不对的地方还请指出。

致谢

感谢其他博主的倾情奉献。本文参考摘抄自以下博客,如果有侵权请联系及时删除。




 

 

下面是一些比较官方名词解释:


客户端 Client


使用 MQTT 的程序或设备。客户端总是通过网络连接到服务端。它可以


发布应用消息给其它相关的客户端。


订阅以请求接受相关的应用消息。


取消订阅以移除接受应用消息的请求。


从服务端断开连接。


5 第一章 - MQTT 介绍


服务端 Server


一个程序或设备,作为发送消息的客户端和请求订阅的客户端之间的中介。服务端


接受来自客户端的网络连接。


接受客户端发布的应用消息。


处理客户端的订阅和取消订阅请求。


转发应用消息给符合条件的已订阅客户端。


订阅 Subscription



订阅包含一个主题过滤器( Topic Filter )和一个最大的服务质量( QoS )等级。订阅与单个会



话( Session )关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过



滤器。



主题名 Topic Name



附加在应用消息上的一个标签,服务端已知且与订阅匹配。服务端发送应用消息的一个副本



给每一个匹配的客户端订阅。



主题过滤器 Topic Filter



订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以使用通配符。



会话 Session



客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端



和服务端的多个连续网络连接间扩展。



控制报文 MQTT Control Packet



通过网络连接发送的信息数据包。 MQTT 规范定义了十四种不同类型的控制报文,其中一个