MQTT客户端
之间要想实现通讯,必须要通过MQTT服务端
。因此MQTT客户端无论是发布消息还是订阅消息,首先都要连接MQTT服务端。下面我们看一下MQTT客户端连接服务端的详细过程。
MQTT客户端连接服务端一共有两步。
CONNECT
。CONNACK
。在上面的描述中我们看到。MQTT客户端要想连接服务端,首先要向服务端发送CONNECT报文。如果此
CONNECT
报文的格式或内容不符合MQTT规范,则服务器会拒绝客户端的连接请求。
下图是CONNECT报文所包含的信息内容。
在接下来的课程讲解中我们将会频繁接触到两个概念。第一个概念是报文
,第二个概念是信息
。
所谓报文就是一个
MQTT数据包
。这个数据包中可能包含有多个信息。比如以上图片就是描绘了一个CONNECT
报文(数据包)的详细内容。
在这个CONNECT
报文(数据包)中包含有多个信息。上图左侧栏中的内容是CONNECT报文所包含的信息名称。右侧是信息的具体内容。如上图示例中,此CONNECT报文包含有名称为clientId
的信息,该信息的内容是”client-1
″。当然,上图只是一个示例,不是所有的CONNECT报文中的clientId信息内容都是”client-1″。
另外也请注意,上图中有些信息名称旁边标注了“可选
”字样,而有些则没有。那些没有标注“可选”字样的信息是必须包含在CONNECT报文中的。而对于标注了“可选”字样的信息,CONNECT报文既可以包含它们也可以没有它们。
ClientId
是MQTT客户端的标识。MQTT服务端用该标识来识别客户端。因此ClientId必须是独立的。如果两个MQTT客户端使用相同ClientId标识,服务端会把它们当成同一个客户端来处理。通常ClientId是由一串字符所构成的,如上图所示,此示例中的clientID是“client-1”。
所谓“清除会话”这一翻译源自MQTT官方文档中文版。要说明
cleanSession
的具体含义,首先要从MQTT网络环境讲起。
MQTT客户端与服务端的连接可能不是非常稳定,在不稳定的网络环境下,要想保证所有信息传输都能够做到准确无误,这是非常困难的。因此,我们就要根据客户端对系统运行的重要性来区别对待。
有些MQTT客户端对整个系统运行起着关键作用,这些客户端一定要准确无误的收到服务端发来的报文。比如一辆自动驾驶汽车的导航系统。假如这个导航系统错过了服务端发来的报文,可能会导致交通事故甚至人员伤亡。因此,即使网络不是非常稳定,我们仍然要求汽车导航系统一定要准确无误的收到服务端所发来的报文。
但是有些MQTT客户端对整个系统运行并不是很重要。比如同样是这辆自动驾驶汽车。它的音乐播放系统如果没有及时收到服务端发来的音乐播放报文,这对驾驶系统来说影响不大。
以上所举的两个例子说明,MQTT通讯中有些客户端必须准确无误的收到报文,有些则不需要。
为了保证重要的MQTT报文可以被客户端准确无误的收到。在服务端向客户端发送报文后,客户端会向服务端返回一个确认报文。如果服务端没有收到客户端返回的确认报文,那么服务端就会认为刚刚发送给客户端的报文没有被准确无误的送达。在这种情况下,服务端将会执行以下两个操作:
操作1:将尚未被客户端确认的报文保存起来**
操作2:再次尝试向客户端发送报文,并且再次等待客户端发来确认信息。**
讲到这里就要看看cleanSession的作用了。
如果
cleanSession
被设置为“true
”。那么服务端不需要客户端确认收到报文,也不会保存任何报文。在这种情况下,即使客户端错过了服务端发来的报文,也没办法让服务端再次发送报文。其实我们从字面上也很容易理解。cleanSession 的第一个词是clean。这个词的意思是clean(干净)的。服务端一旦发送完报文,就会把报文忘得“干干净净”了。
反过来,如果我们将
cleanSession
设置为”false
”。那么服务端就知道,后续通讯中,客户端可能会要求我保存没有收到的报文。
从以上的描述不难看出,如果某个客户端用于收发非常重要的信息(比如前文示例中汽车自动驾驶系统),那么该客户端在连接服务端时,应该将cleanSession设置为”false”。这样才能让服务端保存那些没有得到客户端接收确认的信息。以便服务端再次尝试将这些重要信息再次发送给客户端。
相反的,如果某个客户端用于收发不重要的信息(比如前文示例中车载音乐系统)那么该客户端在连接服务端时,应该将cleanSession设置为”true”。
请注意,如果需要服务端保存重要报文,光设置cleanSession 为false是不够的,还需要传递的MQTT信息QoS级别大于0。
关于QoS的概念,我们会在本教程后续课程中详细讲解。到目前请您务必牢记,如果想让服务器记住重要报文,那么客户端在连接服务端时,需要把cleanSession中设置为false。这一点非常关键,请务必牢记。
KeepAlive
(心跳时间间隔)正是用于服务端了解客户端连接情况的。不过关于KeepAlive (心跳时间间隔)目前讲解还为时过早,我们会在后续的课程中给您做详细介绍。目前您只需要记住,KeepAlive用于服务端实时了解客户端是否与其保持连接的情况。
以上就是CONNECT报文的主要内容。
下面为MQTT服务端接收到客户端发来的连接请求后所回复的CONNACK报文详细内容。
CONNACK
报文包括两个信息。一个是returnCode
(连接返回码),另一个是sessionPresent
(当前会话)。以下是这两个信息的说明:
当服务端收到了客户端的连接请求后,会向客户端发送
returnCode
(连接返回码),用以说明连接情况。如果客户端与服务端成功连接,则返回数字“0
”。如果未能成功连接,连接返回码将会是一个非零的数值,具体这个数值的含义,请见下表:
要说明sessionPresent,首先我们要回顾一下CONNECT报文中的cleanSession – 清除会话。
我们还用自动驾驶汽车为例。对于自动驾驶汽车来说,自动导航系统属于非常重要的MQTT客户端。服务端发送给导航系统的报文必须要准确无误的送达。相反,音乐播放系统就不那么重要了。即使音乐播放系统错过服务端发送的报文也没有关系。
对于不重要的MQTT客户端,它们在向服务器发送连接请求时,CONNECT报文中的cleanSession通常设置为true。原因是这类不重要的MQTT客户端即使丢失信息也不会影响整体系统运行。因此服务端在看到客户端的cleanSession为true时,就不会保存发送给它们的信息。
然而对于汽车导航系统这类重要的MQTT客户端来说。当它在连接服务端时,cleanSession肯定时设置为false。原因是重要客户端需要服务端确保信息发送准确无误。如果服务端发现发送给重要客户端的信息没有得到确认,会将报文进行保存。
当重要客户端连接服务端时,服务端可能保存着没有得到确认的报文。如果是这样的话,那么客户端在连接服务端时,就会通过sessionPresent来了解服务端是否有之前未能确认的信息。
下面我们分几种情况来讲述sessionPresent的作用。
首先,当客户端发送的
CONNECT
报文中的cleanSession
设置为true
。在这种情况下,客户端是不需要服务端保存任何报文的。那么服务端发送的确认连接CONNACK
报文中,sessionPresent
肯定是false
,也就是说,服务端没有保存任何报文。
当客户端发送的
CONNECT
报文中的cleanSession
设置为false
时,客户端是要求服务端保存报文的。在这种情况下,如果服务端的确保存了没有收到客户端接收确认的报文信息,那么cleanSession
为true
,否则为false
。
简言之,
CONNACK
报文的sessionPresent
与CONNECT
报文的cleanSession
相互配合。其作用是客户端发送连接请求时,服务端告知客户端有没有保存报文信息。这个被服务端保存的报文信息是来自于上一次客户端连接时,服务端曾经发送此报文给客户端,但是发送后没有收到客户端接收确认。
内容来自 -----> 太极创客
详情可见太极创客官网,内有Arduino、ESP32等详细教程