一文带你了解 MQTT 协议(连接 ONE

您所在的位置:网站首页 mqtt连接 一文带你了解 MQTT 协议(连接 ONE

一文带你了解 MQTT 协议(连接 ONE

#一文带你了解 MQTT 协议(连接 ONE| 来源: 网络整理| 查看: 265

MQTT 协议连接 ONE-NET 详解 写在前面

​  本文采用 网络调试助手 发送MQTT协议报文(16进制) 连接 ONE-NET 平台,采用的 为 MQTT v3.1.1 标准协议。带你直接 学会 MQTT 协议。

一、ONE-NET 端创建设备

​   由于我们需要使用 MQTT 协议 连接 ONE-NET 平台,所以我们需要先创建一个设备。  

1. 进入 ONE-NET 平台,进入控制台首页,切换置旧版

2. 点击最左侧圆球,选择多协议接入

3. 我们这次采用的是 MQTT 协议,所以直接创建MQTT 协议的产品即可。

4. 联网方式选择 wifi 即可

5. 再添加设备,注意:鉴权信息就是你后面需要使用的 密码,下面的鉴权信息是 博主本人的 QQ号,有需要讨论问题可以添加!

6. 这时候我们需要记录三个连接 ONE-NET 的数据,一个是设备 ID,一个是产品 ID,一个是鉴权信息

​  设备ID 和 密码的话:就是你前面设置的鉴权信息。如果遗忘的话,可以在设备详情里查找

 最后,ONE-NET 端 的设备就创建完毕了。

二、通过 MQTT v3.1.1协议 编写对应的报文

​  MQTT 协议报文由三部分组成,固定报文,可变报头和有效载荷,所以我们编写 MQTT 协议报文也需要从这三方面入手。

1. 通过网络调试助手连接报文 连接 ONE-NET 端 1. 固定报头

 首先是固定报头,上述是 CONNECT 报文的固定报头,由图可知 byte1 = 10,剩余长度是可变报头+有效载荷,如下图所示,剩余长度最多为四个字节,最高位如果 为 1 ,代表下面还有 至少一个字节数。后面当所有报文都编写完后再计算剩余长度大小。

2. 可变报头

​ 如上图所示,我们可以编写出 byte1 - byte7,大概为 00 04 4D 51 54 54 04 (16进制数)

​ byte 8 表示,由于 ONE-NET 端不允许匿名登录,所以我们需要将 用户名标志,密码标志置 1,由于我们为初学者,我们只需要再掌握一个QoS服务质量即可,下面是服务质量分析图。

​  一般我们采用 最多分发一次即可。也就是 QoS = 0 ,bit2 bit1 为 00

​  byte 9 和 byte 10 为 保活时间,我这边采取 100 的 保活时间,变成16进制数也就是 64

 ​ 所以 byte9 和byte 10 分别为 00 64

​   所以固定报头和可变报头为:10 xx(未计算剩余长度) 00 04 4d 51 54 54 04 c0 00 64

3. 有效载荷

 我们需要验证 设备号,用户名(产品 ID)和密码(鉴权信息)。 由于报文为16进制数,我们可以通过网络助手快速计算出这些数据的16进制数和字节长度。

 先选择 UDP 形式,连接远程主机,并且分别把设备 ID,产品ID,密码输入

​  再点击 16 进制数,将该数值转化为 16 进制数。发送的数值为 9 ,注意:要转换成16进制数,换算成 16 进制数 也是 9。所以不必对其进行额外的 进制转换。

 所以有效载荷就为:00 09 37 38 39 35 34 36 38 30 35 00 06 34 35 38 39 34 35 00 09 31 33 36 39 32 38 38 33 31 (先输入 设备号 大小 00 - 09 再输入其设备号,后续一样操作)

 最后将 可变报头和有效载荷 一起输入到网络调试助手计算字节大小,注意:复制数值前先勾选16进制数,因为我们已经将前面的转换为16进制数了

 我这边为 40 ,转化为 16进制数为 28 ,所以我的剩余长度就为 28

 CONNECT连接报文总共为:10 28 00 04 4d 51 54 54 04 c0 00 64 00 09 37 38 39 35 34 36 38 30 35 00 06 34 35 38 39 34 35 00 09 31 33 36 39 32 38 38 33 31

 这时候我们将 网络调试助手 换成 TCP Client 端,远程主机地址为:183.230.40.39 :6002,并且在复制前先勾选16进制发送,和16进制数接受,换行等。

 由图我们发送连接报文,发现返回 20 02 00 00,并且设备已经在线了,说明我们连接成功。

 CONNACK - 确认连接请求 固定报头 就为 20 02 ,也再一次证明为 连接确认请求

​  其他的报文也和这个 连接报文 差不多,可以自己阅读 MQTT v3.1.1 标准协议。

 下面是 Keil5 编写的 MQTT 连接报文

uint8 MQTT_PacketConnect(const int8 *user, const int8 *password, const int8 *devid, uint16 cTime, uint1 clean_session, uint1 qos, const int8 *will_topic, const int8 *will_msg, int32 will_retain, MQTT_PACKET_STRUCTURE *mqttPacket) { //flags 用于接收 byte 8 ,判断用户名,密码,服务质量,遗嘱信息等 uint8 flags = 0; uint8 will_topic_len = 0; uint16 total_len = 15; int16 len = 0, devid_len = strlen(devid); //设备号 if(!devid) //如果设备号为空,直接退出 return 1; total_len += devid_len + 2; // + 2 表示需要使用两个字节表示 设备号的起始和结束位置 //判断断线后,是否清理离线消息:1-清理, 0-不清理 if(clean_session) //默认为 0 就好 { flags |= MQTT_CONNECT_CLEAN_SESSION; //MQTT_CONNECT_CLEAN_SESSION = 0x02,根据 byte8 第2位为 1 的话代表清理离线消息 } //异常掉线是,服务器发送的 Topic if(will_topic) //默认为 NULL 即可 { flags |= MQTT_CONNECT_WILL_FLAG; will_topic_len = strlen(will_topic); total_len += 4 + will_topic_len + strlen(will_msg); } //qos 级别,主要用于 publish 消息 switch((unsigned char)qos) { case MQTT_QOS_LEVEL0: flags |= MQTT_CONNECT_WILL_QOS0; //最多一次 break; case MQTT_QOS_LEVEL1: flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS1); //最少一次 break; case MQTT_QOS_LEVEL2: flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_QOS2); //只有一次 break; default: return 2; } //主要用于 publish 消息,代表服务器要保留这次推送的信息,如果有新的订阅者,就把该消息推送给它 if(will_retain) { flags |= (MQTT_CONNECT_WILL_FLAG | MQTT_CONNECT_WILL_RETAIN); } //ONE-NET 不允许匿名登录,需要判断 if(!user || !password) { return 3; } flags |= MQTT_CONNECT_USER_NAME | MQTT_CONNECT_PASSORD; //byte8 判断是否有用户名,密码 total_len += strlen(user) + strlen(password) + 4; //总长度加 4 //分配新内存 MQTT_NewBuffer(mqttPacket, total_len); //本质是 malloc 创建 if(mqttPacket->_data == NULL) //由于创建的时候,将data全部置0,所以做个判断 return 4; memset(mqttPacket->_data, 0, total_len); //清空下 data,保证无数据 /*************************************固定头部******************************************/ //byte1---------------------连接报文的话为 10 ------------------------------------------ mqttPacket->_data[mqttPacket->_len++] = MQTT_PKT_CONNECT _data + mqttPacket->_len); if(len < 0) { MQTT_DeleteBuffer(mqttPacket); return 5; } else mqttPacket->_len += len; //添加剩余长度字节大小 len 大小为0-4 /*************************************可变报头************************************/ //可变报头----------------------协议长度和协议名(固定的)--------------------------------- mqttPacket->_data[mqttPacket->_len++] = 0; mqttPacket->_data[mqttPacket->_len++] = 4; mqttPacket->_data[mqttPacket->_len++] = 'M'; mqttPacket->_data[mqttPacket->_len++] = 'Q'; mqttPacket->_data[mqttPacket->_len++] = 'T'; mqttPacket->_data[mqttPacket->_len++] = 'T'; //----------------------protocol level 4(固定)--------------------------------------- mqttPacket->_data[mqttPacket->_len++] = 4; //byte8----------------------判断是否存在用户名,密码等标志----------------------------- mqttPacket->_data[mqttPacket->_len++] = flags; //byte9,byte10---------------保活时间---------------------------------------- //#define MOSQ_MSB(A) (uint8)((A & 0xFF00) >> 8) //#define MOSQ_LSB(A) (uint8)(A & 0x00FF) mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(cTime); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(cTime); /*************************************有效载荷*****************/ //有效载荷----------------------------devid长度,devid--------------------------------- mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(devid_len);// mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(devid_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, devid, devid_len); mqttPacket->_len += devid_len; //有效载荷----------------------------will_flag 和 will_msg(默认为 NULL 0)------------- //不执行下列代码 if(flags & MQTT_CONNECT_WILL_FLAG) { unsigned short mLen = 0; if(!will_msg) will_msg = ""; mLen = strlen(will_topic); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_topic, mLen); mqttPacket->_len += mLen; mLen = strlen(will_msg); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(mLen); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(mLen); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, will_msg, mLen); mqttPacket->_len += mLen; } //有效载荷----------------------------use用户名----------------------------------------- if(flags & MQTT_CONNECT_USER_NAME) //判断用户名这一位是否置 1,置1代表存在用户名 { unsigned short user_len = strlen(user); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(user_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(user_len); //使用 strncat 函数添加用户名 strncat((int8 *)mqttPacket->_data + mqttPacket->_len, user, user_len); mqttPacket->_len += user_len; } //有效载荷----------------------------password密码------------------------------------- if(flags & MQTT_CONNECT_PASSORD) //判断密码这一位是否置 1,置1代表存在密码 { unsigned short psw_len = strlen(password); mqttPacket->_data[mqttPacket->_len++] = MOSQ_MSB(psw_len); mqttPacket->_data[mqttPacket->_len++] = MOSQ_LSB(psw_len); strncat((int8 *)mqttPacket->_data + mqttPacket->_len, password, psw_len); mqttPacket->_len += psw_len; } return 0; }

最后

 ​本专栏完结了,最后给大家提供下所有的源代码。有需要自取。

 ​github代码地址

 ​如果可以的话,能帮我 github 上加个星么。

 ​若是该文章对你有作用或是觉得文章写得还行,帮忙点点赞,三连!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3