MQTT协议_服务质量

19 篇文章 2 订阅
6 篇文章 1 订阅

服务质量

MQTT按照这里定义的服务质量 (QoS) 等级分发应用消息。分发协议是对称的,客户端和服务端既可以是发送者也可以是接收者。分发协议关注的是从单个发送者到单个接收者的应用消息。服务端分发应用消息给多个客户端时,每个客户端独立处理。分发给客户端的出站应用消息和入站应用消息的QoS等级可能是不同的。

MQTT定义了三个层次的服务质量:

l  QoS 0:最多分发一次;

l  QoS 1: 至少分发一次;

l  QoS 2: 仅分发一次

接下来,我们分别对这三个服务质量做特别的说明。

2.2.3.1 QoS 0,最多分发一次

消息的分发依赖于底层网络的能力。接收者不会发送响应,发送者也不会重试。消息可能送达一次也可能根本没送达。这个服务质量常用在鸡肋的消息传递中,即消息丢了也没有关系。

发送者:

必须发送QoS等于0,DUP等于0的PUBLISH报文。

接收者:

接受PUBLISH报文时同时接受消息的所有权。

使用场景:

尽力而为。

常用于广播。

交互方式:


断开重连

对于QoS 0的消息,在消息交互的过程中,如果出现断开重连的情况,丢失的消息报文也无需做特别的处理。

2.2.3.2 QoS 1,至少分发一次

服务质量确保消息至少送达一次,有可能存在多次发送的情况。

QoS 1的PUBLISH报文的可变报头中包含一个报文标识符,需要PUBACK报文确认。即需要接收者发送PUBACK回包,但是PUBACK回包只是用来重用相同的报文标识符,不影响后续非重复的报文标识符的发送。

发送者:

ü  每次发送新的应用消息都必须分配一个未使用的报文标识符。一旦发送者收到PUBACK报文,这个报文标识符就可以重用。

ü  发送的PUBLISH报文必须包含报文标识符且QoS等于1,DUP等于0。

ü  必须将这个PUBLISH报文看作是未确认的,直到从接收者那收到对应的PUBACK报文。

ü  允许发送者在等待确认时使用不同的报文标识符发送后续的PUBLISH报文。也就是说可以是异步的情况。

接收者:

ü  响应的PUBACK报文必须包含一个报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。

ü  发送了PUBACK报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH报文当作一个新的消息,并忽略它的DUP标志的值。简单的理解是,在发送PUBACK报文之后,如果还是接收到了一个相同的报文标识符,接收方应当认为这是一个新的报文,同时不关注DUP标志位的数值。

使用场景:

保证送达,可能重复

交互方式:

Client[Qos=1,DUP=0/*重复次数*/,MessageId=x]--->PUBLISH--> Server收到后,存储Message,发布,删除,向Client回发PUBACK。

Client收到PUBACK后,删除Message;如果未收到PUBACK,设置DUP++,重新发送,Server端重新发布,所以有可能重复发送消息。

断开重连

如果在消息分发的过程中出现了断开重连的情况,且客户端设置清理会话(CleanSession)标志为0重连时,客户端和服务端必须使用原始的报文标识符重发任何未确认的PUBLISH报文(如果QoS>0)和PUBREL报文。

且发送端重发任何之前的PUBLISH报文时,必须按原始PUBLISH报文的发送顺序重发。

接收端必须按照对应的PUBLISH报文的顺序发送PUBACK报文。

2.2.3.3 QoS 2,仅分发一次

这是最高等级的服务质量,消息丢失和重复都是不可接受的。使用这个服务质量等级会有额外的开销。

QoS 2的消息可变报头中有报文标识符。QoS 2的PUBLISH报文的接收者使用一个两步确认过程来确认收到。

发送者:

ü  必须给要发送的新应用消息分配一个未使用的报文标识符。一旦发送者收到PUBCOMP报文,这个报文标识符就可以重用。

ü  发送的PUBLISH报文必须包含报文标识符且报文的QoS等于2,DUP等于0。

ü  必须将这个PUBLISH报文看作是未确认的 ,直到从接收者那收到对应的PUBREC报文。

ü  收到PUBREC报文后必须发送一个PUBREL报文。PUBREL报文必须包含与原始PUBLISH报文相同的报文标识符。

ü  必须将这个PUBREL报文看作是未确认的 ,直到从接收者那收到对应的PUBCOMP报文。

ü  一旦发送了对应的PUBREL报文就不能重发这个PUBLISH报文。

接收者:

ü  响应的PUBREC报文必须包含报文标识符,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。

ü  在收到对应的PUBREL报文之前,接收者必须发送PUBREC报文确认任何后续的具有相同标识符的PUBLISH报文。 在这种情况下,它不能重复分发消息给任何后续的接收者。

ü  响应PUBREL报文的PUBCOMP报文必须包含与PUBREL报文相同的标识符。

ü  发送PUBCOMP报文之后,接收者必须将包含相同报文标识符的任何后续PUBLISH报文当作一个新的发布。

使用场景:

不重复不丢失,是最理想的网络收发状态。

交互方式:


断开重连

如果在消息分发的过程中出现了断开重连的情况,且客户端设置清理会话(CleanSession)标志为0重连时,客户端和服务端必须使用原始的报文标识符重发任何未确认的PUBLISH报文(如果QoS>0)和PUBREL报文。

且发送端重发任何之前的PUBLISH报文时,必须按原始PUBLISH报文的发送顺序重发。

接收端必须按照对应的PUBLISH报文的顺序发送PUBREC报文。

发送端必须按照对应的PUBREC报文的顺序发送PUBREL报文。

2.2.3.4 几种QoS之间的关系

在MQTT3.1.1协议的设计过程中,涉及到QoS的报文信息包括以下几个类型:订阅,订阅确认,消息发布,消息分发。

1)订阅和订阅确认中的QoS

订阅是客户端向服务器端申请主题的行为,在每一个订阅报文中,为每一个订阅的主题指定了最大的QoS等级。而服务器端收到订阅请求之后,可以决定给每一个订阅主题的开放何种等级的QoS,并通过SUBACK告知客户端。

即订阅QoS >= 订阅确认QoS

2)消息发布和消息分发

消息发布通过PUBLISH报文实现,可能是服务器端到客户端,也可能是客户端到服务器端。如果是第二种情况的话,那就还需要服务器端根据订阅主题列表,还确认是否将该报文分发,于是就产生了消息分发的动作,在消息分发的报文中,也是包含有QoS的。

于是就涉及到发布消息的QoS,客户端收到订阅确认的QoS等级,以及分发消息(客户端收到消息)的QoS。那这三个之间的关系是如何呢?

一个简单的原则就是:第三个QoS是前两个QoS中的最小者。

列表如下:

发布消息的QoS

Topic订阅确认的QoS

分发消息(接收消息)的QoS

0

0

0

1

0

0

2

0

0

0

1

0

1

1

1

2

1

1

0

2

0

1

2

1

2

2

2



版权所有,转载请注明出处:http://www.junsion.icoc.bz/ by 小丑

这段代码是一个使用MQTT协议进行消息传输的示例。下面是对每个部分的解释: ```c++ char *address = "tcp://127.0.0.1:1234"; ``` 设置MQTT服务器的地址和端口。 ```c++ char *client_id = "MQTT_FX_Client2"; ``` 设置客户端的唯一标识符。 ```c++ char *topic = "PHM/Topics/WaveData/111"; ``` 设置消息的主题。 ```c++ std::string strResult; strResult = writer.write(root); ``` 将一个JSON对象(root)转换为字符串(strResult)。 ```c++ const int time_out = 10000; ``` 设置等待消息发布完成的超时时间(以毫秒为单位)。 ```c++ int rv; int QOS = 1; ``` 定义变量用于存储函数返回值和消息服务质量等级。 ```c++ MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_message publish_msg = MQTTClient_message_initializer; MQTTClient_message publish_msg1 = MQTTClient_message_initializer; MQTTClient_deliveryToken token; ``` 定义MQTT客户端、连接选项、发布消息和传递令牌。 ```c++ conn_opts.keepAliveInterval = 60; conn_opts.cleansession = 1; ``` 设置连接选项,包括心跳间隔和是否清除会话。 ```c++ MQTTClient_create(&client, address, client_id, MQTTCLIENT_PERSISTENCE_NONE, nullptr); ``` 创建MQTT客户端实例。 ```c++ if ((rv = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("MQTTClient_connect failure:%s\n", strerror(errno)); return 0; } ``` 尝试连接到MQTT服务器,如果连接失败,则打印错误信息并返回。 ```c++ publish_msg1.qos = QOS; publish_msg1.retained = 0; ``` 设置发布消息服务质量等级和保留标志。 ```c++ while (1) { printf("enter the message you want to send\n"); publish_msg1.payload = (void*)strResult.c_str(); publish_msg1.payloadlen = strResult.size(); MQTTClient_publishMessage(client, topic, &publish_msg1, &token); rv = MQTTClient_waitForCompletion(client, token, time_out); printf("Message with delivery token %d delivered\n", rv); printf("%s\n", strResult.c_str()); sleep(3); } ``` 在一个无限循环中,用户可以输入要发送的消息,然后将其发布到指定的主题上。然后等待消息发布完成并打印相关信息,然后等待3秒再次循环。 请注意,这只是代码的一个片段,如果想要完整运行该代码,可能还需要其他的依赖项和逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值