mqtt学习入门与全栈认识提高

目录

  • mqtt认识
    • mqtt 简介
    • mqtt协议
      • 协议版本
      • 5.0新增特点
      • 特点概括
      • MQTT协议实现方式
      • MQTT客户端
      • MQTT服务器
      • MQTT协议中的订阅、主题、会话
      • MQTT协议中的方法
      • 协议流程与消息类型
      • 服务质量
    • mqtt 与tcp 关系
  • 硬件开发MQTT
    • STM32(GD32) mqtt
      • 4G通信模组
      • 2G通信模块
    • nodemcu
    • arduino
    • 树莓派
  • 平台(物联网平台)开发
    • 开源平台
    • 开发者使用平台
    • 商用平台
    • 代理平台
    • 物联网平台架构
  • 参考文献

mqtt认识

mqtt是什么
mqtt 协议是什么,有什么特殊之处
mqtt是谁创建的,提出的背景是什么
mqtt模块是什么
mqtt网关是什么
mqtt标准协议如何应用?
mqtt 到硬件能做哪些?到软件又可以做哪些?
mqtt 安全吗
mqtt 是主流吗
mqtt wifi tcp coap nodemcu esp8266 都是什么鬼,头大了呀。
emq kafka rabbitmq emqx 都是啥????

mqtt 简介

MQTT(消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议,为此,它需要一个消息中间件 。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。

mqtt协议

协议版本

(1)3.1.1 版本
Latest version:
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.doc (Authoritative)
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.pdf
(2)5.0版本
Latest version:
http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.docx (Authoritative)
http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
http://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.pdf
(3)中文版
中文版本

github 有人在翻译中文

5.0新增特点

MQTT v5.0现在成为了OASIS官方标准
OASIS现在已经发布了官方的MQTT v5.0标准 - 这对于已经为物联网(IoT)所用的消息传输协议来说,这是一个改进和功能的巨大飞跃。基于早期的v3.1.1标准,它具有重要的更新,同时最大限度地减少与现有版本的不兼容性。

新版本的亮点包括:

更好的错误报告 - 特别是,在发布的响应中添加了原因代码(PUBACK / PUBREC)。MQTT起源于输油管道沿线的传感器等使用案例 - 如果它们的消息发布未能传输,则传感器将不采取任何措施。然而,MQTT的用例现在要广泛得多,如果数据没有成功传输,手机上的应用程序可能会想要警告用户。返回代码现在出现在所有确认中(以及包含人类可读错误诊断的可选原因字符串)。
共享订阅 - 如果订阅上的消息速率很高,则可以使用共享订阅在多个接收客户端之间对消息进行负载平衡。
消息属性 - 消息标题中的元数据。这些用于实现此列表中的其他功能,但也允许用户定义的属性,例如通过告知接收方使用哪个密钥来解密消息内容来协助消息加密
消息过期 - 如果消息无法在用户定义的时间段内传递,则可以选择丢弃消息。
会话到期 - 如果客户端未在用户定义的时间段内连接,则可以丢弃状态(例如,订阅和缓冲的消息)而无需进行清理。
主题别名 - 允许将消息中的主题字符串替换为单个数字,从而减少发布者重复使用相同主题时需要传输的字节数。
Will Delay - 如果客户端断开连接的时间超过用户定义的时间段, 则允许发布消息。允许有关重要客户端应用程序中断的通知, 而不会被误报淹没。
允许的功能发现 - 在连接开始时,可​​以传输最大数据包大小和(QoS> 0)消息的数量限制,以通知客户端允许执行的操作。

特点概括

a.由于采用发布/订阅的消息模式,可以提供一对多的消息发布
b.轻量级,网络开销小,降低传输流量。
c.对负载内容会有屏蔽的消息传输
d.有三种消息发布质量(Qos):
qos=0:“至多一次”,这一级别会发生消息丢失或重复,消息发布依赖于TCP/IP网络
qos=1:“至少一次”,确保消息到达,但消息重复可能会发生
qos=2:“只有一次”,确保消息到达一次
e.通知机制,异常中断时会通知双方
f.安全机制,http 有htpps,mqtt 有tls
g.lwt 遗嘱机制
h

MQTT协议实现方式

实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
mqtt学习入门与全栈认识提高_第1张图片

MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:

(1)Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload);
(2)payload,可以理解为消息的内容,是指订阅者具体要使用的内容。
4.2 网络传输与应用消息
MQTT会构建底层网络传输:它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。

当应用数据通过MQTT网络发送时,MQTT会把与之相关的服务质量(QoS)和主题名(Topic)相关连。

MQTT客户端

一个使用MQTT协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:

(1)发布其他客户端可能会订阅的信息;
(2)订阅其它客户端发布的消息;
(3)退订或删除应用程序的消息;
(4)断开与服务器连接。

MQTT服务器

MQTT服务器以称为"消息代理"(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:

(1)接受来自客户的网络连接;
(2)接受客户发布的应用信息;
(3)处理来自客户端的订阅和退订请求;
(4)向订阅的客户转发应用程序消息。

MQTT协议中的订阅、主题、会话

(1)订阅(Subscription)
订阅包含主题筛选器(Topic Filter)和最大服务质量(QoS)。订阅会与一个会话(Session)关联。一个会话可以包含多个订阅。每一个会话中的每个订阅都有一个不同的主题筛选器。
(2)会话(Session)
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互。会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接。
(3)主题名(Topic Name)
连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配。服务器会将消息发送给订阅所匹配标签的每个客户端。
(4)主题筛选器(Topic Filter)
一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题。
(5)负载(Payload)
消息订阅者所具体接收的内容。

MQTT协议中的方法

MQTT协议中定义了一些方法(也被称为动作),来于表示对确定资源所进行操作。这个资源可以代表预先存在的数据或动态生成数据,这取决于服务器的实现。通常来说,资源指服务器上的文件或输出。主要方法有:

(1)Connect。等待与服务器建立连接。
(2)Disconnect。等待MQTT客户端完成所做的工作,并与服务器断开TCP/IP会话。
(3)Subscribe。等待完成订阅。
(4)UnSubscribe。等待服务器取消客户端的一个或多个topics订阅。
(5)Publish。MQTT客户端发送消息请求,发送完成后返回应用程序线程。

协议流程与消息类型

mqtt学习入门与全栈认识提高_第2张图片
MQTT拥有14种不同的消息类型:

CONNECT:客户端连接到MQTT代理
CONNACK:连接确认
PUBLISH:新发布消息
PUBACK:新发布消息确认,是QoS 1给PUBLISH消息的回复
PUBREC:QoS 2消息流的第一部分,表示消息发布已记录
PUBREL:QoS 2消息流的第二部分,表示消息发布已释放
PUBCOMP:QoS 2消息流的第三部分,表示消息发布完成
SUBSCRIBE:客户端订阅某个主题
SUBACK:对于SUBSCRIBE消息的确认
UNSUBSCRIBE:客户端终止订阅的消息
UNSUBACK:对于UNSUBSCRIBE消息的确认
PINGREQ:心跳
PINGRESP:确认心跳
DISCONNECT:客户端终止连接前优雅地通知MQTT代理

服务质量

为了满足不同的场景,MQTT支持三种不同级别的服务质量(Quality of Service,QoS)为不同场景提供消息可靠性:

级别0:尽力而为。消息发送者会想尽办法发送消息,但是遇到意外并不会重试。
级别1:至少一次。消息接收者如果没有知会或者知会本身丢失,消息发送者会再次发送以保证消息接收者至少会收到一次,当然可能造成重复消息。
级别2:恰好一次。保证这种语义肯待会减少并发或者增加延时,不过丢失或者重复消息是不可接受的时候,级别2是最合适的。
服务质量说明:
级别2所提供的不重不丢很多情况下是最理想的,不过往返多次的确认一定对并发和延迟带来影响。
级别1提供的至少一次语义在日志处理这种场景下是完全OK的,所以像Kafka这类的系统利用这一特点减少确认从而大大提高了并发。
级别0适合鸡肋数据场景,食之无味弃之可惜,就这么着吧。

mqtt 与tcp 关系

mqtt学习入门与全栈认识提高_第3张图片
mqtt学习入门与全栈认识提高_第4张图片
mqtt学习入门与全栈认识提高_第5张图片

假设,一个蔬菜工厂有200个大棚,都需要照明。现在老板一个APP就能控制整个蔬菜工厂的200多个大棚内的照明。
用tcp的socket 也可以实现,但是用mqtt broker 就很简单

mqtt学习入门与全栈认识提高_第6张图片

硬件开发MQTT

STM32(GD32) mqtt

mqtt学习入门与全栈认识提高_第7张图片

个人建议,选择一款主流的通信模块做方案,标准化aa.c 作为标准库

4G通信模组

EC20+oneNet
mqtt学习入门与全栈认识提高_第8张图片
Air724模块(合宙模块)
内置MQTT协议,提供AT,LUAT,CSDK,DTU可供选择使用,接口简单使用方便。
mqtt学习入门与全栈认识提高_第9张图片
mqtt学习入门与全栈认识提高_第10张图片
资料链接:http://wiki.yinerda.com/index.php/YED-C724

2G通信模块

安信可A9 GPRS 模块
单片机通过GPRS模块利用MQTT协议上报设备数据流程

SIM900A
gprs模块用TCP实现MQTT协议(基于SIM900A)

 
int strlen(char *str)
{
    int len = 0;
    while (*str != '\0') {
        len++;
        str++;
    }
    return len;
}
 
// **********************************
// *                                *
// * 根据主机地址和端口号连接服务器 *
// *                                *
// **********************************
 
 
void tcp_connect(char *host,int port)
{
   uart_send_str("AT\r\n");
   uart_send_str("AT+CPIN? \r\n");
   seelp(500);
   uart_send_str("AT+CREG? \r\n");
   seelp(500);
   uart_send_str("AT+CGATT? \r\n");
   seelp(500);
   uart_send_str("AT+CSTT=\"CMNET\" \r\n");
   seelp(500);
   uart_send_str("AT+CIICR \r\n");
   seelp(1500);
   uart_send_str("AT+CIFSR \r\n");
   seelp(1000);
   uart_send_str("AT+CIPSTART=\"TCP\"\,\"23.106.139.167\"\,\"1883\" \r\n"); //连接TCP Server  8081 1883
}
 
 
// *************************
// *                       *
// *  构建MQTT连接包       *
// *                       *
// *************************
 
int baseIndex;
int mqtt_connect_message(unsigned char *mqtt_message,char *client_id,char *username,char *password)
{ 
    char i = 0;  
    char client_id_length = strlen(client_id);  
    int username_length = strlen(username);  
    int password_length = strlen(password);  
    int packetLen = 12 + 2 + client_id_length + 2 + username_length + 2 + password_length;  
      
    mqtt_message[0] = 16;                      // MQTT Message Type CONNECT  
    mqtt_message[1] = packetLen%256;  
    baseIndex = 2;  
    if( packetLen >127 ){//  
        mqtt_message[2] = 1;//packetLen/127;  
        baseIndex = 3;  
    }  
      
      
    mqtt_message[baseIndex] = 0;                       // Protocol Name Length MSB  
    mqtt_message[baseIndex+1] = 6;                       // Protocol Name Length LSB  
    mqtt_message[baseIndex+2] = 77;                      // ASCII Code for M  
    mqtt_message[baseIndex+3] = 81;                      // ASCII Code for Q  
    mqtt_message[baseIndex+4] = 73;                      // ASCII Code for I  
    mqtt_message[baseIndex+5] = 115;                     // ASCII Code for s  
    mqtt_message[baseIndex+6] = 100;                     // ASCII Code for d  
    mqtt_message[baseIndex+7] = 112;                     // ASCII Code for p  
    mqtt_message[baseIndex+8] = 3;                      // MQTT Protocol version = 3  
    mqtt_message[baseIndex+9] = 194;                   // conn flags  
    mqtt_message[baseIndex+10] = 0;                      // Keep-alive Time Length MSB  
    mqtt_message[baseIndex+11] = 60;                     // Keep-alive Time Length LSB  
      
    mqtt_message[baseIndex+12] = 0;                      // Client ID length MSB  
    mqtt_message[baseIndex+13] = client_id_length;       // Client ID length LSB  
      
    baseIndex += 14;  
    // Client ID  
    for(i = 0; i < client_id_length; i++){  
        mqtt_message[baseIndex + i] = client_id[i];  
    }  
      
    baseIndex = baseIndex+client_id_length;  
      
    //username  
    mqtt_message[baseIndex] = 0;                      //username length MSB  
    mqtt_message[baseIndex+1] = username_length;       //username length LSB  
    baseIndex = baseIndex+2;  
    for(i = 0; i < username_length ; i++){  
        mqtt_message[baseIndex + i] = username[i];  
    }  
      
    baseIndex = baseIndex + username_length;  
      
    //password  
    mqtt_message[baseIndex] = 0;                      //password length MSB  
    mqtt_message[baseIndex+1] = password_length;       //password length LSB  
    baseIndex = baseIndex + 2;  
    for(i = 0; i < password_length ; i++){  
        mqtt_message[baseIndex + i] = password[i];  
    }  
      
    baseIndex += password_length;  
  
    return baseIndex;  
}
 
 
int mqtt_publish_message(unsigned char *mqtt_message, char * topic, char * message) {  
      
    //mqtt_message = 0;  
      
    unsigned char i = 0;  
    unsigned char topic_length = strlen(topic);  
    unsigned char message_length = strlen(message);  
      
    mqtt_message[0] = 48;                                  // MQTT Message Type CONNECT  
    mqtt_message[1] = 2 + topic_length + message_length;   // Remaining length  
    mqtt_message[2] = 0;                                   // MQTT Message Type CONNECT  
    mqtt_message[3] = topic_length;                        // MQTT Message Type CONNECT  
      
    // Topic  
    for(i = 0; i < topic_length; i++){  
        mqtt_message[4 + i] = topic[i];  
    }  
      
    // Message  
    for(i = 0; i < message_length; i++){  
        mqtt_message[4 + topic_length + i] = message[i];  
    }  
      
    return 4 + topic_length + message_length;  
}  
 
 
int subindex = 0;
int mqtt_subscribe_message(unsigned char *mqtt_message,unsigned char *topic)  
{  
    unsigned char topic_len = strlen(topic);  
    mqtt_message[0] = 130;  
    mqtt_message[1] = topic_len+5;  
    mqtt_message[2] = 0;  
    mqtt_message[3] = 1;  
    mqtt_message[4] = 0;  
    mqtt_message[5] = topic_len;  
 
    for (subindex=0; subindex

nodemcu

mqtt 控制电灯
智能wifi 插座
mqtt学习入门与全栈认识提高_第11张图片
mqtt学习入门与全栈认识提高_第12张图片
mqtt学习入门与全栈认识提高_第13张图片

智能网关等

案例见本人“少儿编程”专栏

arduino

读码模块+Arduino+MQTT——实现网络数据传输并更新到数据库
github arduino 支持库

树莓派

稍后跟新

平台(物联网平台)开发

开源平台

thingsboard
ZLINKER物联网平台
Groza - 开源物联网平台1
Groza - 开源物联网平台2
awesome-iot

开发者使用平台

乐为物联
奥特美克 all-iot
点灯科技

商用平台

阿里云
华为云
电信 ctwing
移动oneNET
奥特美克 all-iot

代理平台

目前MQTT代理的主流平台有下面几个:
Mosquitto:https://mosquitto.org/
VerneMQ:https://vernemq.com/
EMQTT:http://emqtt.io/

物联网平台架构

见本人专栏

参考文献

mqtt 协议流程图
https://blog.p2hp.com/archives/4100

简介与使用
https://www.jianshu.com/p/a371c6ac076b
mqtt 入门
https://zhuanlan.zhihu.com/p/20888181

MQTT 入门介绍
https://www.runoob.com/w3cnote/mqtt-intro.html
tcp 与mqtt 区别
https://www.zhihu.com/question/23373904
一篇文章让您了解MQTT
https://www.jianshu.com/p/de88edf8e023

你可能感兴趣的