转载MQTT
转载地址:https://www.cnblogs.com/wdg-blog/p/12532836.html
1. 概述
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(Publish/Subscribe)模式的轻量级通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布,目前最新版本为v3.1.1。MQTT最大的优点在于可以以极少的代码和有限的带宽,为远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,MQTT在物联网、小型设备、移动应用等方面有广泛的应用。众所周知,TCP/IP参考模型可以分为四层:应用层、传输层、网络层、链路层。TCP和UDP位于传输层,应用层常见的协议有HTTP、FTP、SSH等。MQTT协议运行于TCP之上,属于应用层协议,因此只要是支持TCP/IP协议栈的地方,都可以使用MQTT。
2. MQTT客户端
一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:
(1)发布其他客户端可能会订阅的信息; //发布消息
(2)订阅其它客户端发布的消息; //订阅消息
(3)退订或删除应用程序的消息; //退订消息
(4)断开与服务器连接。 //断开,连接服务器
3. MQTT服务器
MQTT服务器以称为“消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:
(1)接受来自客户的网络连接; //接受客户端连接
(2)接受客户发布的应用信息; //接收客户端发布的消息
(3)处理来自客户端的订阅和退订请求; //处理消息的订阅及退订
(4)向订阅的客户转发应用程序消息。 //推送消息
4. MQTT消息格式
每条MQTT命令消息的消息头都包含一个固定的报头,有些消息会携带一个可变报文头和一个负荷。消息格式如下:
固定报文头 | 可变报文头 | 负荷
4.1 固定报文头(Fixed Header)
MQTT固定报文头最少有两个字节,第一字节包含消息类型(Message Type)和QoS级别等标志位。第二字节开始是剩余长度字段,该长度是后面的可变报文头加消息负载的总长度,不包括用于编码剩余长度字段本身的字节数,该字段最多允许四个字节。
剩余长度字段单个字节最大值为二进制0b0111 1111,16进制0x7F。也就是说,单个字节可以描述的最大长度是127字节。为什么不是256字节呢?因为MQTT协议规定,单个字节第八位(最高位)若为1,则表示后续还有字节存在,第八位起“延续位”的作用。
例如,数字64,编码为一个字节,十进制表示为64,十六进制表示为0×40。数字321(65+2*128)编码为两个字节,重要性最低的放在前面,第一个字节为65+128=193(0xC1),第二个字节是2(0x02),表示2×128。
由于MQTT协议最多只允许使用四个字节表示剩余长度(如表1),并且最后一字节最大值只能是0x7F不能是0xFF,所以能发送的最大消息长度是256MB,而不是512MB。
4.2 可变报文头(Variable Header)
可变报文头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等,后面会针对主要部分进行讲解。
4.2.1 消息质量(QoS)
MQTT消息质量有三个等级,QoS 0,QoS 1和 QoS 2。
QoS 0:最多分发一次。消息的传递完全依赖底层的TCP/IP网络,协议里没有定义应答和重试,消息要么只会到达服务端一次,要么根本没有到达。
QoS 1:至少分发一次。服务器的消息接收由PUBACK消息进行确认,如果通信链路或发送设备异常,或者指定时间内没有收到确认消息,发送端会重发这条在消息头中设置了DUP位的消息。
QoS 2:只分发一次。这是最高级别的消息传递,消息丢失和重复都是不可接受的,使用这个服务质量等级会有额外的开销。
4.2.2 遗愿标志(Will Flag)
在可变报文头的连接标志位字段(Connect Flags)里有三个Will标志位:Will Flag、Will QoS和Will Retain Flag,这些Will字段用于监控客户端与服务器之间的连接状况。如果设置了Will Flag,就必须设置Will QoS和Will Retain标志位,消息主体中也必须有Will Topic和Will Message字段。
那遗愿消息是怎么回事呢?服务器与客户端通信时,当遇到异常或客户端心跳超时的情况,MQTT服务器会替客户端发布一个Will消息。当然如果服务器收到来自客户端的DISCONNECT消息,则不会触发Will消息的发送。
因此,Will字段可以应用于设备掉线后需要通知用户的场景。
4.2.3 连接保活心跳机制(Keep Alive Timer)
MQTT客户端可以设置一个心跳间隔时间(Keep Alive Timer),表示在每个心跳间隔时间内发送一条消息。如果在这个时间周期内,没有业务数据相关的消息,客户端会发一个PINGREQ消息,相应的,服务器会返回一个PINGRESP消息进行确认。如果服务器在一个半(1.5)心跳间隔时间周期内没有收到来自客户端的消息,就会断开与客户端的连接。心跳间隔时间最大值大约可以设置为18个小时,0值意味着客户端不断开
4.3 有效负荷(Payload)
Payload直译为负荷,可能让人摸不着头脑,实际上可以理解为消息主体(body)。
当MQTT发送的消息类型是CONNECT(连接)、PUBLISH(发布)、SUBSCRIBE(订阅)、SUBACK(订阅确认)、UNSUBSCRIBE(取消订阅)时,则会带有负荷。
(1)CONNECT,消息体内容主要是:客户端的ClientID、订阅的Topic、Message以及用户名和密码。
(2)SUBSCRIBE,消息体内容是一系列的要订阅的主题以及QoS。
(3)SUBACK,消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。
(4)UNSUBSCRIBE,消息体内容是要订阅的主题。
(5)PUBLISH,消息体内容是相关主题的数据。
5. MQTT控制报文
介绍MQTT协议的报文组成并通过wireshark抓取报文包分析报文内容
5.1 连接服务端(CONNECT)
Connect报文在MQTT客户端连接服务器时发出,报文由三部分组成,下面将分别介绍
5.1.1 固定报头(fixed header)
Connect名称的值为1,低四位保留,剩余长度保存可变报头(10字节)加上有效载荷的长度。
5.1.2 可变报头(variable header)
Connect报文的可变报头包含协议名,协议等级,连接标志和保持连接
报文协议名之前有两个字节的报文标识符,唯一标识这条报文。
连接标志包含用户名标志(username flag)、密码标志(password flag)、遗嘱标志(will flag)、遗嘱服务指令(will Qos)、遗嘱保留标志(will retain)、清除会话标志(clean session)、保留位(reserved)。
用户名标志(username flag):若用户名标志被置为1,有效载荷中必须包含用户名字段。
密码标志(password flag):若密码标志被置为1,有效载荷中必须包含密码字段,当用户标志被置为0时,密码标志必须被置0.。
遗嘱标志(will flag):若遗嘱标志被置1,遗嘱服务指令(will Qos)与遗嘱保留标志(will retain)会被服务器用到,遗嘱消息中必须包含will topic和will message。
遗嘱服务指令(will Qos):如果遗嘱标志被设置为0,遗嘱QoS也必须设置为0(0x00),如果遗嘱标志被设置为1,遗嘱QoS的值可以等于0(0x00),1(0x01),2(0x02)。它的值不能等 于3。
遗嘱保留标志(will retain):若遗嘱保留标志位被置位,服务器将保留遗嘱消息(保留发布),当客户端异常断开连接时将遗嘱发给订阅遗嘱主题的客户。
清除会话标志(clean session):标志被设置为1,客户端和服务端必须丢弃之前的任何会话并开始一个新的会话(之前的订阅与发布消息被删除),若标志为0,恢复与服务器会话连接,若没有连接 新建一个会话连接(不删除之前与客户端的会话信息并保存断开本次会话之后的Qos1与Qos2消息)。
保留位(reserved):如果不为0必须断开客 户端连接。
报文最后两字节为发送心跳包的间隔时间,当客户端没有数据发给服务器时,须发送心跳包(pingreq)到服务器,保证连接不断开。
5.1.3 有效载荷(Payload)
CONNECT报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的 标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码。
客户端标识符(client identifier):服务器通过识别客户标识符,确定客户端,识别两者间的MQTT会话相关状态,服务器允许客户端提供一个零字节的标识符,但clean session必须置1。
5.2连接请求确认(CONNACK)
Connack为服务器确认客户端连上服务给出的回应。
5.2.1 固定报头(fixed header)
5.2.2 可变报头(variable header)
- 第一字节1~7位保留,第0位是当前会话标志(session present),若清除会话标志被置1,该位为0,若清除会话标志为0且服务器没有与客户端会话保存,该位置0,有保存置1
第二字节保存连接返回码,若连接成功返回0。
5.3发布消息(PUBLISH)
发布消息可由客户端或服务器发出,被消息订阅者接收。
5.3.1 固定报头(fixed header)
固定报头第一字节的低四位分别保存重发标志(DUP),服务质量(Qos),保留标志(RETAIN)。
重发标志(DUP):当该位被置1,表示该条报文为重发报文,客户端或服务端请求重发一个PUBLISH报文时,必须将DUP标志设置为1。对于QoS 0的消息,DUP标志必须设置为0。
服务质量(Qos):表示发送质量,取值有00 01 10。
保留标志(RETAIN):若该位被置1,表示服务器必须保存其应用消息和质量等级,若为0,表示该消息不须保存,如果服务端收到一条保留(RETAIN)标志为1的QoS 0消息,它必须丢弃之前为那个主题保留的任何消息。它应该将这个新的QoS0消息当作那个主题的新保留消息,但是任何时候都可以选择丢弃它,保留标志为1且有效载荷为零字节的PUBLISH报文会被服务端当作正常消息处理,它会被发送给订阅主题匹配的客户端。此外,同一个主题下任何现存的保留消息必须被移除,因此这个主题之后的任何订阅者都不会收到一个保留消息。
5.3.2 可变报头(variable header)
可变报头按顺序包含主题名和报文标识符。
5.3.3 有效载荷(Payload)
若Qos为0,无响应,若Qos为1,返回PUBACK报文,若Qos为2,返回PUBREC报文。
5.4发布确认(PUBACK)
由服务器或客户端确认已接收到pub消息
5.4.1 固定报头(fixed header)
5.4.2 可变报头(variable header)
只有两字节的报文标识(报文标识为pub报文标识)
5.5发布收到 PUBREC(QoS 2,第一步)
5.5.1 固定报头(fixed header)
5.5.2 可变报头(variable header)
只有两字节的报文标识(报文标识为pub报文标识)
5.6发布释放 PUBREL(QoS 2,第二步)
5.6.1 固定报头(fixed header)
5.6.2 可变报头(variable header)
只有两字节的报文标识(报文标识为pub报文标识)
5.7发布完成 PUBCOMP(QoS 2,第三步)
5.7.1 固定报头(fixed header)
5.7.2 可变报头(variable header)
只有两字节的报文标识(报文标识为pub报文标识)
5.8订阅主题(SUBSCRIBE)
客户端通过订阅消息的方式来接收服务端下发的消息
5.8.1 固定报头(fixed header)
SUBSCRIBE控制固定报头的第3,2,1,0位是保留位,必须分别设置为0,0,1,0。服务端必须将其它的任何值都当做是不合法的并关闭网络连接
5.8.2 可变报头(variable header)
只有两字节的报文标识
5.8.3 有效载荷(Payload)
消息载体包含若干主题过滤器和服务质量等级
PUB时指定的qos是服务器肯定按此规则接收,但是最终订阅者不一定。
SUB时指定的qos表示订阅者可以接收的最高消息等级,也就是可能收到更低等级的消息
5.9订阅确认(SUBACK)
SUBACK报文包含一个返回码清单,它们指定了SUBSCRIBE请求的每个订阅被授予的最大QoS等级。
5.9.1 固定报头(fixed header)
5.9.2 可变报头(variable header)
只有两字节的报文标识
5.9.3 有效载荷(Payload)
允许的返回码为0x00-最大Qos0,0x01-最大Qos1,0x02-最大Qos2,0x80-失败
5.10取消订阅 (UNSUBSCRIBE)
5.10.1 固定报头(fixed header)
5.10.2 可变报头(variable header)
只有两字节的报文标识
5.10.3 有效载荷(Payload)
包含需要取消订阅的主题过滤器的列表.
5.11取消订阅确认 (UNSUBACK)
5.11.1 固定报头(fixed header)
5.11.2 可变报头(variable header)
只有两字节的报文标识(报文标识为unsub报文标识)
5.12心跳请求 (PINGREQ)
客户端发送PINGREQ报文给服务端的。用于:
1.在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
2.请求服务端发送 响应确认它还活着。
3.使用网络以确认网络连接没有断开
5.12.1 固定报头(fixed header)
5.13心跳响应 (PINGRESP)
5.13.1 固定报头(fixed header)
5.14断开连接 (DISCONNECT)
5.14.1 固定报头(fixed header)
抓包注意:用标准不加密MQTT能抓到便于查看的报文,加密报文解析时不便于理解
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
清风 | 文 【原创】
如果本篇博客有任何错误,请批评指教,不胜感激 !
出处:http://www.cnblogs.com/maanshancss/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。所有源码遵循Apache协议,使用必须添加 from maanshancss