Linux--MQTT(二)通信基本原理

一、MQTT 通信基本原理

MQTT 是一种基于 客户端 - 服务端 架构的消息传输协议,所以在 MQTT 协议通信中,有两个最为重要的角色,它们便是服务端 客户端
举例:若开发板向“芯片温度”这一主题发布消息,那么服务端接收到消息后会将消息转发给订阅了“芯片温度”的所有客户端。

服务端

MQTT 服务端通常是一台服务器( broker ),它是 MQTT 信息传输的枢纽,负责将 MQTT 客户端发送来的信息传递给 MQTT 客户端; MQTT 服务端还负责管理 MQTT 客户端,以确保客户端之间的通讯顺畅, 保证 MQTT 信息得以正确接收和准确投递。

客户端

MQTT 客户端可以向服务端发布信息,也可以从服务端收取信息;我们把客户端发送信息的行为称为 “发布”信息。而客户端要想从服务端收取信息,则首先要向服务端“订阅”信息。“订阅”信息这一操作很像我们在使用微信时“关注”了某个公众号,当公众号的作者发布新的文章时,微信官方会向关注了该公众号的所有用户发送信息,告诉他们有新文章更新了,以便用户查看。

MQTT 主题

客户端想要从服务器获取信息,首先需要订阅信息,那客户端如何订阅信息呢?这里我们要引入“主题(Topic )”的概念,“主题”在 MQTT 通信中是一个非常重要的概念,客户端发布信息以及订阅信息都是围绕“主题”来进行的,并且 MQTT 服务端在管理 MQTT 信息时,也是使用“主题”来控制的。
客户端发布消息时需要为消息指定一个“主题”,表示将消息发布到该主题;而对于订阅消息的客户端来说,可通过订阅“主题”来订阅消息,这样当其它客户端或自己(当前客户端)向该主题发布消息时,MQTT 服务端就会将该主题的信息发送给该主题的订阅者(客户端)。
值得注意的是, MQTT 客户端在通信时,角色往往不是单一的,一个客户端既可以作为信息发布者也可以同时作为信息订阅者。如下图所示:

MQTT 发布/订阅特性

MQTT 通信的核心枢纽是 MQTT 服务端,它负责将 MQTT 客户端发送来的 信息传递给 MQTT 客户端,还负责管理 MQTT 客户端,以确保客户端之间的通讯顺畅,保证 MQTT 信息得以正确接收和准确投递。
客户端相互独立: MQTT 客户端是一个个独立的个体,它们无需了解彼此的存在,依然可以实现 信息交流。
时间上可异步: MQTT 客户端在发送和接收信息时无需同步。这一特点对物联网设备尤为重要, 前面我们也介绍了,MQTT 从诞生之初就是专为低带宽、高延迟或不可靠的网络而设计的,高延 迟和不可靠网络必然就会导致时间上的异步;物联网设备在运行过程中发生意外掉线是非常正常 的情况,我们使用上面的实例二的场景来作说明,当开发板在运行过程中,可能会由于突然断电 (假设开发板是通过电源适配器供电的)导致掉线,这时开发板会断开与 MQTT 服务端的连接。 假设此时我们的手机客户端向开发板客户端所订阅的“LED 控制”主题发布了信息,而开发板恰 恰不在线,这时,MQTT 服务端可以将“ LED 控制”主题的新信息保存,待开发板客户端再次上线后,服务端再将“LED 控制”信息推送给开发板。所以这就必然导致了,手机发送信息与开发板接收信息在时间上是异步的。

二、连接MQTT服务端

MQTT 客户端之间想要实现通信,必须要通过 MQTT 服务端。所以,客户端无论是发布信息还是订阅信息都必须先连接到服务端。下面我们来看一下,客户端连接服务端的详细过程。

MQTT 客户端连接服务端总共包含了两个步骤:

①、首先客户端需要向服务端发送连接请求,这个连接请求实际上就是向服务端发送一个 CONNECT报文,也就是发送了一个 CONNECT 数据包。
②、 MQTT 服务端收到连接请求后,会向客户端发送连接确认。连接确认实际上是向客户端发送一个CONNACK 报文,也就是 CONNACK 数据包。

CONNECT 报文

在上面的描述中我们看到, MQTT 客户端要想连接服务端,首先要向服务端发送 CONNECT 报文。如 果此 CONNECT 报文的格式或内容不符合 MQTT 规范,则服务器会拒绝客户端的连接请求。
一个CONNECK报文内容举例如下:
所谓报文就是一个数据包, MQTT 报文组成分为三个部分:固定头( Fixed header )、可变头( Variable header)以及有效载荷( Payload ,消息体)。这里我们简单地介绍一下:
固定头( Fixed header ): 存在于所有 MQTT 报文中,固定头中有报文类型标识,可用于识别是哪 种 MQTT 报文,譬如该报文是 CONNECT 报文还是 CONNACK 报文,亦或是其它类型报文。
可变头( Variable header ): 存在于部分类型的 MQTT 报文中,报文的类型决定了可变头是否存 在及其具体的内容。
消息体( Payload ): 存在于部分类型的 MQTT 报文中, payload 就是消息载体的意思。
在上图中的报文内容有:
clientId-- 客户端 id
clientId MQTT 客户端的标识,也就是 MQTT 客户端的名字, MQTT 服务端可通过 clientId 来区分不同的客户端,MQTT 服务端用该标识来识别客户端。
keepAlive-- 心跳时间间隔
keepAlive 其实是指定了心跳时间间隔,也就是客户端向服务端发送心跳包的时间间隔。譬如 keepAlive=60 ,表示告诉服务端,客户端将会每隔 60 秒左右向服务端发送心跳包。
cleanSession-- 清除会话
cleanSession 设置为 1 ,表示此次连接将创建一个新的临时会话,在客户端断开后,这个会话会自动销毁。而 cleanSession 设置为 0 ,表示创建一个持久性会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销。

CONNACK 报文

                  

returnCode-- 连接返回码
当服务端收到了客户端的连接请求后,会向客户端发送 returnCode( 连接返回码 ) ,用来说明连接情况。 如果客户端与服务端成功连接,则返回数字“0 ”。如果未能成功连接,返回码将会是一个非零的数字。
sessionPresent
CONNACK 报文的 sessionPresent CONNECT 报文的 cleanSession 相互配合。其作用是客户端发送连接请求时,服务端告知客户端有没有保存会话状态。这个被服务端保存的会话状态是来自于上一 次客户端连接时,譬如离线消息以及上一次连接时客户端所订阅的主题。

三、断开连接

MQTT 客户端连接到服务端之后,在后续的通信过程中,如果客户端想要断开与服务端的连接,此 时客户端可以主动向服务端发送一个 DISCONNECT 报文来断开与服务端的连接,如下图所示:

四、发布消息、订阅主题与取消订阅主题

当客户端连接到服务端之后,便可以发布消息或订阅主题了。

PUBLISH–发布消息

当客户端连接到服务端之后,就可以向服务端发布消息了,每条发布的消息必须指定一个“主题”,表示向某主题发布消息;MQTT 服务端可以通过主题来确定将消息转发给哪些客户端(订阅了该主题的客户端)。
MQTT 客户端向服务端发布消息其实就是向服务端发送一个 PUBLISH 报文,服务端收到客户端发送过来的 PUBLISH 报文之后,会向发送方回复一个报文。根据 QoS 的不同,回复的报文类型也是不同的,并且 整个发布消息的过程也将会有所区别;譬如对于 QoS=1 时,客户端向服务端发送 PUBLISH 报文,服务端 收到 PUBLISH 报文之后会向发送方回复 PUBACK 报文;而对于 QoS=2 的情况,将会更加复杂。
下图是 PUBLISH 报文包含的信息:
packetId-- 报文标识符
报文标识符可用于对 MQTT 报文进行标识(识别不同的报文)。不同的 MQTT 报文所拥有的标识符不同。MQTT 设备可以通过该标识符对 MQTT 报文进行甄别和管理, MQTT 协议内部使用的标识符。请注意:
报文标识符的内容与 QoS 级别有密不可分的关系。只有 QoS 级别大于 0 时,报文标识符才是非零数值。如果 QoS 等于 0 ,报文标识符为 0
topicName-- 主题名字
这个就是发布消息时对应的主题的名字,这是一个字符串,譬如上图中 topicName= myTopic ”,表示会将消息发布到“myTopic ”这个主题。
payload-- 有效载荷
有效载荷是我们希望通过 MQTT 所发送的实际内容。我们可以使用 MQTT 协议发送字符串文本,图像等格式的内容。这些内容都是通过有效载荷所发送的。
qos-- 服务质量等级
QoS Quality of Service )表示 MQTT 消息的服务质量等级。 QoS 有三个级别: 0 1 2 QoS 决定 MQTT 通信有什么样的服务保证。
retain-- 保留标志
在默认情况下,当客户端订阅了某一主题后,并不会马上接收到该主题的信息。因为客户端订阅该主题 之后,并没有其它客户端向该主题发布消息;只有在客户端订阅该主题后,服务端接收到该主题的新消息时,服务端才会将最新接收到的该主题消息推送给客户端。
但是在有些情况下,我们需要客户端在订阅了某一主题后马上接收到一条该主题的信息。这时候就需要用到保留标志这一信息。
dup-- 重发标志
dup 标志指示此消息是否重复。
MQTT 报文的接收方没有及时向报文发送发回复 确认收到报文 时,发送方会以为对方没有收到信息,会再次重复发送 MQTT 报文(譬如客户端向服务端发送 PUBLISH 报文,服务端收到 PUBLISH 报文之后需要向客户端回复一个 PUBACK 报文,如果客户端没收到 PUBACK 报文,则会认为服务端可能没接收到自己发送的报文,将会再次发送 PUBLISH 报文)。在重复发送 MQTT 报文时,发送方会将此“dup--重发标志”设置为 true 请注意,重发标志只在 QoS 级别大于 0 时使用。

SUBSCRIBE--订阅主题

客户端要想接收消息,首先要订阅该消息的主题。这样,当有客户端向该主题发布消息后,订阅了该主题的客户端就能接收到消息了。
客户端要想订阅主题,首先要向服务端发送主题订阅请求。客户端是通过向服务端发送 SUBSCRIBE 报文来实现这一请求的。该报文包含有一系列“订阅主题名”。请留意,一个 SUBSCRIBE 报文可以包含有单个或者多个订阅主题名。也就是说,一个 SUBSCRIBE 报文可以用于订阅一个或者多个主题。服务端会根据 SUBSCRIBE 中的 QoS 来提供相应的服务保证。
SUBACK 报文包含有“订阅返回码”和“报文标识符”这两个信息。
returnCode-- 订阅返回码
客户端向服务端发送订阅请求后,服务端会给客户端返回一个订阅返回码。在之前的讲解中我们说过,客户端可通过一个 SUBSCRIBE 报文发送多个主题的订阅请求。服务端会针对 SUBSCRIBE 报文中的所有订阅主题来逐一回复给客户端一个返回码。这个返回码的作用是告知客户端是否成功订阅了主题。

UNSUBSCRIBE--取消订阅主题

客户端订阅了某一主题之后,可以随时取消订阅, MQTT 协议提供了这样的操作。
客户端通过向服务端发送一个 UNSUBSCRIBE 报文来取消订阅主题,当服务端接收到 UNSUBSCRIBE报文后,会向发送发回复一个 UNSUBACK 报文(取消订阅确认报文),如下图所示:

五、主题的进阶

主题的基本形式就是一个字符串,譬如: "myTopic" "currentTemp" "LEDControl"等,但是有几个点需要大家注意一下:

1、主题形式

主题是区分大小写的。 所以 "LEDControl" "ledControl" 是两个不同的主题。
主题可以使用空格。 譬如 "LED Control" ,虽然主题允许使用空格,但是笔者建议大家尽量不要使用空格。
不要使用中文主题。 虽然有些 MQTT 服务器支持中文主题,但是绝大部分 MQTT 服务器是不支持中文主题的,所以大家不要使用中文主题,而是使用 ASCII 字符来作为 MQTT 主题。

2、主题分级

MQTT 主题可以是一个简单的字符串,譬如: "myTopic" "currentTemp" "LEDControl" ,事实上, MQTT协议为了更好的对主题进行管理和分类,支持主题分级,对主题进行分级处理,各个级别之间使用" / " 符号进行分隔。如下所示:
"home/sensor/led/brightness"
在以上示例中一共有四级主题,分别是第 1 home 、第 2 sensor 、第三级 led 、第 4 brightness 。 主题的每一级至少需要一个字符;而只有一个简单字符串的主题,如"myTopic" "currentTemp"、 "LEDControl",这些都是单一级别的主题。需要注意的是,主题名称不要使用 " / " 开头。

3、主题通配符

当客户端订阅主题时,可以使用通配符同时订阅多个主题。通配符只能在订阅主题时使用,分为单级通配符和多级通配符。

4、主题应用注意事项

$ 开头的主题
$ 号开头的主题是 MQTT 服务端系统保留的特殊主题,客户端不可随意订阅或向其发布信息
不要使用“ / ”作为主题开头
尽量不要使用“ / ”作为主题的开头,这样做没有什么意义,而且额外产生一个没有用处的主题级别。
主题中不要使用空格
虽然, MQTT 支持在主题中使用空格,但是我们应该尽量避免使用空格。
保持主题简洁明了
MQTT 是一种轻量级的通讯协议,它常用于网络带宽受限的环境,因此我们应尽量让主题简洁明了,从而让设备间交互的内容更加简洁,以更好的适应网络带宽受限的环境。
主题中尽量使用 ASCII 字符
虽然有些 MQTT 设备支持 UTF-8 字符作为 MQTT 主题,建议在主题中尽量使用 ASCII 字符。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/350869.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode --- 401周赛

题目列表 3178. 找出 K 秒后拿着球的孩子 3179. K 秒后第 N 个元素的值 3180. 执行操作可获得的最大总奖励 I 3181. 执行操作可获得的最大总奖励 II 一、找出K秒后拿着球的孩子 这题可以直接模拟,从前往后,再从后往前走k次,最后直接返回…

第〇篇:深入Docker的世界系列博客介绍

深入Docker的世界系列博客介绍 欢迎来到“深入Docker的世界”系列博客,这是一次旨在全面探索Docker容器化技术的冒险之旅。从基础原理到高级应用,再到实践案例分析,我们将深入挖掘Docker的每一个角落,帮助你不仅掌握这项技术的实…

ecshop鲜花商城微信分销源码附移动端

ecshop 微信手机分销商城 微信支付微信通,PHP鲜花礼品商城源码带手机wap ecshop鲜花商城微信分销源码附移动端

C语言小例程20/100

题目&#xff1a;一个数如果恰好等于它的因子之和&#xff0c;这个数就称为"完数"。例如61&#xff0b;2&#xff0b;3.编程找出1000以内的所有完数。 #include<stdio.h> #define N 1000 int main() {int i,j,k,n,sum;int a[256];for(i2;i<N;i){suma[0]1;k…

LabVIEW在高校中的应用

LabVIEW 作为一款功能强大的图形化编程工具&#xff0c;在高校中有广泛的应用。它不仅用于教学实验&#xff0c;还广泛应用于科研项目和工程训练。本文将从教学、科研、实验室管理和学生技能培养等多个角度&#xff0c;详细分析LabVIEW在高校中的应用。 教学应用 课程设计 自动…

Flutter调用本地web

前言: 在目前Flutter 环境中&#xff0c;使用在线 webview 是一种很常见的行为 而在 app 环境中&#xff0c;离线使用则更有必要 1.环境准备 将依赖导入 2.引入前端代码 前端代码有两种情况 一种是使用打包工具 build 而来的前端代码 另一种情况是直接使用 HTML 文件 …

深入探讨限流算法:固定窗口、滑动窗口、漏桶与令牌桶原理及应用场景

固定窗口算法 简单粗暴&#xff0c;但有临界问题&#xff1a; 滑动窗口算法 滑动窗口通俗来讲是一种流量控制技术&#xff0c;描述接收方TCP数据报缓冲区大小的数据。发送方根据这个数据计算最大可发送的数据量。滑动窗口协议是TCP使用的一种流量控制方法&#xff0c;允许发送…

【Linux硬盘数据读取】WIN10访问linux分区解决方案:ext2fsd

<div id"content_views" class"htmledit_views" style"user-select: auto;"><p>尝试ext2explore、Paragon ExtFS都不好用&#xff0c;强烈安利ext2fsd&#xff0c;可读写&#xff0c;很强大</p> 转自&#xff1a;https://blog…

设计通用灵活的LabVIEW自动测试系统

为了在不同客户案例中灵活使用不同设备&#xff08;如采集卡、Modbus模块&#xff09;且保持功能一致的LabVIEW自动测试系统&#xff0c;需要采用模块化的软件架构、配置文件管理、标准化接口和良好的升级维护策略。本文从软件架构、模块化设计、配置管理、升级维护、代码管理和…

sigmoid函数

σ ( x ) 1 1 e − x \sigma(x)\frac1{1e^{-x}} σ(x)1e−x1​ sigmoid函数好处 1. σ ( x ) \sigma(x) σ(x)的域值是[0,1] &#xff0c;在(-∞, ∞)单调递增&#xff0c;很符合概率分布函数的特点 2.以 σ ( x ) \sigma(x) σ(x)为分布函数的概率密度函数在远离零点的位置…

springSecurity学习笔记(一)

简介 Spring Security是一个Java框架&#xff0c;用于保护应用程序的安全性。它提供了一套全面的安全解决方案&#xff0c;包括身份验证、授权、防止攻击等功能。Spring Security基于过滤器链的概念&#xff0c;可以轻松地集成到任何基于Spring的应用程序中。它支持多种身份验…

hugo-magic主题使用教程(一)

前提条件 以下教程以windows10为例操作终端使用git bash魔法上网的前提下 下载hugo https://github.com/gohugoio/hugo/releases/download/v0.127.0/hugo_extended_0.127.0_windows-amd64.zip解压到任意目录,然后将目录添加到系统环境变量 如图 (windows)打开cmd 输入 hugo …

[数据集][目标检测]胸部解剖检测数据集VOC+YOLO格式100张10类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;100 标注数量(xml文件个数)&#xff1a;100 标注数量(txt文件个数)&#xff1a;100 标注类别…

宿舍用电管理模块一进三出的升级改造

宿舍用电管理模块一进三出石家庄光大远通电气有限公司产品在高校日常管理工作中,宿舍管理是一项重要工作。宿舍管理内容复杂,而且涉及学生的日常生活,意义重大。其中,学生宿舍内漏电,超负荷用电,违规用电等现象一直是困扰后勤管理的普遍问题。随着学生日常生活方式以及生活用品…

第九届星华杯网络邀请赛

T1喵星人的身高 T2犇犇碑 T3嘤嘤词典 T4三角区间和

微服务feign组件学习

手写不易&#xff0c;对您有帮助。麻烦一键三连。也欢饮各位大料指正&#xff0c;交流。 微服务feign组件学习 1.概念1.1 feign 概念1.2 Ribbon概念 2.使用2.1 集成feign2.1.1 maven依赖2.1.2 项目结构 2.2 使用2.2.1 定义feign接口2.2.2 消费端服务调用2.2.3 消费端扫描feig…

Ubuntu 22.04 解决 firefox 中文界面乱码

问题复现 在为Ubuntu 22.04 Server安装完整的GNOME 42.01桌面后&#xff0c;将桌面语言设置为中文时&#xff0c;打开Firefox可能会出现中文乱码的问题。经过网上调查发现&#xff0c;这个问题是由Snap软件包引起的。 解决方案 为了避免在Ubuntu 22.04中文模式下的乱码问题…

Redis系列-4 Redis集群介绍

Redis集群 Redis提供了持久化能力&#xff0c;保证了重启不会丢失数据&#xff1b;但Redis重启至完全恢复期间&#xff0c;缓存不可用。另外&#xff0c;对于高并发场景下&#xff0c;单点Redis服务器的性能不能满足吞吐量要求&#xff0c;需要进行横向扩展。此时&#xff0c;…

mmdeploy环境部署流程

参考&#xff1a;mmdeploy/docs/zh_cn/01-how-to-build/linux-x86_64.md at main open-mmlab/mmdeploy (github.com) 从零入门《openmmlab》mmdeploy[1]环境安装及简单上手_哔哩哔哩_bilibili 我的环境&#xff1a; docker容器&#xff0c;ubuntu20.04&#xff0c;cuda11.7…

注解(Annotation)(一)

Java 注解&#xff08; Annotation &#xff09;又称 Java 标注&#xff0c;是 JDK5.0 引入的一种注释机制。 Java 语言中的类、 构造器、 方法、成员变量、参数等都可以被注解进行标注。 自定义注解 --- 格式 自定义注解就是自己做一个注解来使用。 public interface …