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级别等标志位。第二字节开始是剩余长度字段,该长度是后面的可变报文头加消息负载的总长度,不包括用于编码剩余长度字段本身的字节数,该字段最多允许四个字节。

图4-1固定报头报文结构
剩余长度字段单个字节最大值为二进制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数据包类型

图4-3数据包类型标识位

4.2 可变报文头(Variable Header)

可变报文头主要包含协议名、协议版本、连接标志(Connect Flags)、心跳间隔时间(Keep Alive timer)、连接返回码(Connect Return Code)、主题名(Topic Name)等,后面会针对主要部分进行讲解。

图4-4可变报头结构

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)。

图4-5消息结构
当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)


图5-1 CONNECT固定报头报文
Connect名称的值为1,低四位保留,剩余长度保存可变报头(10字节)加上有效载荷的长度。

5.1.2 可变报头(variable header)

Connect报文的可变报头包含协议名,协议等级,连接标志和保持连接

图5-2 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-3 CONNECT消息报文

5.2连接请求确认(CONNACK)

Connack为服务器确认客户端连上服务给出的回应。

5.2.1 固定报头(fixed header)


图5-4 CONNACK固定报头报文

5.2.2 可变报头(variable header)


图5-5 CONNACK可变报头报文

  • 第一字节1~7位保留,第0位是当前会话标志(session present),若清除会话标志被置1,该位为0,若清除会话标志为0且服务器没有与客户端会话保存,该位置0,有保存置1
    第二字节保存连接返回码,若连接成功返回0。

  • 图5-6 连接返回码

    图5-7 CONNECT响应报文

    5.3发布消息(PUBLISH)

    发布消息可由客户端或服务器发出,被消息订阅者接收。

    5.3.1 固定报头(fixed header)


    图5-8 PUBLISH固定报头报文
    固定报头第一字节的低四位分别保存重发标志(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-9 publish消息报文

    5.4发布确认(PUBACK)

    由服务器或客户端确认已接收到pub消息

    5.4.1 固定报头(fixed header)


    图5-10 puback固定报头报文

    5.4.2 可变报头(variable header)

    只有两字节的报文标识(报文标识为pub报文标识)

    图5-11 puback消息报文

    5.5发布收到 PUBREC(QoS 2,第一步)

    5.5.1 固定报头(fixed header)


    图5-12 pubrec固定报头报文

    5.5.2 可变报头(variable header)

    只有两字节的报文标识(报文标识为pub报文标识)

    图5-13 pubrec消息报文

    5.6发布释放 PUBREL(QoS 2,第二步)

    5.6.1 固定报头(fixed header)


    图5-14 pubrel固定报头报文

    5.6.2 可变报头(variable header)

    只有两字节的报文标识(报文标识为pub报文标识)

    图5-15 pubrel消息报文

    5.7发布完成 PUBCOMP(QoS 2,第三步)

    5.7.1 固定报头(fixed header)


    图5-16 pubcomp固定报头报文

    5.7.2 可变报头(variable header)

    只有两字节的报文标识(报文标识为pub报文标识)

    图5-17 pubcomp消息报文

    5.8订阅主题(SUBSCRIBE)

    客户端通过订阅消息的方式来接收服务端下发的消息

    5.8.1 固定报头(fixed header)

    SUBSCRIBE控制固定报头的第3,2,1,0位是保留位,必须分别设置为0,0,1,0。服务端必须将其它的任何值都当做是不合法的并关闭网络连接

    图5-18 subscribe固定报头报文

    5.8.2 可变报头(variable header)

    只有两字节的报文标识

    5.8.3 有效载荷(Payload)


    图5-19 subscribe有效载体报文
    消息载体包含若干主题过滤器和服务质量等级
    PUB时指定的qos是服务器肯定按此规则接收,但是最终订阅者不一定。
    SUB时指定的qos表示订阅者可以接收的最高消息等级,也就是可能收到更低等级的消息

    图5-20 subscribe消息报文

    5.9订阅确认(SUBACK)

    SUBACK报文包含一个返回码清单,它们指定了SUBSCRIBE请求的每个订阅被授予的最大QoS等级。

    5.9.1 固定报头(fixed header)


    图5-21 suback固定报头报文

    5.9.2 可变报头(variable header)

    只有两字节的报文标识

    5.9.3 有效载荷(Payload)


    图5-22 suback有效载体报文
    允许的返回码为0x00-最大Qos0,0x01-最大Qos1,0x02-最大Qos2,0x80-失败

    图5-23 suback消息报文

    5.10取消订阅 (UNSUBSCRIBE)

    5.10.1 固定报头(fixed header)


    图5-24 unsubscribe固定报头报文

    5.10.2 可变报头(variable header)

    只有两字节的报文标识

    5.10.3 有效载荷(Payload)

    包含需要取消订阅的主题过滤器的列表.

    图5-25 unsubscribe消息报文

    5.11取消订阅确认 (UNSUBACK)

    5.11.1 固定报头(fixed header)


    图5-26 unsuback固定报头报文

    5.11.2 可变报头(variable header)

    只有两字节的报文标识(报文标识为unsub报文标识)

    图5-27 unsuback消息报文

    5.12心跳请求 (PINGREQ)

    客户端发送PINGREQ报文给服务端的。用于:
    1.在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
    2.请求服务端发送 响应确认它还活着。
    3.使用网络以确认网络连接没有断开

    5.12.1 固定报头(fixed header)


    图5-28 pingreq固定报头报文

    图5-29 pingreq消息报文

    5.13心跳响应 (PINGRESP)

    5.13.1 固定报头(fixed header)


    图5-30 pingresp固定报头报文

    图5-31 pingresp消息报文

    5.14断开连接 (DISCONNECT)

    5.14.1 固定报头(fixed header)


    图5-32 disconnect固定报头报文

    图5-33 disconnect消息报文

    抓包注意:用标准不加密MQTT能抓到便于查看的报文,加密报文解析时不便于理解

    创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

    清风 | 文 【原创】

    如果本篇博客有任何错误,请批评指教,不胜感激 !

    MQTT抓包分析的更多相关文章

    1. Wireshark抓包分析/TCP/Http/Https及代理IP的识别

      前言 坦白讲,没想好怎样的开头.辗转三年过去了.一切已经变化了许多,一切似乎从没有改变. 前段时间调研了一次代理相关的知识,简单整理一下分享之.如有错误,欢迎指正. 涉及 Proxy IP应用 原理/ ...

    2. HTTP2特性预览和抓包分析

      背景 近年来,http网络请求量日益添加,以下是httparchive统计,从2012-11-01到2016-09-01的请求数量和传输大小的趋势图: 当前大部份客户端&服务端架构的应用程序, ...

    3. 抓包分析SSL/TLS连接建立过程【总结】

      1.前言 最近在倒腾SSL方面的项目,之前只是虽然对SSL了解过,但是不够深入,正好有机会,认真学习一下.开始了解SSL的是从https开始的,自从百度支持https以后,如今全站https的趋势越来 ...

    4. 实战录 | 基于openflow协议的抓包分析

      <实战录>导语 云端卫士<实战录>栏目定期会向粉丝朋友们分享一些在开发运维中的经验和技巧,希望对于关注我们的朋友有所裨益.本期分享人为云端卫士安全SDN工程师宋飞虎,将带来基于 ...

    5. 在Hdsi2.0 SQL的注入部分抓包分析语句

      在Hdsi2.0 SQL的注入部分抓包分析语句 恢复cmd ;insert tb1 exec master..xp_cmdshell''net user ''-- ;exec master.dbo.s ...

    6. [转] Android实时抓包分析 : 善用adb调试桥

      Android实时抓包分析 : 善用adb调试桥   谈到android网络抓包,很多人都能想到牛逼轰轰的神器tcpdump.方法就是在android机器上面安装tcpdump,然后通过-w参数把抓包 ...

    7. 云计算之路-阿里云上:Wireshark抓包分析一个耗时20秒的请求

      这篇博文分享的是我们针对一个耗时20秒的请求,用Wireshark进行抓包分析的过程. 请求的流程是这样的:客户端浏览器 -> SLB(负载均衡) -> ECS(云服务器) -> S ...

    8. 用Wireshark抓包分析超过70秒的请求

      超过70秒的请求是通过分析IIS日志发现的: 10.159.63.104是SLB的内网IP. 通过Wireshark抓包分析请求是9:22:21收到的(tcp.stream eq 23080): 09 ...

    9. Wireshark抓包分析HTTPS与HTTP报文的差异

      一.什么是HTTPS: HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议 它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换 ...

    随机推荐

    1. get 传中文,可以通过下面这种方式

      window.location.href=encodeURI("<%=path%>/XXX.XXX?name=中文"); 然后在后台通过new String(reque ...

    2. mysql表关联问题(第三卷:外键多对多)

      现在我们整理一下多对多的问题,举个例子现在一个男的可能和多个女的谈过恋爱,一个女的也可能和多个男的谈过恋爱,把他们恋爱的关系整理为数据关联表就成为了多对多的关系. 准备三张表,男人信息表,女人信息表, ...

    3. 题解 HDU 3698 Let the light guide us Dp + 线段树优化

      http://acm.hdu.edu.cn/showproblem.php?pid=3698 Let the light guide us Time Limit: 5000/2000 MS (Java ...

    4. dos窗口运行python文件提示找不到模块

      问题:在pycharm直接运行test_suit.py正常,通过dos窗口运行则提示找不到模块. 原因: https://blog.csdn.net/crylearner/article/detail ...

    5. 原生 XMLHttpRequest

      一.什么是XMLHttpRequest? XHR英文全名XmlHttpRequest,中文可以解释为可扩展超文本传输请求.Xml可扩展标记语言,Http超文本传输协议,Request请求.XMLHtt ...

    6. 详解服务器性能测试的全生命周期?——从测试、结果分析到优化策略(转载)

      服务器性能测试是一项非常重要而且必要的工作,本文是作者Micheal在对服务器进行性能测试的过程中不断摸索出来的一些实用策略,通过定位问题,分析原因以及解决问题,实现对服务器进行更有针对性的优化,提升 ...

    7. es6this箭头函数

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 < ...

    8. 传智播客学习之Android运行原理 (转)

      传智播客学习之Android运行原理 (2010-03-20 22:45:15) 转载▼ 今天终于忙里偷闲,和大家探讨一下android技术,第一次听到3G应该追溯到大学三年级的时候了,记得当时现代通 ...

    9. 能源科技,苹果和Google的新圣战?

      细心的果粉可能会注意到,最新版本的IOS软体中,增加了一个不起眼的按钮,它是一款署名为"家庭"的App,之所以说它不起眼,是因为它好像真得没什么用,活跃率恐怕不及Wechat的万分 ...

    10. Spring源码阅读笔记03:xml配置读取

      前面的文章介绍了IOC的概念,Spring提供的bean容器即是对这一思想的具体实现,在接下来的几篇文章会侧重于探究这一bean容器是如何实现的.在此之前,先用一段话概括一下bean容器的基本工作原理 ...