概述
ESP8266连接阿里云之MQTT
因为本人正在学习ESP8266上传数据至阿里云,需要学习了解MQTT报文协议,在这里总结一下。
在阿里云物联网平台控制台创建设备的过程就省略了但是要注意的就是节点类型选直连设备,联网方式为WIFI,数据格式为ICA
1.MQTT控制报文格式
1.2 MQTT控制报文结构
Fixed header 固定报头,所有控制报文都包含 |
Variable header 可变报头,部分控制报文包含 |
Payload 有效载荷,部分控制报文包含 |
1.2 MQTT控制报文的类型报文
学习MQTT报文其实就是学习这16种报文,并且基本都是成对出现,起始要学习的也就几种而已,后面就按照平常与阿里云连接的MQTT报文顺序进行讲解。
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
Reserved | 0 | 禁止 | 保留 |
CONNECT | 1 | C->S | 客户端请求连接服务端 |
CONNACK | 2 | S->C | 连接报文确认 |
PUBLISH | 3 | C->S、S->C | 发布信息 |
PUBACK | 4 | C->S、S->C | QoS 1消息发布收到确认 |
PUBREC | 5 | C->S、S->C | 发布收到(保证交付第一步) |
PUBREL | 6 | C->S、S->C | 发布释放(保证交付第二步) |
PUBCOMP | 7 | C->S、S->C | QoS 2消息发布完成(保证交互第三步) |
SUBSCRIBE | 8 | C->S | 客户段订阅请求 |
SUBACK | 9 | S->C | 订阅请求报文确认 |
UNSUBSCRIBE | 10 | C->S | 客户端取消i订阅请求 |
UNSUBACK | 11 | S->C | 取消订阅请求报文确认 |
PINGREQ | 12 | C->S | 心跳请求 |
PINGRESP | 13 | S->C | 心跳响应 |
DISCONNECT | 14 | C->S | 客户点断开连接 |
Reserved | 15 | 禁止 | 保留 |
2. MQTT控制报文
2.1 CONNECT-连接服务端
2.1.1 固定报头:
剩余长度:指可报头变加有效载荷长度.
剩余长度字段大小:
剩余长度举例:小于128字节的长度用单字节表示(没有进位,最高位始终为0),
大于等于128小于16364字节的长度用双字节表示,比如:2000(2000%128=80(0x50),由于有进位,最高位为1,所以第一字节为c0,2000/128=15(0x0f),第二字节没有进位,所以第二字节0f。2000剩余长度的写法为c0 0f)。
大于等于16384小于2097152时用三字节表示,除以16484。
byte1固定为10(注意报文是十六进制)byte2是剩余长度,报文还未完成,长度未知,暂时先用xx代替。
当前报文(十六进制):10 xx
2.1.2可变报头
CONNECT 报文的可变报头按下列次序包含四个字段:协议名(Protocol Name),协议级别(Protocol Level),连接标志(Connect Flags)和保持连接(Keep Alive)
2.1.2.1协议名:
协议名是表示协议名 MQTT 的 UTF-8 编码的字符串。MQTT 规范的后续版本不会改变这个字符串的偏移和长度。
如果协议名不正确服务端可以断开客户端的连接,也可以按照某些其它规范继续处理 CONNECT 报文。对于后一种情况,按照本规范,服务端不能继续处理 CONNECT 报文 [MQTT-3.1.2-1]。
当前报文:10 xx 00 04(00 04是MQTT的长度) 4D 51 54 54 (MQTT)
2.1.2.2协议级别:
客户端用 8 位的无符号值表示协议的修订版本。对于 3.1.1 版协议,协议级别字段的值是 4(0x04)。如果发现不支持的协议级别,服务端必须给发送一个返回码为0x01(不支持的协议级别)的CONNACK 报文响应CONNECT 报文,然后断开客户端的连接 [MQTT-3.1.2-2]。
当前报文:10 xx 00 04 4D 51 54 54 04(Level)
2.1.2.3连接标志:
服务端必须验证 CONNECT 控制报文的保留标志位(第 0 位)是否为 0,如果不为 0 必须断开客户端连接 [MQTT-3.1.2-3]。
当前报文:10 xx 00 04 4D 51 54 54 04 C2(使用User Name和Password,Will Flag遗嘱标志暂未使用,1清除会话(下线后不保留会话))
2.1.2.4保持连接:
保持连接(Keep Alive)是一个以秒为单位的时间间隔,表示为一个 16 位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻,两者之间允许空闲的最大时间间隔。客户端负责保证控制报文发送的时间间隔不超过保持连接的值。如果没有任何其它的控制报文可以发送,客户端必须发送一个PINGREQ 报文 [MQTT-3.1.2-23]。
不管保持连接的值是多少,客户端任何时候都可以发送 PINGREQ 报文,并且使用 PINGRESP 报文判断网络和服务端的活动状态。
如果保持连接的值非零,并且服务端在一点五倍的保持连接时间内没有收到客户端的控制报文,它必须断开客户端的网络连接,认为网络连接已断开 [MQTT-3.1.2-24]。
客户端发送了 PINGREQ 报文之后,如果在合理的时间内仍没有收到 PINGRESP 报文,它应该关闭到服务端的网络连接。
当前报文:10 xx 4D 51 54 54 04 C2 00 64(100s内需要发送一次报文,如果100s内没有要发送的数据,需要发送一个PING包(C0 00)来保持连接状态)
2.1.3有效载荷
CONNECT 报文的有效载荷(payload)包含一个或多个以长度为前缀的字段,可变报头中的标志决定是否包含这些字段。如果包含的话,必须按这个顺序出现:客户端标识符,遗嘱主题,遗嘱消息,用户名,密码 [MQTT-3.1.3-1]。
2.1.3.1客户端标识符
服务端使用客户端标识符 (ClientId) 识别客户端。连接服务端的每个客户端都有唯一的客户端标识符(ClientId)。客户端和服务端都必须使用 ClientId 识别两者之间的 MQTT 会话相关的状态。
客户端标识符 (ClientId) 必须存在而且必须是 CONNECT 报文有效载荷的第一个字段 。
2.1.3.2遗嘱主题(暂未使用)
2.1.3.3遗嘱信息(暂未使用)
2.1.3.4用户名
如果用户名(User Name)标志被设为1,有效载荷的下一个字段就是它。
2.1.3.5密码
如果密码(Password)标志被设为1,有效载荷的下一个字段就是它。
下面将客户端标识符、用户名和密码一同讲解。
以下信息来自阿里云设备信息:
DeviceName:stm32f103vet6
ProductKey:a1p48BzSEHs
DeviceSecret:放自己设备的设备密码即可(注意:是DeviceSecret,而不是ProductSecret)
现在我们需要把设备ID,用户名和密码写进报文。
设备ID(即客户端标识符):*|securemode=3,signmethod=hmacsha1| *号表示设备名称(DeviceName),加密计算时注意替换
用户名:*&# *号表示设备名称 ,#号表示ProductKey,加密计算时注意替换
密 码:用DeviceSecret作为密钥对clientId*deviceName*productKey#进行hmacsha1加密后的结果 注意加密时对符号进行替换
hmacsha1加密在线计算网站:因为时间久了,一些网站可能由于某些原因会挂掉,就不放具体网站的链接了,浏览器直接搜索hmacsha1加密在线计算网站即可
在hmacsha1加密在线计算网站进行转换如下图:
当前的设备ID、用户名和密码为(以转换为十六进制,注意符号替换):
设备ID:73 74 6D 33 32 66 31 30 33 76 65 74 36 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C
用户名:73 74 6D 33 32 66 31 30 33 76 65 74 36 26 61 31 70 34 38 42 7A 53 45 48 73
密码: 39 33 34 31 65 35 39 61 34 37 35 61 62 31 34 62 39 64 65 31 36 33 33 62 34 xx xx xx xx xx xx 65 38 61 31 37 36 65 31 36
当前的报文为:10 80 01(剩余长度是128) 00 04 4D 51 54 54 04 C2 00 64 00 2F(设备ID长度) 73 74 6D 33 32 66 31 30 33 76 65 74 36 7C 73 65 63 75 72 65 6D 6F 64 65 3D 33 2C 73 69 67 6E 6D 65 74 68 6F 64 3D 68 6D 61 63 73 68 61 31 7C 00 19(用户名长度) 73 74 6D 33 32 66 31 30 33 76 65 74 36 26 61 31 70 34 38 42 7A 53 45 48 73 00 28 (密码长度) 39 33 34 31 65 35 39 61 34 37 35 61 62 31 34 62 39 64 65 31 36 33 33 62 34 xx xx xx xx xx xx 65 38 61 31 37 36 65 31 36 (这里就不放我的阿里云设备的全部报文了)
阿里云服务器IP地址(华东2):*.iot-as-mqtt.cn-shanghai.aliyuncs.com *号表示自己的ProductKey,注意这里用的是华东2的服务器,要根据自己的阿里云设备选择不同地区的服务器。
阿里云服务器端口号(华东2):1883
打开网络调试助手,配置好阿里云的服务器IP和端口号,把报文以16进制(HEX)发送,如果接受到阿里云发来的20 02 00 00表示已经连接上阿里云的服务器。
接受到的20 02 00 00数据的解释
20 02是固定的,表示MQTT控制报文类型和剩余长度
00 00 第一个00是固定的,第二个00表示成功连接,其他值都是表示连接有错误。
查看阿里云的设备状态可以看到,设备状态已由未激活变为在线状态
2.2 DISCONNECT-断开连接
DISCONNECT报文是客户端发给服务端的最后一个控制报文了,表示客户端正常断开连接。
2.2.1固定报头
2.2.2可变报头
DISCONNECT没有可变报头。
2.2.3使用
因此在连接状态,发送固定的E0 00就可以让客户端与服务端断开连接。
这里演示一下:
首先连接到阿里云,看到连接阿里云成功
接下来发送E0 00
可以看到设备已经断开连接
2.3 PINGREQ-心跳请求
客户段发送PINGREQ报文给服务器,用于:
1.在没有任何其它控制报文从客户端发给服务时,告知服务器客户端还活着。
2.请求服务端发送 响应确认它还活着。
3.使用网络以确认网络连接没有断开。
2.3.1固定报头
2.3.2可变报头
PINGREQ无可变报头。
2.3.3使用
连接状态,客服端发送C0 00,服务器会发送响应报文PINGRESP(D0 00)
2.4 SUBSCRIBE-订阅
客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅注册客户端关心的一个或多个主题。为了将停用消息转发给与那些订阅匹配的的主题,服务端发送PUBLISH报文给客户端。SUBSCRIBE报文也(为每个订阅)指定了最大的QoS等级,服务端根据这个发送应用消息给客服端。
2.4.1固定报头
SUBSCRIBE控制报文固定报头的3-0位是保留位,必须分别设置位0,0,1,0、服务端必须将其它的任何值都当作是不合法的,并关闭网络连接。
剩余长度字段
等于可变报头的长度(2字节)加上有效荷载的长度。
2.4.2可变报头
可变报头包含客户端标识符(比如订阅多个TOPIC时,用来区分彼此,自己定义)。
2.4.3有效载荷
SUBSCRIBE报文的有效载荷包含了一个主题过滤列表,他们表示客户段想要订阅的主题。SUBSCRIBE报文有效载荷中的主题过滤器列表必须是定义过的UTF-8字符串。服务端应该支持包含通配符的主题过滤器。如果服务器选择不支持包含通配符的主题过滤器,必须拒绝任何包含通配符过滤器的订阅请求。每一个过滤器后面跟着一个字节,这个字节被叫做服务质量要求(Request QoS)。他给出了服务端想客服端发送应用消息所允许的最大Qos等级。SUBSCRIBE报文的有效载荷必须包含至少一对主题过滤器和QoS等级字段组合。没有有效载荷的SUBSCRIBE报文是违反协议的。
2.4.4使用
阿里云的TOPIC列表(默认就有,在设备管理中,双击产品名称,点击TOPIC列表):
我们订阅这个TOPIC:/sys/a1p48BzSEHs/${deviceName}/thing/service/property/set,注意把deviceName替换为自己的设备名,美元符号,和中括号要删掉,否则会SUNACK会返回错误码0x80,替换后为
/sys/a1p48BzSEHs/stm32f103vet6/thing/service/property/set
示例报文:
82 3E (固定报头和剩余长度) 12 34(12 34自己设置的客户端标识符) 00 39 2F 73 79 73 2F 61 31 70 34 38 42 7A 53 45 48 73 2F 73 74 6D 33 32 66 31 30 33 76 65 74 36 2F 74 68 69 6E 67 2F 73 65 72 76 69 63 65 2F 70 72 6F 70 65 72 74 79 2F 73 65 74 (00 39是订阅的阿里云上设备的TOPIC转换为16进制后的长度)00(服务质量等级0:最多分发一次)
更直观的报文如下:
82 3E 12 34 00 39 2F 73 79 73 2F 61 31 70 34 38 42 7A 53 45 48 73 2F 73 74 6D 33 32 66 31 30 33 76 65 74 36 2F 74 68 69 6E 67 2F 73 65 72 76 69 63 65 2F 70 72 6F 70 65 72 74 79 2F 73 65 74 00
阿里云服务器返回SUBACK报文,90 表示是MQTT控制报文类型,03表示剩余长度,12 34是我们设置的客户端标识符。01表示成功(在阿里云上,无论QoS是1还是0是,返回的都是01)。
2.5 UNSUBSCRIBE-取消订阅
客户端发送UNSUBSCRIBE报文给服务端,用于取消订阅主题。
2.5.1 固定报头
剩余长度
等于可变报头的长度加上有效载荷的长度
2.5.2 可变报头
可变报头包含一个报文标识符(同样也是自己设置的)。
2.5.3 有效载荷
UNSUBSCRIBE 报文的有效载荷包含客户端想要取消订阅的主题过滤器列表。UNSUBSCRIBE 报文中的主题过滤器必须是连续打包的、按照 1.5.3 节定义的 UTF-8 编码字符串 [MQTT-3.10.3-1]。
UNSUBSCRIBE 报文的有效载荷必须至少包含一个消息过滤器。没有有效载荷的 UNSUBSCRIBE 报文是违反协议的 [MQTT-3.10.3-2]。
2.5.4使用
UNSUBSCRIBE报文与SUBSCRIBE的不同:固定报头不同,不需要服务等级,所以剩余长度也会减一
SUBSCRIBE报文:
82 3E 12 34 00 39 2F 73 79 73 2F 61 31 70 34 38 42 7A 53 45 48 73 2F 73 74 6D 33 32 66 31 30 33 76 65 74 36 2F 74 68 69 6E 67 2F 73 65 72 76 69 63 65 2F 70 72 6F 70 65 72 74 79 2F 73 65 74 00
UNSUBSCRIBE报文:
A2 3D 12 34 00 39 2F 73 79 73 2F 61 31 70 34 38 42 7A 53 45 48 73 2F 73 74 6D 33 32 66 31 30 33 76 65 74 36 2F 74 68 69 6E 67 2F 73 65 72 76 69 63 65 2F 70 72 6F 70 65 72 74 79 2F 73 65 74
2.6 PUBLISH-发布
PUBLISH控制报文是指从客户端向服务端或服务端向客户端传输一个应用消息。
2.6.1固定报头
位3 DUP设置为0时,表示这是客户端或服务端第一次请求发送这个PUBLISH报文,设置为1时,表示这可能是一个早期报文请求的重发。
客户端或服务端请求重发一个PUBLISH时,必须将DUP标志设为1,对于QoS0的消息,DUP必须设置为0。
位2 服务质量等级
位0 保留标志
剩余长度字段
等于可变报头的长度加上有效载荷的长度。
2.6.2 可变长度
可变报头按顺序包含主题名和报文标识符。
主题名(TOPIC Name)
报文标识符
只有QoS等级是1或2时。报文标识符字段才能出现在PUBLISH报文中。
2.6.3 有效载荷
有效载荷包含将被发布的应用消息,数据的内容和格式是应用特定的,有效载荷的长度这样计算,用固定包头中剩余长度字段的值减去可变报头的长度。包含零长度有效载荷的PUBLISH报文是合法的。
2.6.4 响应
PUBLISH报文的接收者必须按照根据PUBLISH报文中的QoS等级发送响应。
2.6.5 动作
2.6.6 使用
需要发布的TOPIC:/sys/a1p48BzSEHs/stm32f103vet6/thing/event/property/post
需要发布的数据:{"method":"thing.service.event.post","id":"123456789","params":{"temperature":28.60,"humidity":18.81},"version":"1.0.0"}
示例
固定报头+剩余长度+(topic长度+topic)+(报文标识符位置,这里没用)+(需要发布的数据)
30(固定报头) B5 01(剩余长度) 00 38(TOPIC长度) 2F 73 79 73 2F 61 31 70 34 38 42 7A 53 45 48 73 2F 73 74 6D 33 32 66 31 30 33 76 65 74 36 2F 74 68 69 6E 67 2F 65 76 65 6E 74 2F 70 72 6F 70 65 72 74 79 2F 70 6F 73 74(TOPIC) (报文标识符位置,等级1有标识符,当前是等级0,所以此位置没有标识符) 7B 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 6E 67 2E 73 65 72 76 69 63 65 2E 70 72 6F 70 65 72 74 79 2E 70 6F 73 74 22 2C 22 69 64 22 3A 22 31 32 33 34 35 36 37 38 39 22 2C 22 70 61 72 61 6D 73 22 3A 7B 22 74 65 6D 70 65 72 61 74 75 72 65 22 3A 32 38 2E 36 30 2C 22 68 75 6D 69 64 69 74 79 22 3A 31 38 2E 38 31 7D 2C 22 76 65 72 73 69 6F 6E 22 3A 22 31 2E 30 2E 30 22 7D (数据)
3. 总结
3.1 连接报文
MQTT连接报文=固定报头+可变报头(10)+负载(报文是16进制)
固定报头=10+剩余长度
可变报头=可变报头长度(2)+"MQTT"(4)+协议级别(1)+使能用户名、密码(1)+保活时长(2)=10(这个10是长度)
负载=设备ID长度(2)+设备ID+用户名长度(2)+用户名+密码长度(2)+密码
其他报文类似,不再总结。
3.2 长度表示
小于128直接用1字节表示,大于等于128小于等于16384用两字节表示,长度分别求余和取整,求余的或上0x80(表示有进位)放第一位,取整的放在第二位。
3.3 注意事项
报文是16进制,使用在线网站进行加密时注意替换对应的符号,本文用的是华东2服务器,注意更改,订阅报文时注意选择相应的TOPIC类。
学到里,MQTT报文已经学习的差不多了,可以继续学习ESP8266上传数据至阿里云。
最后
以上就是无私天空为你收集整理的ESP8266连接阿里云之MQTT学习 ESP8266连接阿里云之MQTT1.MQTT控制报文格式1.2 MQTT控制报文结构3. 总结的全部内容,希望文章能够帮你解决ESP8266连接阿里云之MQTT学习 ESP8266连接阿里云之MQTT1.MQTT控制报文格式1.2 MQTT控制报文结构3. 总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复