一、MQTT 简介
图:MQTT 通信示例2
图: CONNACK 报文的内容
CONNACK 报文包括两个信息,一个是 returnCode(连接返回码),另一个是 sessionPresent。
returnCode--连接返回码:用来说明连接状态。
表:返回码说明
在 cleanSession=0 的情况下,当客户端连接到服务器之后,可通过 CONNACK 报文中返回的sessionPresent 来查询服务端是否为客户端保存了会话状态(客户端上一次连接时的会话状态信息),如果服务端已为客户端保存了上一次连接时的会话状态,则 sessionPresent=1,如果没有保存会话状态,则sessionPresent=0。
如果 cleanSession=1,在这种情况下,客户端是不需要服务端保存会话状态的,那么服务端发送的确认连接 CONNACK 报文中,sessionPresent 肯定是 false(sessionPresent=0),也就是说,服务端没有保存客户端的会话状态信息。
在以上 PUBLISH 报文讲解中,我们曾经提到过 QoS(服务质量等级)这一概念。同样的,客户端在订阅主题时也可以明确 QoS。服务端会根据 SUBSCRIBE 中的 QoS 来提供相应的服务保证。
另外每一个 SUBSCRIBE 报文还包含有“报文标识符”。报文标识符可用于对 MQTT 报文进行标识。不同的 MQTT 报文所拥有的标识符不同。MQTT 设备可以通过该标识符对 MQTT 报文进行甄别和管理。
当客户端向服务端发送 SUBSCRIBE 报文,服务端接收到 SUBSCRIBE 报文之后会向客户端回复一个SUBACK 报文(订阅确认报文),如下图所示:
图 :客户端订阅主题
表:返回码说明
图 :客户端取消订阅主题
客户端接收到 UNSUBACK 报文后就可以确认取消主题订阅已经成功完成了。
图 : MQTT.fx 下载地址
下载完成之后得到一个 exe 安装包文件,运行后如下所示:
也可使用MQTTBox
八、MQTT 服务端
MQTT 客户端搞定之后,接下来就是 MQTT 服务端的问题了。我们可以自己搭建一个 MQTT 服务器,也可以使用现成的 MQTT 服务器。
使用 Mosquitto 开源项目来搭建一个属于自己的 MQTT 服务器其实非常简单,如果有兴趣的读者可以百度搜索“搭建 Mosquitto服务器”便可找到一大堆相关的文章。
2、公用 MQTT 服务器
QoS = 0:最多发一次:最多一次,不管发送是否失败!发送端一旦发送完消息后,就完成任务了,发送端不会检查发出的消息能否被正确接收到。
QoS = 1:最少发一次
注意:Qos=1 时,MQTT 服务器是不会进行去重的,只要发布者或者服务器没有收到 PUBACK 报文,就认为主题消息没有发送成功进入重发;服务器或者订阅者,不会根据 dup 标志的值进行去重(也就是说
QoS = 2:保证收一次
当 MQTT 服务质量为 2 级时,MQTT 协议可以确保接收端只接收一次消息(注意是只接收到一次,在 QoS=1 的情况下,接收端接收到消息的次数可能不止一次:>=1)。
从上到下,按照 1、2、3、4 的顺序进行:
十、保留消息
PUBLISH 报文中有一个 retain保留标志,是一个布尔值,当 retain 设置为true 时表示保留消息,如果设置为 false 表示不保留消息。
应用场景: 比如客户端每小时整点发布消息,比如7:00发布了一条,但由于某种原因订阅这条信息的显示客户端重启了,重启后7:05分,但是下一次发布要到8:00,这时候问题就出现了。
为避免以上情况,我们可以让室温测量客户端在每次向室温主题发布消息时将 retain 标志设置为true,以告诉服务端接收到此消息之后需要保留这个消息,这样服务端就会将该消息进行存储、保留,无论显示客户端在任何时间订阅室温主题,订阅之后都会马上收到该主题中的“保留消息”,也就是温度测量客户端发布的最新室温消息。
当订阅之后我们的客户端立马就收到了一条消息,并且还标识了这条消息是“保留消息”。这就是“保留消息”的作用。
十、MQTT 的心跳机制
原理:让客户端在没有向服务端发送消息的这个空闲时间里,定时向服务端发送一个心跳包,这个心跳包被称为心跳请求,其实质就是向服务端发送一个 PINGREQ 报文;当服务端收到PINGREQ 报文后就知道该客户端依然在线,然后向客户端回复一个 PINGRESP 报文,称为心跳响应!(通过 keepAlive 设置时间间隔)如下图所示:
十一、MQTT 的遗嘱机制
客户端断开与服务端的连接通常是有两种方式的:
十一、MQTT 用户密码认证
有些 MQTT 服务端需要客户端在连接时提供用户名和密码,只有客户端正确提供了用户名和密码后,才能连接服务端,否则服务端将会拒绝客户端连接,那么客户端也就无法发布和订阅消息了。但有些 MQTT服务端并不需要客户端提供用户名、密码进行认证,譬如我们前面使用的公用 MQTT 服务器,无需提供用户名和密码也可连接。所以这个 username 和 password 是可选的参数,而非必须的,重点在于 MQTT 服务端是否需要用户名、密码认证。
用户名和密码除了用于在连接服务端时进行认证、校验这一功能外,有些 MQTT 服务端也利用此信息来识别客户端属于哪一个用户,从而对客户端进行管理。譬如用户可以拥有私人主题,这些主题只有该用户可以发布和订阅;对于私人主题,服务端就可以利用客户端连接时的用户名和密码来判断该客户端是否有发布订阅该用户私人主题的权限。
申请社区版 MQTT 服务
我们都是使用的公共版 MQTT 服务器进行了测试,既然是公共版,那就意味着大家都可以使用,只要输入了正确的服务器地址就可以连接,大家都可以对相同的主题发布消息、订阅该主题,导致我们发布的信息谁都能看到(只要它订阅了这个主题),这对物联网项目的安全性以及实用性方面来说都是不合适的,所以这些公用 MQTT 服务也仅供用于测试、学习!
事实上,然也物联平台也提供了免费的社区版 MQTT 服务,社区版 MQTT 服务是面向个人用户的免费MQTT 服务。与公共版 MQTT 服务不同的是,社区版 MQTT 服务中,用户个人主题和信息传输受到用户名和密码保护。即,A 用户的个人主题只有 A 用户可以发布和订阅,其他用户不能对该主题进行订阅和发布,这样会使得安全性得到提升。
当客户端连接社区版 MQTT 服务端时,需要提供正确的用户名和密码,服务端会对此进行验证,如果没有提供正确的用户名、密码信息,则服务器将拒绝为用户提供 MQTT 服务,也就是拒绝客户端连接。所以,我们个人用户可使用然也物联的社区版 MQTT 服务来搭建自己的私人物联网项目,注意仅限于个人用户使用,不可商用!
那接下来,笔者将向大家介绍如何通过然也物联平台申请社区版 MQTT 服务。首先进入到然也物联的官方网站:http://www.ranye-iot.net/
大家根据指示填写信息,完成用户注册。注册完成之后登陆然也物联平台,登陆成功之后如下所示:
左上角会出现一个“平台申请”链接,点击“平台申请”链接即可申请然也物联的社区版 MQTT 服务,如下所示:
同样,大家根据指示说明填写好信息。在填写信息之前,仔细阅读相关说明以及相应的要求,最后有三个题目需要大家填写正确,只有正确回答所有问题最终才会显示“提交申请”这个按钮。这样做为了防止申请服务的用户是真正需要使用 MQTT 服务的用户、而不是随随便便的一个用户。
当我们提交申请之后,页面会出现一个提示信息,这个大家要认真看一下,提示中说到:然也物联官方工作人员会在未来几天之内添加你申请时留下的微信号,以人工的形式进一步完成申请审核。所以大家要留意下自己的微信,未来几天内会不会有然也物联官方工作人员添加你为好友,到时你要同意一下。
工作人员会通过微信通知我们,告诉我们申请已经成功了!接着工作人员会将相关的使用注意事项、使用方法通过微信发送给您,大家要认真阅读尤其是注意事项;如果违反了它的规定,将会停止您使用社区版服务。除了注意事项之外,还包括对于我们使用社区版 MQTT 服务非常重要的信息,譬如社区版 MQTT 服务器的地址(iot.ranye-iot.net)、端口(1883)以及然也物联给我们提供的客户端连接认证信息。
然也物联给每一个申请的用户提供了 8 组客户端连接认证信息,也就是 8 组用户名、密码、clientId,也就是说允许我们同时使用 8 台客户端设备连接服务端;每一台客户端设备连接服务端时使用其中一组用户名、密码、clientId 信息,只有用户名、密码、clientId 匹配、服务端的认证才会通过、才可成功连接到服务端。
MQTT 客户端库支持多种不同的编程语言,我们使用的是 C 语言开发,所以要选择 MQTT C 客户端库,如下所示:
这里有多种不同的 MQTT C 客户端库,笔者推荐大家使用第一个 Eclipse Paho C,这是一个“MQTT CClient for Posix and Windows”,Paho MQTT C 客户端库是用 ANSI 标准 C 编写的功能齐全的 MQTT 客户端库,可运行在 Linux 系统下,支持 MQTT3.1、MQTT3.1.1、MQTT5.0。
在这个页面中会有一些简单地介绍信息,大家可以自己看一看。我们往下看,找到它的下载地址:
点击右边的“Release”找到它的发布版本,如下所示:
目前最新的版本是 1.3.9,我们不使用最新版本,建议大家使用 1.3.8 版本,如上图所示,点击“Sourcecode (tar.gz)”链接地址下载客户端库源码。
下载成功之后会得到如下压缩文件:
交叉编译 MQTT C 客户端库源码
将 paho.mqtt.c-1.3.8.tar.gz 压缩文件拷贝到 Ubuntu 系统某个目录下,如下所示:
接着将其解压到当前目录,如下所示:
解压成功之后会得到 paho.mqtt.c-1.3.8 文件夹,这就是 paho MQTT C 客户端库源码工程,进入到该目录下,可以看到工程顶级目录下有一个 CMakeLists.txt 文件,所以可知这是一个由 cmake 构建的工程。
首先我们要新建一个交叉编译配置文件 arm-linux-setup.cmake,进入到 cmake 目录下,新建 arm-linuxsetup.cmake 文件,并输入以下内容:
进入到 build 目录下,执行 cmake 进行构建:
~/tools/cmake-3.16.0-Linux-x86_64/bin/cmake 这是第三十二章时笔者下载的 3.16.0 版本的 cmake 工具,您 得 根 据 自 己 的 实 际 路 径 来 指 定 ; CMAKE_BUILD_TYPE 、 CMAKE_INSTALL_PREFIX 、
cmake 执行完毕之后,接着执行 make 编译:
这里需要给大家简单地说明一下,事实上,MQTT 客户端库依赖于 openssl 库,所以通常在移植 MQTT客户端库的时候,需要先移植 openssl、交叉编译 openssl 得到库文件以及头文件,然后再来编译 MQTT 客
编译成功之后,执行 make install 进行安装:
对安装目录下的文件夹进行简单介绍
进入到安装目录下:
在安装目录下有 bin、include、lib 以及 share 这 4 个文件夹,bin 目录下包含了一些简单的测试 demo,lib 目录下包含了我们编译出来的库文件,如下所示:
一共有 4 种类型的库,这里我们简单地介绍一下:
拷贝库文件到开发板
十三、MQTT 客户端库 API 介绍
1、MQTTClient_message 结构体
这里向大家介绍一个结构体 MQTTClient_message,该结构体很重要,MQTT 客户端应用程序发布消息和接收消息都是围绕着这个结构体。MQTTClient_message 数据结构描述了 MQTT 消息的负载和属性等相关
当客户端发布消息时就需要实例化一个 MQTTClient_message 对象,同理,当客户端接收到消息时,其实也就是接收到了 MQTTClient_message 对象。通常在实例化 MQTTClient_message 对象时会使用
在连接服务端之前,需要创建一个客户端对象,使用 MQTTClient_create 函数创建:
handle:MQTT 客户端句柄;
persistence_context:如果使用 MQTTCLIENT_PERSISTENCE_NONE 持久化类型,则该参数应设置为NULL。如果选择的是 MQTTCLIENT_PERSISTENCE_DEFAULT 持久化类型,则该参数应设置为持久化目
注意,"tcp://iot.ranye-iot.net:1883"地址中,第一个冒号前面的 tcp 表示我们使用的是 TCP 连接;后面的1883 表示 MQTT 服务器对应的端口号。
3、连接服务端
客户端创建之后,便可以连接服务器了,调用 MQTTClient_connect 函数连接:
handle:客户端句柄;
使用示例:
通常在定义 MQTTClient_connectOptions 对象时会使用 MQTTClient_connectOptions_initializer 宏对其进行初始化操作;而在定义 MQTTClient_willOptions 对象时使用 MQTTClient_willOptions_initializer 宏对其初
handle:客户端句柄;
参 数 topicName 表 示消息的主题名, topicLen 表示主题名的长 度;参数 message 指向一 个MQTTClient_message 对象,也就是客户端所接收到的消息。
dc:一个 MQTTClient_deliveryComplete 类型的函数指针,如下:
参 数 dt 表 示 MQTT 消 息 的 值 , 将 其 称 为 传 递 令 牌 。 发 布 消 息 时 ( 应 用 程 序 通 过MQTTClient_publishMessage 函数发布消息),MQTT 协议会返回给客户端应用程序一个传递令牌;应用程序可以通过将调用 MQTTClient_publishMessage()返回的传递令牌与传递给此回调的令牌进行匹配来检查消息是否已成功发布。
对于 msgarrvd 函数有两个点需要注意:
当 客 户 端 成 功 连 接 到 服 务 端 之 后 , 便 可 以 发 布 消 息 或 订 阅 主 题 了 , 应 用 程 序 通 过MQTTClient_publishMessage 库函数来发布一个消息:
handle:客户端句柄;
handle:客户端句柄;
当客户端想取消之前订阅的主题时,可调用 MQTTClient_unsubscribe 函数,如下所示:
7、断开服务端连接
handle:客户端句柄;
转载:https://www.cnblogs.com/gengtongyu/p/17219066.html