C#MQTT编程03--连接报文

news2025/2/27 10:22:35

1、报文回顾

MQTT协议中一共有14个报文,如下图

从上图看,我们要特别要注意以下3个点:

(1)值,14个报文的排列,不是随意的,每个报文都有自己的值,而值在报文中是要用到的。后面例子会介绍到。

(2)流向,C指客户端,S指服务器,比如CONNECT报文的流向是C->S,表示客户端向服务器发送报文,意思是客户端连接服务器,比如第2个CONNACK报文的流向是S->C,表示服务器向客户端发送的报文,意思是服务器确认连接,也就是连接成功啦。

(3)报文成员,MQTT的报文可以分成3个组成部分,分别是固定报头、可变报头以及负载。从上图可以看到,固定报头是必备成员,14个报文都必须包含固定报头。而可变报头和负载是非必备的,有的报文有,有的报文没有。

2、连接报文

1、报文介绍

本节来讲连接报文(CONNECT)。可以说他是所有报文的基础,“所有报文的基础”这句话的意思就是说不管你做什么操作,订阅也好,发布也好,都必须先连接,你说对不对,电话都没有接通还谈什么爱情谈什么生意?俗话说,要致富先通路。

所有的动作都必须在连接之上操作,MQTT是基于TCP/IP网络协议的,并且以字节流传输的。那这句话说明了2个意思:

1)MQTT通信时客户和服务器都必须有IP地址

2)通信是以字节流,在网络通信中IO流中按类型有字节流和字符流,字节流是以byte方式,并且是16进制的表现形式

Connect和Connack示意如下,其中CONNECT报文是客户端发送服务器,它比较复杂一点。可以说是所有报文中信息种类最多的。CONNACK报文是服务器发送客户机,最大特点就是没有有效载荷部分,如图:

 从前面的图片里面我们就知道如果客户端发送一个连接报文(CONNECT)之后,服务端就会返回一个连接确定报文(CONNACK)。如果客户端在一段时间之后,还没有接收到来自服务端的连接确定报文(CONNACK)的话,客户端一定要断开连接。同时要重起一个新的网络连接。在发一次连接报文(CONNECT)。并且客户端这边要保证连接报文只能发送一次,同时在服务端也要有验证来自客户端的连接报文只有一次。如果发送俩次以上的连接报文的话,不好意思请当作违反了协议断开当前连接。

2、CONNECT连接服务端报文

客户端发送给服务端的第一个报文必须是CONNECT报文。在一个网络连接上,客户端只能发送一次CONNECT报文。服务端必须将客户端发送的第二个CONNECT报文当作协议违规处理并断开客户端的连接 。此话意思就表明了连接报文只能发一次。报文结构如下

1、固定报头,占2个字节

第1个字节报文类型,固定值为1,从上面的14种报文类型看到是固定的1.

第2个字节剩余字节长度,注意这是指剩余字节的长度,意思是指从它开始到最后一共有多少个字节,包括自己在内。

2、可变报头,占10个字节

10个字节分别是:协议名称长度2+协议名称4+协议级别1+连接标志1+保持连接2=10

--1~6个字节为协议名长度和协议名

MQTT协议名是预先规定好的,这个后续不会变。

--第7个字节为协议级别

其实就是mqtt协议的修订版本。对于3.1.1版协议,协议级别字段的值是4(0x04)。

--第8个字节为连接标志

连接标志字节包含一些用于指定MQTT连接行为的参数。它还指出有效载荷中的字段是否存在。有效荷载里有啥全看这个字节的8位字符是0还是1了,这8个位的意义如下所述:

  |--第0位:服务端必须验证CONNECT控制报文的保留标志位(第0位)是否为0,如果不为0必须断开客户端连接。

  |--第1位:清理会话 Clean Session

  这个二进制位指定了会话状态的处理方式。客户端和服务端可以保存会话状态,以支持跨网络连接的可靠消息传输。这个标志位用于控制会话状态的生存时间。

  这个值是0:服务端可以根据报文里的客户端标识符,来找之前这个客户端有没有连过,连过的话就恢复之前的会话状态,没有的话就新建一个会话。就算是这个连接断开了,会话也要保存在服务端,针对这个客户端订阅的消息,会保存为会话的一部分,在这个客户端重新连接后,把这些        消息再推送给这个客户端。

  这个值是1:服务端丢弃之前所有的和这个客户端建立的会话,并开始一个新的会话,新的会话仅持续和网络连接同样长的时间。与这个会话关联的状态数据不能被任何之后的会话重用。为了确保在发生故障时状态的一致性,客户端应该使用会话状态标志1重复请求连接,直到连接成功。

  一般来说,客户端连接时总是将清理会话标志设置为0或1,并且不交替使用两种值。这个选择取决于具体的应用。清理会话标志设置为1的客户端不会收到旧的应用消息,而且在每次连接成功后都需要重新订阅任何相关的主题。清理会话标志设置为0的客户端会收到所有在它连接断开期间发布的QoS 1和QoS 2级别的消息。因此,要确保不丢失连接断开期间的消息,需要使用QoS 1或 QoS 2级别,同时将清理会话标志设置为0。清理会话标志0的客户端连接时,它请求服务端在连接断开后保留它的MQTT会话状态。如果打算在之后的某个时间点重连到这个服务端,客户端连接应该只使用清理会话标志0。当客户端决定之后不再使用这个会话时,应该将清理会话标志设置为1最后再连接一次,然后断开连接。

  |--第2位:遗嘱标志 Will Flag

  遗嘱比较有用,比如说你手机app订阅了你家扫地机器人的在线状态topic,这个在线状态扫地机器人可以通过遗嘱来实现,一旦它断开了与mqttbroker连接,mqttboker就可以发送机器人在连接时就设置好的遗嘱,通知手机机器人掉线了。

  如果被设置为1,表示如果连接请求被接受了,遗嘱(Will Message)消息必须被存储在服务端并且与这个网络连接关联。也就是确认使用遗嘱。之后网络连接关闭时,服务端必须发布这个遗嘱消息,除非服务端收到DISCONNECT报文时删除了这个遗嘱消息。如果决定启用遗嘱,那么连接标志中的Will QoS和Will Retain字段会被服务端用到,同时有效载荷中必须包含Will Topic和Will Message字段。因为你得组织服务端遗嘱的publish的报文。

  如果被设置成了0,连接标志中的Will QoS和Will Retain字段必须设置为0,并且有效载荷中不能包含Will Topic和Will Message字段。

  |--第3位、第4位:遗嘱QoS Will QoS

  没啥说的,遗嘱也是一个publish的消息,需要确定的消息等级。

  |--第5位:遗嘱保留 Will Retain

  如果遗嘱消息被发布时需要保留,需要指定这一位的值。

       |--第6位:用户名标志 User Name Flag

  这设置0,有效载荷就不能有了,设置1就必须有这个字段。

  |--第7位:密码标志 Password Flag

  同上

     --第9、10个字节:保持连接 Keep Alive

  保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个16位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个。保持连接的实际值是由应用指定的,一般是几分钟。允许的最大值是18小时12分15秒。

  3、有效载荷,占N个字节

        这个为什么是占N个字节,意思是指字节数是不确定的,因为连接时的用户名密码或客户端Id长度不同,那所占的字节数就不同啦,所以说是占X个字节。        

CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端id字符长度,客户端id字符,用户名字符长度,用户名字符,密码字符长度,密码字符。比如下列的一个软件界面 

用户名字符长度是5,用户名字符内容是admin。跟前面讲的协议名称长度和协议名称一样,意思是指两个东西,不要混乱了。

有个概念必须要了解--客户端标识符id,也就是客户端的唯一标识。服务端使用客户端标识符 (ClientId) 识别客户端。连接服务端的每个客户端都有唯一的客户端标识符(ClientId)。客户端和服务端都必须使用ClientId识别两者之间的MQTT会话相关的状态。

客户端标识符 (ClientId) 必须存在而且必须是CONNECT报文有效载荷的第一个字段 ,客户端标识符必须是1.5.3节定义的UTF-8编码字符串。

   

 

3、CONNACK确认连接报文

服务端发送CONNACK报文响应从客户端收到的CONNECT报文。服务端发送给客户端的第一个报文必须是CONNACK。如果客户端在合理的时间内没有收到服务端的CONNACK报文,客户端应该关闭网络连接。合理 的时间取决于应用的类型和通信基础设施。

1.固定报文头

固定头没啥可说的的,报文类型是2,占1个字节

2.可变报文头

 如图所示:

占两个字节:

--第一个字节是连接确认标志,8位里面就第0位有用,其他都是0不用管。

第0位标识的是当前会话,也就是服务端告诉客户端你在我这的session是我新启动的(值是0),还是原来就有的,我只是重用(值是1)

如果之前客户端发的连接报文,让服务端清理clientsession,那服务端的session肯定是新建的,那这个标志就是0,或者是之前客户端就没连过,那这个值也是0 。

如果连接报文没有让服务端清理clientsession,并且之前客户端连接过,服务器用的是原来的会话,那这个值就是1 。

--第二个字节是连接返回码

连接返回码字段使用一个字节的无符号值【见下表】。如果服务端收到一个合法的CONNECT报文,但出于某些原因无法处理它,服务端应该尝试发送一个包含非零返回码(表格中的某一个)的CONNACK报文。

如果服务端发送了一个包含非零返回码的CONNACK报文,那么它必须关闭网络连接 。

如果认为上表中的所有连接返回码都不太合适,那么服务端必须关闭网络连接,不需要发送CONNACK报文。

3.有效荷载

CONNACK报文没有有效载荷。

3、小结

这报文结构有点晕啊,不要慌,正常现象,遇到带刺的玫瑰,真香啊。

讲解不易,分析不易,原创不易,整理不易,伙伴们动动你的金手指,你的支持是我最大的动力。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【含完整代码】Java定时任务之xxl-job[超详细]

前言 个人博客:www.wdcdbd.com 在Java中使用定时任务是一件很常见的事情,比如使用定时任务在什么时间,什么时候,去发布一些信息,或者去查询一些日志等相关的代码。这时,我们就要开发定时任务这中功能来实现…

理解TCP/IP协议

一、协议 在计算机网络与信息通讯领域里,人们经常提及 “协议” 一词。互联网中常用的协议有HTTP、TCP、IP等。 协议的必要性 简单来说,协议就是计算机与计算机之间通过网络通信时,事先达成的一种 “约定”。这种“约定”使不同厂商的设备…

精通业务:资深程序员的核心优势

在IT行业,我们常常听到关于技术实力、项目经验、团队协作等方面的讨论,但有一个重要因素常常被忽视,那就是对业务的了解。 对于资深程序员来说,懂业务和不懂业务之间的区别,犹如一道深邃的鸿沟,决定着他们…

【MySQL】:探秘主流关系型数据库管理系统及SQL语言

🎥 屿小夏 : 个人主页 🔥个人专栏 : MySQL从入门到进阶 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一. MySQL概述1.1 数据库相关概念1.2 主流数据库1.3 数据模型1.3.1 关系型数据库…

QT DAY5作业

1.QT基于TCP服务器端 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QMessageBox> //消息对话框类 #include <QTcpSocket> //客户端类 #include <QList> //链表容器类namespace …

unity C#什么时候用“可空类型”

文章目录 例子1. **声明一个可空类型变量&#xff1a;**2. **给可空类型变量赋值&#xff1a;**3. **检查可空类型变量是否有值&#xff1a;**4. **转换与比较&#xff1a;**5. **使用null合并运算符&#xff1a;** 可空类型的重要意义1. **表示缺失或未知的值&#xff1a;**2.…

基于51单片机的智能热水器设计

需要全部文件请私信关注我&#xff01;&#xff01;&#xff01; 基于51单片机的智能热水器设计 摘要一、绪论1.1 选题背景及意义1.2 完成目标与功能设计 二、硬件系统设计2.1 硬件完成要求2.2 方案选择2.3 电源电路设计2.4 键盘电路2.5 蜂鸣器报警电路2.6 温度检测电路2.7 红…

LeetCode刷题--- 删除并获得点数

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 ​​​​​​http://t.csdnimg.cn/6AbpV 数据结构与算法 ​​​http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述动…

AAAI 2024|ETH轻量化Transformer最新研究,浅层MLP完全替换注意力模块提升性能

论文题目&#xff1a; Rethinking Attention: Exploring Shallow Feed-Forward Neural Networks as an Alternative to Attention Layers in Transformers 论文链接&#xff1a; https://arxiv.org/abs/2311.10642 代码仓库&#xff1a; GitHub - vulus98/Rethinking-attention…

【Redis】非关系型数据库之Redis的增删改查

目录 一、Redis的数据类型分类 二、Redis的字符串类型string 三、Redis的列表list 四、Redis的哈希hash 五、Redis的无序集合set 六、Redis的有序集合zset 七、Redis的通用命令 一、Redis的数据类型分类 通常Redis的数据类型有五大基础类型 String&#xff08;字符串&am…

解决Unexpected record signature 0X9maven 资源过滤

解决Unexpected record signature: 0X9|maven 资源过滤 记录问题&#xff1a;我们有个需求是根据excel模版导出一个excel表。我们的项目是SpringBoot&#xff0c;所以理所当然的把这个模版文件放到了&#xff0c;resources文件夹中。但是在导出文件的时候却遇到了invalid code …

关于tex中的表格设置

文章目录 控制表格列宽和行高控制表格列宽的同时实现居中tex中多表格排列单元格的合并与分割对单个单元格进行操作 控制表格列宽和行高 将下面的代码放在table环境内&#xff0c;放在tabular环境外 调整表格宽度和高度&#xff1a; \resizebox{\textwidth}{2cm}{%第一个{}是表…

Linux之静态库和动态库

目录 一、前言 二、对于库的理解 三、静态库 四、动态库 五、动静态库的加载 一、前言 在之前&#xff0c;我们讲了静态库和动态库&#xff0c;详情请跳转&#xff1a;静态库和动态库 下面我们将从工程师的角度&#xff0c;去了解静态库和动态库的形成过程&#xff0c;以…

EndNote快速上手

前言&#xff1a;用EndNote主要就是为了方便管理文章引用的文献&#xff0c;所以本篇就是针对EndNote在文章中引用文献需要的技巧&#xff0c;然后本文用的是EndNoteX9。 EndNote快速上手 创建文献资料库创建文献分组导入文献手动输入文件导入在线搜索 修改文献信息去重文献删除…

火出圈的ChatGPT,在地学、地球科学领域的强大应用

以ChatGPT、LLaMA、Gemini、DALLE、Midjourney、Stable Diffusion、星火大模型、文心一言、千问为代表AI大语言模型带来了新一波人工智能浪潮&#xff0c;可以面向科研选题、思维导图、数据清洗、统计分析、高级编程、代码调试、算法学习、论文检索、写作、翻译、润色、文献辅助…

一篇文章带你了解Redis的发展史

Redis 是一个开源的内存数据存储和处理系统&#xff0c;它在过去的几十年中经历了重大的发展和演进。以下是 Redis 的发展历程概述&#xff1a; 早期阶段&#xff08;2000年代初至中期&#xff09;&#xff1a;在这个时期&#xff0c;网站的访问量通常较低&#xff0c;单个数据…

在Colab上测试Mamba

我们在前面的文章介绍了研究人员推出了一种挑战Transformer的新架构Mamba 他们的研究表明&#xff0c;Mamba是一种状态空间模型(SSM)&#xff0c;在不同的模式(如语言、音频和时间序列)中表现出卓越的性能。为了说明这一点&#xff0c;研究人员使用Mamba-3B模型进行了语言建模…

MyBatis第二课,灰度发布,@Results注解,使用xml书写mysql

目录 打印MyBatis的日志配置&#xff1a; 灰度发布:指发布环境&#xff0c;比如发布环境有200台机器&#xff0c;发布的时候是一批一批的机器的发布 2.删除与修改 使用Results注解&#xff0c;这样就和上面的别名一个意思&#xff0c;column是数据库的列 自动转驼峰&#…

ubuntu的动图截屏怎么做

在Ubuntu系统中&#xff0c;你可以通过以下步骤来截取动图&#xff08;即屏幕录制并转换为GIF格式&#xff09;&#xff1a; 1,首先&#xff0c;你需要安装一些必要的工具。打开终端并输入以下命令以安装gtk-recordmydesktop&#xff08;用于录制屏幕&#xff09;、mplayer&am…

【快速解决】保姆级Anaconda安装教程

目录 第一步 ​编辑第二步 ​编辑第三步 第四步 第五步 第六步 ​编辑 第七步 第八步 第九步 第一步 在anaconda清华大学开源软件镜像站下载anaconda。点击这里进入 我这里选的是windows-x86_64。 第二步 下载好以后进行安装 第三步 第四步 第五步 选择…