W5100S+树莓派RP2040快速入门之MQTT篇(十二)

目录

前言

MQTT介绍

什么是mqtt?

MQTT主要控制报文

固定报头 Fixed header

MQTT控制报文的类型 MQTT Control Packet type

标志 Flags

剩余长度 Remaining Length(包括可变报头和负载的数据的长度)

可变报头 Variable header

有效载荷 Payload

协议格式讲解

 CONNECT报文

 PUBLISH报文

SUBSCRIBE报文

DISCONNECT报文

硬件准备及接线方式

 硬件准备

接线方式(W5100SIO模块+树莓派RP2040)

测试

MQTT测试流程图

相关代码

测试现象

相关链接: 



前言

        

        上一章我们用W5100S-EVB-PICO通过SNTP获取网络时间,那么本章我们介绍一下MQTT协议的内容以及使用开发板与MQTTX软件来实现mqtt通信。

        如果您在阅读本章之后仍有不清楚的地方,可以私信联系我们或者评论区留言,我们会及时回复您的问题!

MQTT介绍

什么是mqtt?

        MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,用极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

MQTT主要控制报文

固定报头 Fixed header

        每个MQTT控制报文都包含一个固定报头。

Bit

7

6

5

4

3

2

1

0

byte 1

MQTT控制报文的类型

用于指定控制报文类型的标志位

byte 2...

剩余长度

MQTT控制报文的类型 MQTT Control Packet type

        位置:第1个字节,二进制位7-4

名字

报文流动方向

描述

Reserved

0

禁止

保留

CONNECT

1

客户端到服务端

客户端请求连接服务端

CONNACK

2

服务端到客户端

连接报文确认

PUBLISH

3

两个方向都允许

发布消息

PUBACK

4

两个方向都允许

QoS 1消息发布收到确认

PUBREC

5

两个方向都允许

发布收到(保证交付第一步)

PUBREL

6

两个方向都允许

发布释放(保证交付第二步)

PUBCOMP

7

两个方向都允许

QoS 2消息发布完成(保证交互第三步)

SUBSCRIBE

8

客户端到服务端

客户端订阅请求

SUBACK

9

服务端到客户端

订阅请求报文确认

UNSUBSCRIBE

10

客户端到服务端

客户端取消订阅请求

UNSUBACK

11

服务端到客户端

取消订阅报文确认

PINGREQ

12

客户端到服务端

心跳请求

PINGRESP

13

服务端到客户端

心跳响应

DISCONNECT

14

客户端到服务端

客户端断开连接

Reserved

15

禁止

保留

标志 Flags

        固定报头第1个字节的剩余的4位 [3-0]包含每个MQTT控制报文类型特定的标志,如果收到非法的标志,接收者必须关闭网络连接。

控制报文

固定报头标志

Bit 3

Bit 2

Bit 1

Bit 0

CONNECT

Reserved

0

0

0

0

CONNACK

Reserved

0

0

0

0

PUBLISH

Used in MQTT 3.1.1

DUP1

QoS2

QoS2

RETAIN3

PUBACK

Reserved

0

0

0

0

PUBREC

Reserved

0

0

0

0

PUBREL

Reserved

0

0

1

0

PUBCOMP

Reserved

0

0

0

0

SUBSCRIBE

Reserved

0

0

1

0

SUBACK

Reserved

0

0

0

0

UNSUBSCRIBE

Reserved

0

0

1

0

UNSUBACK

Reserved

0

0

0

0

PINGREQ

Reserved

0

0

0

0

PINGRESP

Reserved

0

0

0

0

DISCONNECT

Reserved

0

0

0

0

  1. DUP1 =控制报文的重复分发标志
  2. QoS2 = PUBLISH报文的服务质量等级
  3. RETAIN3 = PUBLISH报文的保留标志

剩余长度 Remaining Length(包括可变报头和负载的数据的长度)

        使用变成编码(1到4个字节表示,即最大可表示256M,每个字节可编码128个数值+1个延续位(最高位是延续位表示是否有更多字节,低7位表示128个数值)):

字节数

最小值

最大值

1

0 (0x00)

127 (0x7F)

2

128 (0x80, 0x01)

16 383 (0xFF, 0x7F)

3

16 384 (0x80, 0x80, 0x01)

2 097 151 (0xFF, 0xFF, 0x7F)

4

2 097 152 (0x80, 0x80, 0x80, 0x01)

268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)

可变报头 Variable header

        可变报头的内容根据 控制报文类型 的不同而不同。(特别注意:部分控制报文需要 报文标识符字段)

控制报文

报文标识符字段

CONNECT

不需要

CONNACK

不需要

PUBLISH

需要(如果QoS > 0)

PUBACK

需要

PUBREC

需要

PUBREL

需要

PUBCOMP

需要

SUBSCRIBE

需要

SUBACK

需要

UNSUBSCRIBE

需要

UNSUBACK

需要

PINGREQ

不需要

PINGRESP

不需要

DISCONNECT

不需要

        PUBACK, PUBREC, PUBREL报文必须包含与最初发送的PUBLISH报文相同的报文标识符,以此来标识是同一条信息如果一个客户端要重发这个特殊的控制报文,在随后重发那个报文时,它必须使用相同的标识符。

         当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。QoS 1的PUBLISH对应的是PUBACK,QoS 2的PUBLISH对应的是PUBCOMP

有效载荷 Payload

        有效载荷是除控制报文格式以外的有效信息,CONNECT、PUBLISH、SUBSCRIBE等需要传递有效信息的协议帧都需要。

控制报文

有效载荷

CONNECT

需要

CONNACK

不需要

PUBLISH

可选

PUBACK

不需要

PUBREC

不需要

PUBREL

不需要

PUBCOMP

不需要

SUBSCRIBE

需要

SUBACK

需要

UNSUBSCRIBE

需要

UNSUBACK

不需要

PINGREQ

不需要

PINGRESP

不需要

DISCONNECT

不需要

协议格式讲解

        MQTT报文格式参考文档:mqtt.v3.1.1

        MQTT客户端连接服务器流程图

 CONNECT报文

        CONNECT 协议是客户端建立连接的第一个报文,通常都要带有鉴权的字段,一个CONNECT报文都会对应一个服务端的CONNACK报文。

        得到CONNECT报文如下:

#16进制表示
102C00044D51545404C2003C000A636C69656E7469642F31000A757365726E616D652F31000870617373776F7264
 
#固定报头(剩余长度44个字节)
10 2C
#可变报头
00 04 4D 51 54 54 04 C2 00 3C
#余下为有效载荷字段
#客户端标识符(000A 表示长度为10个字节, 文本内容为 "clientid/1")
00 0A 63 6C 69 65 6E 74 69 64 2F 31
#遗嘱主题、遗嘱消息为启用,所以没有
#用户名(000A 表示长度为10个字节, 文本内容为 "username/1")
00 0A 75 73 65 72 6E 61 6D 65 2F 31
#密码(0008 表示长度为8个字节, 文本内容为 "password")
00 08 70 61 73 73 77 6F 72 64

        可变报头非规范示例

 PUBLISH报文

        PUBLISH是发布消息协议报文,双向都可以使用。

         得到PUBLISH报文如下:

#16进制表示
32100005746F70696300016D657373616765
#固定报头(qos1消息,非重传、非保留,剩余长度16个字节)
32 10
可变报头(5个字节的主题"topic",报文标识符为1,)
00 05 74 6F 70 69 63 00 01
#有效载荷("message")
6D 65 73 73 61 67 65

SUBSCRIBE报文

        客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。

         得到SUBSCRIBE报文如下:

#16进制表示
820A00010005746F70696300
#固定报头(剩余长度10个字节)
82 0A
#可变报头(报文标识符为1)
00 01
#有效载荷(长度为5个字节,topicfilter为 "topic", qos 为0)
00 05 74 6F 70 69 63 00

DISCONNECT报文

        DISCONNECT报文是客户端发给服务端的最后一个控制报文。表示客户端正常断开连接。

        得到DISCONNECT报文如下: 

#16进制表示
E0 00

硬件准备及接线方式

 硬件准备

  1. W5100S-EVB-Pico开发板或/W5100SIO模块+树莓派RP2040
  2. 数据线、网线
  3. 路由器
  4. pc

接线方式(W5100SIO模块+树莓派RP2040

  • W5100SIO_MISO->RP2040_GPIO16
  • W5100SIO_MOSI->RP2040_GPIO19
  • W5100SIO_CS->RP2040_GPIO17
  • W5100SIO_SCK->RP2040_GPIO18
  • W5100SIO_RST->RP2040_GPIO20

测试

MQTT测试流程图

相关代码

        我们打开例程中库文件的mqttx_client.c文件用到如下所示几个函数:mqtt_init是对mqtt的信息进行初始化,把配置信息填入;messageArrived函数主要作用是讲发布和订阅的信息进行判断打印keep_alive函数是一个心跳包,如果超过设定值没有发送心跳包就进行mqtt_init函数初始化。

void mqtt_init(void)
{
    int ret;

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    NewNetwork(&n, 1);
    ConnectNetwork(&n, mqtt_params.server_ip, 1883);
    MQTTClientInit(&c, &n, 1000, mqtt_send_buff, MQTT_SEND_BUFF_SIZE, mqtt_recv_buff, MQTT_RECV_BUFF_SIZE);
    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.clientID.cstring = mqtt_params.clientid;
    data.username.cstring = mqtt_params.username;
    data.password.cstring = mqtt_params.passwd;
    data.keepAliveInterval = 30;
    data.cleansession = 1;
    connOK = MQTTConnect(&c, &data);
    printf("Connected:%s\r\n", connOK == 0 ? "success" : "failed");
    printf("Subscribing to %s\r\n", mqtt_params.subtopic1);
    ret = MQTTSubscribe(&c, mqtt_params.subtopic1, mqtt_params.QOS, messageArrived);
    printf("Subscribed:%s\r\n", ret == 0 ? "success" : "failed");
   
    sleep_ms(300);
    MQTTMessage pubmessage={
        .qos=QOS2,
        .dup=0,
        .retained=0,
        .id=0,
    };
    pubmessage.payload="hello mqtt!\r\n";
    pubmessage.payloadlen=strlen(pubmessage.payload);
    MQTTPublish(&c,mqtt_params.pubtopic,&pubmessage);
}
void messageArrived(MessageData* md)
{
    unsigned char messagebuffer[512];
    MQTTMessage* message = md->message;
    if (mqtt_params.QOS)
    {
        memcpy(messagebuffer,(char*)message->payload,(int)message->payloadlen);
        *(messagebuffer + (int)message->payloadlen + 1) = '\n';
        printf("%s\r\n",messagebuffer);
    }
    if (mqtt_params.QOS)
        printf("%.*s", (int)message->payloadlen, (char*)message->payload);
    else
        printf("%s%.*s%s%s", "RX:",(int)message->payloadlen, (char*)message->payload, mqtt_params.QOS,"\r\n");
}
void keep_alive(void)
{
    if (!connOK)
    {
        if (MQTTYield(&c, 30))
        {
            mqtt_init();
        }
    }
}

        网络配置信息和之前的一样,还多加了mqtt的连接参数,其中的参数主要包括服务器ip,端口号,客户端id,用户名和密码(由于是本地测试,可以不需要设置用户名和密码)然后就是发布和订阅消息(必须和服务器上的一致)然后是QOS等级设置。

#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

#define MQTT_SEND_BUFF_SIZE 2048
#define MQTT_RECV_BUFF_SIZE 2048
uint8_t mqtt_send_buff[MQTT_SEND_BUFF_SIZE] = {0};
uint8_t mqtt_recv_buff[MQTT_RECV_BUFF_SIZE] = {0};
typedef struct MQTTCONNECTION
{
    char mqttHostUrl[1024];
    int port;
    char clientid[1024];
    char username[1024];
    char passwd[1024];
    uint8_t server_ip[4];
    char pubtopic[255];
    char subtopic1[255];
    int QOS;
} mqttconn;
mqttconn mqtt_params = {
    .server_ip = {54,244,173,190},
    .port = 1883,
    .clientid = "9a1d7719a8ac40d29311f26c5c5469dc",
    .username = "mqtt_username",
    .passwd = "123456",
    .pubtopic = "1234",
    .subtopic1 = "2345",
    .QOS = 0,
};
unsigned char *data_ptr = NULL;
void network_init(void);
wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e},
    .ip = {192, 168, 124, 10},
    .sn = {255, 255, 255, 0},
    .gw = {192, 168, 124, 1},
    .dns = {8, 8, 8, 8},
    .dhcp = NETINFO_STATIC};
MQTTClient c = {0};
Network n = {0};
int connOK;
bool repeating_timer_callback(struct repeating_timer *t);
void mqtt_init(void);
void messageArrived(MessageData *md);
void keep_alive(void);
wiz_NetInfo get_info;
static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {0,};
static uint8_t destip[4]={192, 168, 124, 1};
static uint16_t destport = 8080;
static uint16_t local_port =8000;
int main()                                                          
{   
    struct repeating_timer timer;
    stdio_init_all();
    sleep_ms(2000);
    wizchip_initialize();
    wizchip_setnetinfo(&net_info);
    print_network_information(net_info);
    add_repeating_timer_ms(1, repeating_timer_callback, NULL, &timer);
    mqtt_init();
    while(true)
    {
        // loopback_udpc(SOCKET_ID, ethernet_buf, destip, destport);
        keep_alive();
        sleep_ms(10);
    }
    
}
bool repeating_timer_callback(struct repeating_timer *t)
{
    MilliTimer_Handler();
    return true;
}

        打开MQTTX工具信息配置好mqtt的信息。


        订阅和发布(对应代码上的订阅与发布信息)。

测试现象

        我们可以看到串口打印信息中打印了网络连接上且配置好网络信息,最后连接上了mqttx上的mqtt公共服务器。

        打开mqttx可以到由W5100S_EVB_PICO发来的“hello mqtt”,表示订阅成功。

        用mqttx切换到发布消息,将信息发送给W5100S_EVB_PICO。

        最后可以看到串口打印了mqttx下发的消息,表示发布成功。

相关链接: 

        本章例程链接:mqtt_cliten example

        感谢大家的观看,对本例程有任何不清楚的地方或者想对产品有更多的了解可以私信或者在评论区留言,我们看到会及时回复您!下章为大家带来mqtt协议连接阿里云的讲解

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
毕设新项目基于python3.7+django+sqlite开发的学生就业管理系统源码+使用说明(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 学生就业管理系统(前端) ## 项目开发环境 - IDE: vscode - node版本: v12.14.1 - npm版本: 6.13.4 - vue版本: @vue/cli 4.1.2 - 操作系统: UOS 20 ## 1.进入项目目录安装依赖 ``` npm install ``` ## 2.命令行执行进入UI界面进行项目管理 ``` vue ui ``` ## 3.编译发布包(请注意编译后存储路径) #### PS:需要将编译后的包复制到后端项目的根目录下并命名为'static' 学生就业管理系统(后端) ## 1.项目开发环境 - IDE: vscode - Django版本: 3.0.3 - Python版本: python3.7.3 - 数据库 : sqlite3(测试专用) - 操作系统 : UOS 20 ## 2.csdn下载本项目并生成/安装依赖 ``` pip freeze > requirements.txt pip install -r requirements.txt ``` ## 3.项目MySQL数据库链接错误 [点击查看解决方法](https://www.cnblogs.com/izbw/p/11279237.html)
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值