嵌入式物联网协议--MQTT

2023-11-19

本文使用MQTT-3.1.1版本

 

目录

一.MQTT简介

1.什么是MQTT

2.MQTT本质

3.MQTT报文类型

4.MQTT Qos质量

二.14个报文详解

1.CONNECT报文(1 C->S  固定报头+可变报头+负载)

1)固定报头:

2)可变报头:

3)有效载荷(clientID长度+clientID数据+username长度+username数据+password长度+password数据)

2.CONNACK报文(2  S->C 固定报头+可变报头)

1)固定报头(0x20+剩余长度(02))

2)可变报头(连接确认标志+连接返回码)

3.DISCONNECT报文(14 C->S 固定报头)

1).固定报头(E0 00)

4.PING报文(12 C->S 固定报头)

1)固定报头(C0 00)

5.PINGRSP报文(13 S->C 固定报头)

1)固定报头(D0 00)

6.SUBSCRIBE报文(8 C->S 固定报头+可变报头+负载)

1)固定报头(0x82+剩余长度)

2)可变报头(00 0A)

3)负载(Topic)

7.SUBACK报文(9 S->C 固定报头+可变报头+负载)

1)固定报头(0x90 + 剩余长度)

2)可变报头(00 0A)

3)负载

8.UNSUBSCRIBE报文(10 C->S 固定报头+可变报头+负载)

1)固定报头(0xA2 +剩余长度)

2)可变报头(00 0A)

3)负载

9.UNSUBACK报文(11 S->C 固定报头+可变报头)

1)固定报头(B0 02)

2)可变报头(00 0A)

10.PUBLISH报文(3  S<=>C 固定报头+可变报头+负载)

2)可变报头

3)负载

4)响应

11.PUBACK报文(4  S<=>C 固定报头+可变报头  QoS1)

1)固定报头(40 02)

2)可变报头

12.PUBREC报文(5  S<=>C 固定报头+可变报头  QoS2 第一步)

1)固定报头(50 02 )

2)可变报头

13.PUBREC报文(6  S<=>C 固定报头+可变报头  QoS2 第二步)

1)固定报头( 62 02)

2)可变报头

14.PUBCOMP报文(7  S<=>C 固定报头+可变报头  QoS2 第三步)

1)固定报头( 70 02)

​2)可变报头


一.MQTT简介

1.什么是MQTT

MQTT 是一个客户端服务端架构的发布/订阅模式的消息传输协议。 它的设计思想是轻巧、 开放、简单、 规范, 因此易于实现。这些特点使得它对很多场景来说都是很好的选择, 包括受限的环境如机器与机器的通信( M2M)以及物联网环境( IoT) , 这些场景要求很小的代码封装或者网络带宽非常昂贵。本协议运行在 TCP/IP,或其它提供了有序、可靠、 双向连接的网络连接上。 它有以下特点:

  1.  使用发布/订阅消息模式,提供了一对多的消息分发和应用之间的解耦。
  2.  消息传输不需要知道负载内容。
  3.  提供三种等级的服务质量: .
  4.  “最多一次”,尽操作环境所能提供的最大努力分发消息。 消息可能会丢失。 例如, 这个等级可用于环境传感器数据,单次的数据丢失没关系, 因为不久之后会再次发送。
  5.  “至少一次”,保证消息可以到达, 但是可能会重复。
  6.  “仅一次”, 保证消息只到达一次。 例如, 这个等级可用在一个计费系统中, 这里如果消息重复或丢失会导致不正确的收费。
  7.  很小的传输消耗和协议数据交换,最大限度减少网络流量
  8.  异常连接断开发生时, 能通知到相关各方。

2.MQTT本质

MQTT是基于TOPIC的订阅与发布,与谁通信就先订阅谁(并不是订阅服务器,服务器是将消息进行转发),服务器会进行推送发布消息 

3.MQTT报文类型

4.MQTT Qos质量

QoS 是消息的发送方( Sender)和接受方( Receiver)之间达成的一个协议:
QoS 0 代表, Sender 发送的一条消息, Receiver 最多能收到一次,也就是说 Sender 尽力向 Receiver 发送消息,如果发送失败,也就算了;
QoS 1 代表, Sender 发送的一条消息, Receiver 至少能收到一次,也就是说 Sender 向 Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,但是因为重传的原因, Receiver 有可能会收到重复的消息;
QoS 2 代表, Sender 发送的一条消息, Receiver 确保能收到而且只收到一次,也就是说 Sender 尽力向Receiver 发送消息,如果发送失败,会继续重试,直到 Receiver 收到消息为止,同时保证 Receiver 不会因为消息重传而收到重复的消息。
注:当前主流服务器应用MQTT采用的协议等级大都是0,1。 Qos2太消耗带宽。

 

二.14个报文详解

1.CONNECT报文(1 C->S  固定报头+可变报头+负载)

1)固定报头:

  • 字节1:10
  • 字节2: 剩余长度值。对于小于128的值采用单字节编码。更大的值按下面的方式处理。低 7 位有效位用于编码数据, 最高有效位用于指示是否有更多的字节。 因此每个字节可以编码 128 个数值和一个延续位( continuation bit)。剩余长度字段最大 4 个字节。

MQTT 为了传输数据量减少、避免浪费数据流量,使用了变长编码方式;变长编码规则如下:

 

假设数据长度:200,第一个字节最大值为 127,对于 200 是一定放不下的,根据上表可知需要两个字节;发送数据结构如下

当超过128字节的时候,第一个字节表示128的整数倍,第二个字节因为使用了,所以最高位填1.剩余长度转换为16进制后7位数加上最高位1,最终长度是:0x c8 01(代表1个128)

2)可变报头:

CONNECT 报文的可变报头按下列次序包含四个字段:协议名( Protocol Name),协议级别rotocolLevel) ,连接标志( Connect Flags)和保持连接( Keep Alive)。

  • 协议名
  • 协议级别

客户端用 8 位的无符号值表示协议的修订版本。对于 3.1.1 版协议,协议级别字段的值是 4(0x04)。 如果发现不支持的协议级别, 服务端必须给发送一个返回码为 0x01(不支持的协议级别) 的 CONNACK 报文响应CONNECT 报文, 然后断开客户端的连接 [MQTT-3.1.2-2]。

  • 连接标志

  • 保活连接

保持连接( Keep Alive) (保活包) 是一个以秒为单位的时间间隔,表示为一个 16 位的字,它是指在客户端传输完成一个控制报文的时刻到发送下一个报文的时刻, 两者之间允许空闲的最大时间间隔。 客户端负责保证控制报文发送的时间间隔不超过保持连接的值。 如果没有任何其它的控制报文可以发送, 客户端必须发送一个 PINGREQ 报文。

3)有效载荷(clientID长度+clientID数据+username长度+username数据+password长度+password数据)

DEVICENAME:LED_CONTROL                      

PRODUCTKEY:a1U1OR0WIlM

  • clientID:LED_CONTROL|securemode=3,signmethod=hmacsha1|
  • 16进制clientID(45):00 2D 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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
  • username:LED_CONTROL&a1U1OR0WIlM
  • 16进制username(23):00 17 4C 45 44 5F 43 4F 4E 54 52 4F 4C 26 61 31 55 31 4F 52 30 57 49 6C 4D
  • password

哈希加密之前:clientIdLED_CONTROLdeviceNameLED_CONTROLproductKeya1U1OR0WIlM    加密网址

设备秘钥:XvCiVzzpEooo4mj0EqwJRSUsOihnevri

哈希加密之后:fe205fdd687b474ea68da04a76ffe852f1f5ec41

16进制password(40):00 28 66 65 32 30 35 66 64 64 36 38 37 62 34 37 34 65 61 36 38 64 61 30 34 61 37 36 66 66 65 38 35 32 66 31 66 35 65 63 34 31

 

 

发送connect报文: 10 7C 00 04 4D 51 54 54 04 C2 00 64 00 2D 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 17 4C 45 44 5F 43 4F 4E 54 52 4F 4C 26 61 31 55 31 4F 52 30 57 49 6C 4D 00 28 66 65 32 30 35 66 64 64 36 38 37 62 34 37 34 65 61 36 38 64 61 30 34 61 37 36 66 66 65 38 35 32 66 31 66 35 65 63 34 31

红:固定字节

黄:剩余长度

绿:可变报头10字节数据

黑:有效载荷

2.CONNACK报文(2  S->C 固定报头+可变报头)

服务器返回:0x20 02 00 00

1)固定报头(0x20+剩余长度(02))

2)可变报头(连接确认标志+连接返回码)

  • 字节1:连接确认标志, 位 7-1 是保留位且必须设置为 0。第 0 (SP)位 是当前会话( Session Present) 标志
  • 字节2:连接返回码

 

3.DISCONNECT报文(14 C->S 固定报头)

1).固定报头(E0 00)

  • 字节1:0xE0
  • 字节2:0x00

服务器无返回

4.PING报文(12 C->S 固定报头)

1)固定报头(C0 00)

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

  • 字节1:0xC0
  • 字节2:0x00  

5.PINGRSP报文(13 S->C 固定报头)

1)固定报头(D0 00)

  • 字节1:D0
  • 字节2:00

6.SUBSCRIBE报文(8 C->S 固定报头+可变报头+负载)

客户端向服务端发送 SUBSCRIBE 报文用于创建一个或多个订阅。 每个订阅注册客户端关心的一个或多个主题。 为了将应用消息转发给与那些订阅匹配的主题, 服务端发送 PUBLISH 报文给客户端。 SUBSCRIBE报文也(为每个订阅) 指定了最大的 QoS 等级, 服务端根据这个发送应用消息给客户端。(订阅报文就相当于关注up主)

1)固定报头(0x82+剩余长度)

2)可变报头(00 0A)

3)负载(Topic)

SUBSCRIBE 报文的有效载荷包含了一个主题过滤器列表, 它们表示客户端想要订阅的主题。每一个过滤器后面跟着一个字节, 这个字节被叫做服务质量要求( Requested QoS) 。它给出了服务端向客户端发送应用消息所允许的最大 QoS 等级。

主题过滤器就是订阅谁,位置在阿里云设备 Topic 列表中→物模型通信 Topic 列表:

注:MQTT-3.1.1没有用到 服务质量要求( Requested QoS) 字节的高六位。

 

固定报头:82 xx

可变报头:00 0A

TOPIC:/sys/a1U1OR0WIlM/LED_CONTROL/thing/service/property/set

TOPIC(二进制 55):2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 37 2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 

Qos:00或者01或者02

发送subscribe报文:82 3C 00 0A 00 37 2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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

7.SUBACK报文(9 S->C 固定报头+可变报头+负载)

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

1)固定报头(0x90 + 剩余长度)

2)可变报头(00 0A)

描述了订阅的可变报头的标识符,以上述订阅报文可变报头为例,就是00 0A

3)负载

有效载荷包含一个返回码清单。 每个返回码对应等待确认的 SUBSCRIBE 报文中的一个主题过滤器。返回码的顺序必须和 SUBSCRIBE 报文中主题过滤器的顺序相同。

8.UNSUBSCRIBE报文(10 C->S 固定报头+可变报头+负载)

1)固定报头(0xA2 +剩余长度)

剩余长度:等于可变报头的长度加上有效载荷的长度

2)可变报头(00 0A)

是订阅的报文标识符

3)负载

UNSUBSCRIBE 报文的有效载荷包含客户端想要取消订阅的主题过滤器列表。 UNSUBSCRIBE 报文中的主题过滤器必须是连续打包的。UNSUBSCRIBE 报文的有效载荷必须至少包含一个消息过滤器。

固定报头:A2 xx
可变报头:00 0A

TOPIC:/sys/a1U1OR0WIlM/LED_CONTROL/thing/service/property/set
TOPIC(二进制 55):2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 
UNsubscribe:A2 3B 00 0A 00 37 2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 

9.UNSUBACK报文(11 S->C 固定报头+可变报头)

1)固定报头(B0 02)

2)可变报头(00 0A)

       UNSUBSCRIBE的 报文标识符

10.PUBLISH报文(3  S<=>C 固定报头+可变报头+负载)

PUBLISH 控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息。

1)固定报头

位3:如果 DUP 标志被设置为 0, 表示这是客户端或服务端第一次请求发送这个 PUBLISH 报文。 如果 DUP标志被设置为 1,表示这可能是一个早期报文请求的重发。客户端或服务端请求重发一个 PUBLISH 报文时, 必须将 DUP 标志设置为 1。

但是:对于 QoS0 的消息, DUP 标志必须设置为 0

位0:如果客户端发给服务端的 PUBLISH 报文的保留标志位 0,服务端不能存储这个消息也不能移除或替换任何现存的保留消息。

综上,固定报头:0x30 ??

2)可变报头

主题名:主题名( Topic Name) 用于识别有效载荷数据应该被发布到哪一个信息通道---------------->  /sys/a1U1OR0WIlM/LED_CONTROL/thing/event/property/post
报文标识符:只有当 QoS 等级是 1 或 2 时,报文标识符( Packet Identifier) 字段才能出现在 PUBLISH 报文中。

3)负载

有效载荷包含将被发布的应用消息。 数据的内容和格式是应用特定的。 有效载荷的长度这样计算: 用固定报头中的剩余长度字段的值减去可变报头的长度。 包含零长度有效载荷的 PUBLISH 报文是合法的。

有效载荷是一个json数据格式,对于event事件,如下:

"events": [
{
"identifier": "post", “属性”:”值”
"name": "post",
"type": "info",
"required": true,
"desc": "属性上报",
"method": "thing.event.property.post",
"outputData": [
{
"identifier": "LightSwitch",
"name": "主灯开关",
"dataType": {
"type": "bool",
"specs": {
"0": "关闭",
"1": "开启"
}
}
}
]
}

因此:有效载荷发布的数据位:{"method":"thing.event.property.post","id":"292200613","params":{"LightSwitch":0},"version":"1.0.0"}

 

 

实现:

固定报头:30 xx
可变报头:/sys/a1U1OR0WIlM/LED_CONTROL/thing/event/property/post
可变报头(二进制 54):00 36 2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 
{"method":"thing.event.property.post","id":"292200613","params":{"LightSwitch":0},"version":"1.0.0"}
有效载荷:7B 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 79 2E 70 6F 73 74 22 2C 22 69 64 22 3A 22 32 39 32 32 30 30 36 31 33 22 2C 22 70 61 72 61 6D 73 22 3A 7B 22 4C 69 67 68 74 53 77 69 74 63 68 22 3A 31 7D 2C 22 76 65 72 73 69 6F 6E 22 3A 22 31 2E 30 2E 30 22 7D  


PUBLISH(共159):30 9C 01 00 36 2F 73 79 73 2F 61 31 55 31 4F 52 30 57 49 6C 4D 2F 4C 45 44 5F 43 4F 4E 54 52 4F 4C 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 7B 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 79 2E 70 6F 73 74 22 2C 22 69 64 22 3A 22 32 39 32 32 30 30 36 31 33 22 2C 22 70 61 72 61 6D 73 22 3A 7B 22 4C 69 67 68 74 53 77 69 74 63 68 22 3A 31 7D 2C 22 76 65 72 73 69 6F 6E 22 3A 22 31 2E 30 2E 30 22 7D

4)响应

11.PUBACK报文(4  S<=>C 固定报头+可变报头  QoS1)

PUBACK 报文是对 QoS 1 等级的 PUBLISH 报文的响应。

1)固定报头(40 02)

2)可变报头

12.PUBREC报文(5  S<=>C 固定报头+可变报头  QoS2 第一步)

发布消息收到

PUBREC 报文是对 QoS 等级 2 的 PUBLISH 报文的响应。它是 QoS 2 等级协议交换的第二个报文

1)固定报头(50 02 )

2)可变报头

13.PUBREC报文(6  S<=>C 固定报头+可变报头  QoS2 第二步)

发布消息释放

1)固定报头( 62 02)

2)可变报头

14.PUBCOMP报文(7  S<=>C 固定报头+可变报头  QoS2 第三步)

发布消息完成

PUBCOMP 报文是对 PUBREL 报文的响应。 它是 QoS 2 等级协议交换的第四个也是最后一个报文

1)固定报头( 70 02)


2)可变报头

#include "wifi.h"
#include "delay.h"
#include "string.h"
#include "usart2.h"
#include "stdio.h"
#include "usart.h"
#include "mqtt.h"
#include "utils_hmac.h"
#include "timer3.h"
#include "timer1.h"
#include "timer4.h"
#include "mqtt_data_deal.h"

char ConnectPack_flag = 0;
char SubcribePack_flag = 0;
char Ping_flag = 0;
/*********************************临时缓冲区***************************/
unsigned char temp_buff[300];//14个报文存储缓冲区

unsigned char MQTT_TxData_buff[5][300];//发送数据缓冲区
unsigned char *MQTT_TxData_Input; //发送输入缓冲区
unsigned char *MQTT_TxData_Output;//发送输出缓冲区
unsigned char *MQTT_TxData_End;  //发送缓冲区尾

unsigned char MQTT_RxData_buff[5][300];//接收数据缓冲区
unsigned char *MQTT_RxData_Input; //接收输入缓冲区
unsigned char *MQTT_RxData_Output;//接收输出缓冲区
unsigned char *MQTT_RxData_End;  //接收缓冲区尾

unsigned char MQTT_CMD_buff[5][300];//接收数据缓冲区
unsigned char *MQTT_CMD_Input; //接收输入缓冲区
unsigned char *MQTT_CMD_Output;//接收输出缓冲区
unsigned char *MQTT_CMD_End;  //接收缓冲区尾

/*********************************阿里云参数***************************/
char ServerIP[128];
int Port;
char clientID[128];
char username[128];
char password[128];

int clientID_len;
int username_len;
int password_len;

/****************************************************************************
函数名称:void MQTT_Buff_Init(void)
函数参数:无
函数返回值:无
描述: 初始化接收,发送,命令数据的 缓冲区 以及各状态参数
@author:冷瑾瑜
****************************************************************************/
void MQTT_Buff_Init(void)
{
	memset(WIFI_RXBUFF,0,sizeof(WIFI_RXBUFF));
	USART2_RX_LENG = 0;
	//输入输出缓冲区指向地址二维数组第一行
	MQTT_TxData_Input = MQTT_TxData_buff[0];
	MQTT_TxData_Output= MQTT_TxData_Input ;
	MQTT_TxData_End = MQTT_TxData_buff[4];
	
	MQTT_RxData_Input = MQTT_RxData_buff[0];
	MQTT_RxData_Output = MQTT_RxData_Input;
	MQTT_RxData_End = MQTT_RxData_buff[4];
	
	MQTT_CMD_Input = MQTT_CMD_buff[0];
	MQTT_CMD_Output = MQTT_CMD_Input;
	MQTT_CMD_End = MQTT_CMD_buff[4];
	
	MQTT_ConectPack();
	MQTT_Subscribe(0x00); //发送Qos0的报文
 
	
	Ping_flag = ConnectPack_flag = SubcribePack_flag = 0;   
}

/****************************************************************************
函数名称:void AliIoT_Parameter_Init(void)
函数参数:无
函数返回值:无
描述:阿里云初始化参数
@author:冷瑾瑜
****************************************************************************/
void AliIoT_Parameter_Init(void)
{
	char temp[128] = {0};
	
	//ServerIP  PORT
	memset(ServerIP,0,sizeof(ServerIP));
	sprintf(ServerIP,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",PRODUCTKEY);
	Port = 1883;
	
	//clientID
	memset(clientID,0,sizeof(clientID));
	sprintf(clientID,"%s|securemode=3,signmethod=hmacsha1|",DEVICENAME);
	clientID_len = strlen(clientID);
	//username
	memset(username,0,sizeof(username));
	sprintf(username,"%s&%s",DEVICENAME,PRODUCTKEY);
	username_len = strlen(username);
	//password
	memset(password,0,sizeof(password));
	sprintf(temp,"clientId%sdeviceName%sproductKey%s",DEVICENAME,DEVICENAME,PRODUCTKEY);
	//哈希加密
	utils_hmac_sha1(temp,strlen(temp),password,DEVICESECRE,DEVICESECRE_LEN);
	password_len = strlen(password);
	
	u1_printf("********************输出调试信息**********************\r\n");
	u1_printf("ServerIP = %s   Port = %d  \r\n",ServerIP,Port);
	u1_printf("clientID = %s\r\n",clientID);
	u1_printf("username = %s\r\n",username);
	u1_printf("password = %s\r\n",password);
	u1_printf("******************************************************\r\n");
	
}
/****************************************************************************
函数名称:void MQTT_ConectPack(void)
函数参数:无
函数返回值:无
描述:连接服务器报文    固定报头+可变报头+负载
@author:冷瑾瑜
****************************************************************************/
void MQTT_ConectPack(void)
{
	int i = 0;
	int length = 0,temp = 0,remain_len,buff_count = 1;
	memset(temp_buff,0,300);
	//固定报头
	temp_buff[0] = 0x10;
			//变长度编码
	length = 10 + clientID_len + 2 + username_len + 2 + password_len + 2;
  remain_len =	length;
	
	do
	{
		temp = length % 128;  //将每个字节最大位取出
		remain_len = remain_len /128;
		if(remain_len > 0){temp |= 0x80;} //数据超过128,需要将最高位置位,这个字节使你用到的第几个字节,如果是1就是基字节
			
		temp_buff[buff_count] = temp;
		buff_count++;
		
	}while(remain_len > 0);//判断几个字节
	//可变报头
	temp_buff[buff_count+0]=0x00;                 
	temp_buff[buff_count+1]=0x04;   
	temp_buff[buff_count+2]=0x4D;	 
	temp_buff[buff_count+3]=0x51;	 
	temp_buff[buff_count+4]=0x54;	 
	temp_buff[buff_count+5]=0x54;	 
	temp_buff[buff_count+6]=0x04;	 
	temp_buff[buff_count+7]=0xC2;	//可变报头第8个字节 :使能用户名和密码校验,不使用遗嘱,不保留会话
	temp_buff[buff_count+8]=0x00; 	//可变报头第9个字节 :保活时间高字节 0x00
	temp_buff[buff_count+9]=0x64;	//可变报头第10个字节:保活时间高字节 0x64   100s
	//负载
		//clientID 
  temp_buff[buff_count+10]=clientID_len / 256;	
	temp_buff[buff_count+11]=clientID_len % 256;	
	memcpy(&temp_buff[buff_count+12],clientID,clientID_len);
		//username
  temp_buff[buff_count+11+ clientID_len + 1]=username_len / 256;	
	temp_buff[buff_count+12+ clientID_len + 1]=username_len % 256;	
	memcpy(&temp_buff[buff_count+13+ clientID_len + 1],username,username_len);
		//password
	temp_buff[buff_count+13+ clientID_len +  username_len + 1]=password_len / 256;	
	temp_buff[buff_count+14+ clientID_len +  username_len + 1]=password_len % 256;	
	memcpy(&temp_buff[buff_count + 15+ clientID_len + username_len + 1],password,password_len);
	
	TxDataBuf_Deal(temp_buff,buff_count + length);  
	
//	for(i = 0;i < buff_count + length;i++)
//	{
//		u1_printf("%x ",temp_buff[i]);
//	}
//	u1_printf("\r\n");
//	Delay_ms(3000);
 
}
/****************************************************************************
函数名称:void MQTT_CONNACK(void)
函数参数:无
函数返回值:无
描述:连接报文响应
@author:冷瑾瑜
****************************************************************************/
void MQTT_CONNACK(void)
{
	if(MQTT_RxData_Output[2]==0x20)
		{      //connect报文         			
			switch(MQTT_RxData_Output[5]){					
			case 0x00 : u1_printf("CONNECT报文成功\r\n");                         
							ConnectPack_flag = 1;                                        
						break;                                                                                                    
			case 0x01 : u1_printf("连接已拒绝,不支持的协议版本,准备重启\r\n");    
						Link_mode = 0;                                             
						break;                                                      
			case 0x02 : u1_printf("连接已拒绝,不合格的客户端标识符,准备重启\r\n");  
						Link_mode = 0;                                           
						break;                                                       
			case 0x03 : u1_printf("连接已拒绝,服务端不可用,准备重启\r\n");       
						Link_mode = 0;                                            
						break;                                                      
			case 0x04 : u1_printf("连接已拒绝,无效的用户名或密码,准备重启\r\n");   
						Link_mode = 0;                                            			
						break;                                                      
			case 0x05 : u1_printf("连接已拒绝,未授权,准备重启\r\n");              
						Link_mode = 0;                                            					
						break;                                                       
			default   : u1_printf("连接已拒绝,未知状态,准备重启\r\n");             
						Link_mode = 0;                                             	
						break;                                                        	
		}
	}			
}
/****************************************************************************
函数名称:void MQTT_Subscribe(int QoS)
函数参数:QoS:订阅等级    
函数返回值:无
描述:SUBSCRIBE订阅topic报文     
@author:冷瑾瑜
****************************************************************************/
void MQTT_Subscribe(int QoS)
{
	
	int remain = 2 + 2 + 1 + S_TOPIC_LEN;
	
	memset(temp_buff,0,300);
	temp_buff[0] = 0x82;
	temp_buff[1] = remain;//自动转换为16机制
	temp_buff[2] = 0x00;
	temp_buff[3] = 0x0A;
	temp_buff[4] = S_TOPIC_LEN / 256;
	temp_buff[5] = S_TOPIC_LEN % 256;
	memcpy(&temp_buff[6],S_TOPIC,S_TOPIC_LEN);
	temp_buff[6 + S_TOPIC_LEN ] = QoS;
	
  TxDataBuf_Deal(temp_buff,remain + 2);
}
/****************************************************************************
函数名称:void MQTT_SUBACK(void)
函数参数:无    
函数返回值:无
描述:  订阅报文响应  
@author:冷瑾瑜
****************************************************************************/
void MQTT_SUBACK(void)
{
	if(MQTT_RxData_Output[2]==0x90)  //SubcribePack报文
	{
			switch(MQTT_RxData_Output[6]){					
			case 0x00 :
			case 0x01 : u1_printf("订阅成功\r\n");            //串口输出信息
								SubcribePack_flag = 1;                //SubcribePack_flag置1,表示订阅报文成功,其他报文可发送
						Ping_flag = 0;                        //Ping_flag清零
								TIM3_ENABLE_30S();                    //启动30s的PING定时器
				//		LED1_State();                         //判断开关状态,并发布给服务器  
						break;                                //跳出分支                                             
			default   : u1_printf("订阅失败,准备重启\r\n");  //串口输出信息 
						Link_mode = 0;                     //Connect_flag置零,重启连接
						break;                                //跳出分支 								
		}
	}
}
/****************************************************************************
函数名称:void MQTT_UNSUBSCRIBE(void)
函数参数:无    
函数返回值:无
描述:  取消报文订阅  
@author:冷瑾瑜
****************************************************************************/
void MQTT_UNSUBSCRIBE(void)
{
	int remain = 2 + 2 + S_TOPIC_LEN;
	memset(temp_buff,0,300);
	temp_buff[0] = 0xA2;
	temp_buff[1] = remain;
	temp_buff[2] = 0x00;
	temp_buff[3] = 0x0A;
	temp_buff[4] = S_TOPIC_LEN / 256;
	temp_buff[5] = S_TOPIC_LEN % 256;
	memcpy(&temp_buff[6],S_TOPIC,S_TOPIC_LEN);
	
	TxDataBuf_Deal(temp_buff,remain + 2);
}

/****************************************************************************
函数名称:void MQTT_UNSUBACKE(void)
函数参数:无    
函数返回值:无
描述:  取消报文订阅响应  
@author:冷瑾瑜
****************************************************************************/
void MQTT_UNSUBACKE(void)
{
	if(MQTT_RxData_Output[2]==0xB0 && MQTT_RxData_Output[3] == 0x02 && MQTT_RxData_Output[4] == 0x00 && MQTT_RxData_Output[5] == 0x0A)
	{
		u1_printf("取消报文订阅成功\r\n");
	} 
}
/****************************************************************************
函数名称:void MQTT_PingREQ(void)
函数参数:无     
函数返回值:无
描述:PING报文,心跳包   
@author:冷瑾瑜
****************************************************************************/
void MQTT_PingREQ(void)
{
	memset(temp_buff,0,300);
	temp_buff[0] = 0xC0;
	temp_buff[1] = 0x00;
	
	TxDataBuf_Deal(temp_buff,2); //将数据添加至发送缓冲区
}

/****************************************************************************
函数名称:void MQTT_PingRSP(void)
函数参数:无     
函数返回值:无
描述:PING报文,心跳包   
@author:冷瑾瑜
****************************************************************************/
void MQTT_PingRSP(void)
{
	if(MQTT_RxData_Output[2]==0xD0)  //ping报文回复
	{ 
			u1_printf("PING报文回复\r\n"); 		  //串口输出信息 
			if(Ping_flag==1){                     //如果Ping_flag=1,表示第一次发送
				 Ping_flag = 0;    				  //要清除Ping_flag标志
			}else if(Ping_flag>1) //如果Ping_flag>1,表示是多次发送了,而且是2s间隔的快速发送
			{ 				 
				Ping_flag = 0;     				  //要清除Ping_flag标志
				TIM3_ENABLE_30S(); 				  //PING定时器重回30s的时间
			}		
	}			

}

/****************************************************************************
函数名称:void MQTT_PublishPUBACK(void)
函数参数:无    
函数返回值:无
描述:处理发布响应(QOS1)    
@author:冷瑾瑜
****************************************************************************/
void MQTT_PublishPUBACK(void)
{
	if(MQTT_RxData_Output[2]==0x40 && MQTT_RxData_Output[3]==0x02)   
	{ 
			u1_printf("收到发布消息确认\r\n"); 		   
	}	
		//可加上报文标识符	
}
/****************************************************************************
函数名称:void MQTT_PublishPUBREC(void)
函数参数:无    
函数返回值:无
描述:发布消息收到    
@author:冷瑾瑜
****************************************************************************/
void MQTT_PublishPUBREC(void)
{
	if(MQTT_RxData_Output[2]==0x50 && MQTT_RxData_Output[3]==0x02)   
	{ 
			u1_printf("发布消息收到\r\n"); 		   
	}
			//可加上报文标识符		
}
/****************************************************************************
函数名称:void MQTT_PublishPUBREL(void)
函数参数:无    
函数返回值:无
描述:发布消息释放    
@author:冷瑾瑜
****************************************************************************/
void MQTT_PublishPUBREL(void)
{
	if(MQTT_RxData_Output[2]==0x62 && MQTT_RxData_Output[3]==0x02)   
	{ 
			u1_printf("发布消息释放\r\n"); 		   
	}
			//可加上报文标识符		
}
/****************************************************************************
函数名称:void MQTT_PublishPUBCOMP(void)
函数参数:无    
函数返回值:无
描述:发布消息完成    
@author:冷瑾瑜
****************************************************************************/
void MQTT_PublishPUBCOMP(void)
{
	if(MQTT_RxData_Output[2]==0x70 && MQTT_RxData_Output[3]==0x02)   
	{ 
			u1_printf("发布消息完成\r\n"); 		   
	}
			//可加上报文标识符		
}
/****************************************************************************
函数名称:void MQTT_PublishQs0(void)
函数参数:topic_name:topic名称    data:数据   data_len:数据长度      
函数返回值:无
描述:等级0 发布消息报文    
@author:冷瑾瑜
****************************************************************************/
void MQTT_PublishQs0(char *data,int data_len)
{
	//Info Temp;
		//Temp = MQTT_LightSwitch(1); //点灯任务
//	u1_printf("%d %d",P_TOPIC_LEN,Temp.length);
	int leng = 0,remain = 0;
	char count = 1,temp = 0;

	leng = 2 + P_TOPIC_LEN +  data_len;  //156
	remain = leng;
	memset(temp_buff,0,300);
  temp_buff[0] = 0x30;
	do
	{
		temp = remain % 128;//28
	  remain = remain / 128;  //判断是否进位 1
		
		if(remain > 0){temp |= 0x80;}
		temp_buff[count++] = temp;
	}while(remain > 0);
	temp_buff[count+0] = P_TOPIC_LEN / 128;
	temp_buff[count+1] = P_TOPIC_LEN % 128;
	
	memcpy(&temp_buff[count+2],P_TOPIC,P_TOPIC_LEN);
	memcpy(&temp_buff[count+2+P_TOPIC_LEN],data,data_len);
		
	TxDataBuf_Deal(temp_buff,leng + 1 + count); //将数据添加至发送缓冲区
}
/****************************************************************************
函数名称:void MQTT_DealPushdata_Qs0(unsigned char *redata)
函数参数:redata:接收的数据    
函数返回值:无
描述:处理服务器发来的等级0的推送  服务器下发的第一个字节是30,紧跟的几个字节是变长度  
@author:冷瑾瑜
bug: re_len接收存在问题 
解决办法:将data[1] = 0;认定每个pack< 128
****************************************************************************/
void MQTT_DealPushdata_Qs0(unsigned char *redata)
{
	int  re_len;               	           //定义一个变量,存放接收的数据总长度
	int  pack_num;                         //定义一个变量,当多个推送一起过来时,保存推送的个数
    int  temp,temp_len;                    //定义一个变量,暂存数据
    int  totle_len;                        //定义一个变量,存放已经统计的推送的总数据量
	int  topic_len;              	       //定义一个变量,存放推送中主题的长度
	int  cmd_len;                          //定义一个变量,存放推送中包含的命令数据的长度
	int  cmd_loca;                         //定义一个变量,存放推送中包含的命令的起始位置
	int  i;                                //定义一个变量,用于for循环
	int  local,multiplier;
	unsigned char tempbuff[300];	   //临时缓冲区
	unsigned char *data;                   //redata过来的时候,第一个字节是数据总量,data用于指向redata的第2个字节,真正的数据开始的地方
		
	re_len = redata[0]*256+redata[1];                               //获取接收的数据总长度	
//	u1_printf("re_len = %d\r\n",re_len);
//		for(i = 0;i < re_len + 1 ;i++)
//		{
//			u1_printf("%c",redata[i]);
//		}
//			u1_printf("\r\n");
	data = &redata[2];                                              //data指向redata的第2个字节,真正的数据开始的 
//		u1_printf("data = %c\r\n",data);
	pack_num = temp_len = totle_len = temp = 0;                	    //各个变量清零
	local = 1;
	multiplier = 1;
	do{
		pack_num++;                                     			//开始循环统计推送的个数,每次循环推送的个数+1	
		do{
			temp = data[totle_len + local];   
			temp_len += (temp & 127) * multiplier;
			multiplier *= 128;
			local++;
		}while ((temp & 128) != 0);
		totle_len += (temp_len + local);                          	//累计统计的总的推送的数据长度
		re_len -= (temp_len + local) ;                              //接收的数据总长度 减去 本次统计的推送的总长度      
		local = 1;
		multiplier = 1;
		temp_len = 0;
	}while(re_len!=0);                                  			//如果接收的数据总长度等于0了,说明统计完毕了
	u1_printf("本次接收了%d个推送数据\r\n",pack_num);//串口输出信息
	temp_len = totle_len = 0;                		            	//各个变量清零
	local = 1;
	multiplier = 1;
	for(i=0;i<pack_num;i++){                                        //已经统计到了接收的推送个数,开始for循环,取出每个推送的数据 		
		do{
			temp = data[totle_len + local];   
			temp_len += (temp & 127) * multiplier;
			multiplier *= 128;
			local++;
		}while ((temp & 128) != 0);				
//		u1_printf("local = %d  totle_len = %d \r\n",local,totle_len);
//		u1_printf("data[1] = %d    data[2] = %d \r\n",data[local+totle_len]*256,data[local+1+totle_len]);
	//	topic_len = data[local+totle_len]*256+data[local+1+totle_len] + 2;    //计算本次推送数据中主题占用的数据量
		topic_len = data[local+1+totle_len] + 2;
		cmd_len = temp_len-topic_len;                               //计算本次推送数据中命令数据占用的数据量
		cmd_loca = totle_len + local +  topic_len;                  //计算本次推送数据中命令数据开始的位置
//		u1_printf("totle_len = %d  local = %d  topic_len = %d\r\n",totle_len,local,topic_len);
//		u1_printf("cmd_loca = %d\r\n",cmd_loca);
//		u1_printf("data[cmd_loca] = %c cmd_len = %d  \r\n",data[cmd_loca],cmd_len);	
		memcpy(tempbuff,&data[cmd_loca],cmd_len);                   //命令数据拷贝出来	
	
		CMDBuf_Deal(tempbuff, cmd_len);                             //加入命令到缓冲区
		totle_len += (temp_len+local);                              //累计已经统计的推送的数据长度
		local = 1;
		multiplier = 1;
		temp_len = 0;
	}	
}


//void MQTT_DealPushdata_Qs0(unsigned char *redata)
//{
//	unsigned char *data = NULL;
//	unsigned char tempbuff[300];	   
//	int redata_len,totle_len = 0;
//	int index = 1;
//	int temp = 0,temp_len = 0,i = 0; //temp:可变报头 + 有效载荷 长度
//	int mul; //倍数
//	int pack_num = 0;
//	int topic_len = 0;
//	int cmd_len = 0,cmd_index = 0;
//	
//	redata_len = redata[0]*256 + redata[1];
//	data = &redata[2];  //数据包第一个字节开始位置
//	
//	do
//	{
//		pack_num++;
//		do//
//		{
//			temp = data[totle_len + index];
//			temp_len += (temp & 127) * mul;  //取出每个pack的长度 
//			mul = mul * 128;
//			index++;
//			 
//		}while((temp & 128) != 0);//验证长度是几个字节
//		totle_len += (temp_len + index);  //每次加一个包的长度
//		redata_len -= (temp_len + index);  //每次减一个数据包的长度
//		
//		index = mul = 1;
//		temp_len = 0;
//	}while(redata_len != 0);
//	u1_printf("本次接收了%d个推送数据\r\n",pack_num); 
//	
//	totle_len = temp_len = 0;
//	index = mul = 1;
//	
//	for(i = 0;i < pack_num;i ++)
//	{
//		do//取出一包
//		{
//			temp = data[totle_len + index];
//			temp_len += (temp & 127) * mul;  //取出每个pack的长度(pack = 可变报头 + 有效载荷 )
//			mul = mul * 128;
//			index++;
//		}while((temp & 128) != 0);//验证长度是几个字节
//		
//		topic_len = data[index + totle_len] * 256 + data[index + 1+ totle_len] + 2;  //每个pack中可变报头长度
//		cmd_index = totle_len + index + topic_len;//有效载荷起始位置
//		cmd_len = temp_len - topic_len;  //有效载荷长度
//		
//		memcpy(tempbuff,&data[cmd_index],cmd_len);  //将有效载荷存入缓冲区
//		CMDBuf_Deal(tempbuff,cmd_len); 
//		totle_len += (temp_len + index);//累加数据长度
//		index = mul = 1;
//		temp_len = 0;
//		
//	}
//}


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式物联网协议--MQTT 的相关文章

  • 第八章 确认访问用户身份的认证

    第八章 确认访问用户身份的认证 8 1 何为认证 在计算机安全和网络通信的背景下 认证是 确认实体 如用户 计算机系统 服务 身份真实性的过程 认证是确保系统只对合法用户或实体开放访问权限的一种关键机制 在网络通信中 认证通常涉及验证用户或
  • 一个网工(网络工程师)七年的职业血泪史....

    前言 一个工作了七年的老网工 上家公司待了五年 现在这家公司也快三年了 分享一些我自己学习网络安全路上的一些经历 也算是帮大家少走些弯路 一 如何学习网络安全 1 不要试图以编程为基础去学习网络安全 不要以编程为基础再开始学习网络安全 一般
  • 网络基础面试题(二)

    11 什么是网桥 防火墙的端口防护是指什么 网桥是一种网络设备 用于连接两个或多个局域网 LAN 并转发数据包 它能够根据MAC地址来识别和转发数据 提高网络的传输效率和安全性 防火墙的端口防护是指对防火墙上的各个端口进行保护和限制 只允许
  • 如何使用内网穿透实现iStoreOS软路由公网远程访问局域网电脑桌面

    文章目录 简介 一 配置远程桌面公网地址 二 家中使用永久固定地址 访问公司电脑 具体操作方法是 简介 软路由 是PC的硬件加上路由系统来实现路由器
  • 【一份老网工珍藏多年的网络配置笔记,很重要!】

    01 交换机 路由器的几种配置模式及模式转换 1 用户模式 登录到交换机 路由器 时会自动进入用户模式 提示符为 switchname gt 在该模式下只能够查看相关信息 对 IOS的运行不产生任何影响 2 特权模式 用户模式下 键入 en
  • 6类典型场景的无线AP选型和部署方案

    你们好 我的网工朋友 前段时间刚给你们来了篇解决无线频繁断网的技术文 解决无线频繁断网 这个办法值得收藏 不少朋友私聊 说想再聊聊无线AP的选型和部署方案 这不就安排上了 无线网络覆盖项目中 无线AP的合理选型和部署非常重要 在设计施工中
  • 网络空间安全女生就业,怎么学?

    我实验室的学长们基本都是以红队和复现为主 如果学校好点可能还有更多的选择 如果想在这个方向深入下去 推荐流程是先打两年CTF 把大概的技术方向摸一摸 大一的话 如果学校还不错 那就优先建议打好基础 包括C语言 Python一类 建议把CTF
  • 内网穿透的应用-使用Net2FTP轻松部署本地Web网站并公网访问管理内网资源

    文章目录 1 前言 2 Net2FTP网站搭建 2 1 Net2FTP下载和安装 2 2 Net2FTP网页测试 3 cpolar内网穿透 3 1 Cpolar云端设置 3 2 Cpolar本地设置
  • 掌握内网渗透之道,成为实战高手,看《内网渗透实战攻略》就够了

    文末送书 文末送书 今天推荐一本网络安全领域优质书籍 内网渗透实战攻略 文章目录 前言 如何阅读本书 目录 文末送书 前言 当今 网络系统面临着越来越严峻的安全挑战 在众多的安全挑战中 一种有组织 有特定目标 长时间持续的新型网络攻击日益猖
  • 基于java的物业管理系统设计与实现

    基于java的物业管理系统设计与实现 I 引言 A 研究背景和动机 物业管理系统是指对物业进行管理和服务的系统 该系统需要具备对物业信息 人员信息 财务信息等进行管理的能力 基于Java的物业管理系统设计与实现的研究背景和动机主要体现在以下
  • 网络安全(黑客)自学启蒙

    一 什么是网络安全 网络安全是一种综合性的概念 涵盖了保护计算机系统 网络基础设施和数据免受未经授权的访问 攻击 损害或盗窃的一系列措施和技术 经常听到的 红队 渗透测试 等就是研究攻击技术 而 蓝队 安全运营 安全运维 则研究防御技术 作
  • 揭秘看不见人的“黑灯工厂”

    你知道吗 未来工厂不需要人也能24小时运转 未来机器能自己配合的天衣无缝 未来工厂连一点灰尘都进不去 未来自研的智能化设备甚至几秒就能生产出一部手机 千万不要惊讶 其实这样的工厂已经在我们的身边 很可能你在元旦买到的一件衣服 一部手机就是
  • 静态综合实验

    1 IP地址划分 192 168 1 0 27 用于主干拆分 192 168 1 32 27 用于用户拆分 192 168 1 64 27 用于用户拆分 192 168 1 96 27 用于用户拆分 192 168 1 128 27 用于用
  • 【安全】网络安全态势感知

    文章目录 一 态势感知简介 1 概念 2 形象举例 3 应具备的能力 二 为什么要态势感知 为什么网络安全态势感知很重要 三 态势感知系统的功能 四 如何评估态势感知的建设结果 五 什么是态势感知的三个层级 四 业界的态势感知产品 1 安全
  • MQTT 连接在 Node 中工作,但不能作为 ReactJS 组件

    当我在 nodeJS 中运行它时 我有这个 mqtt 连接工作正常 但是当我将它移动到反应组件中时 我收到此错误 WebSocket 握手期间出错 net ERR CONNECTION RESET 我读过这是由与这里的默认端口有关的事情引起
  • java.io.EOFException 与 paho

    我想对蚊子进行压力测试 所以我创建了一些代码 如下所示 for int i 0 i lt 800 i final int j i Thread t new Thread new Runnable Override public void r
  • 如何使用 QtMqtt 和 SSL 执行安全 MQTT?

    我正在尝试使用 QtMQtt 示例项目 simpleclient 但我想执行安全的 MQTT 我该如何处理这个问题 我读过这篇博客 https www qt io blog 2017 08 14 introducing qtmqtt pro
  • Mosquitto 1.4.2 Websocket 支持

    我正在尝试利用 Mosquittos 最近的更新来支持代理中的 websocket 我正在运行 Mosquitto v1 4 2 并将以下几行添加到 mosquitto 配置文件 mosquitto conf 中 listener 1000
  • OPC-UA 的替代方案 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 作为访问由各种 PLC 组成的系统的过程数据的解决方案 是否有 OPC UA 的合适替代方案 独立于平
  • 通过 MQTT 将 LoRa 测量结果发送到 Fiware IOT 代理

    我有 LoRa 传感器 它使用 Cayenne LPP 格式有效负载发送测量值 我的网关 LOrank8v1 捕获这些数据包并将其转换为 UDP 网关中有一个服务 lora gateway bridge 它将数据包从 UDP 转换为 TCP

随机推荐

  • 纯css画三角形及气泡样式的简单画法

    在做项目的过程中 遇到了要写一个气泡的样式 先布局了矩形部分 但小三角形的旗气泡遇到一点困难 后来梳理了一下 以此记录 首先是三角形的画法 三角形的原理就是矩形 然后分成四个三角形 一般使用border来画一个三角形 如下图所示 我们给一个
  • 云服务器木马文件该如何应对,云服务器木马入侵怎么办?服务器中木马怎么排查?...

    由于云服务器的扩展方便 并且能够减少硬件方面的维护成本 因此使用云服务器的用户数量越来越多 但是云服务器也同样存在安全方面的隐患 被入侵的案列也是时有发生 那么云服务器木马入侵怎么办 服务器中木马怎么排查 我们来了解下吧 云服务器木马入侵怎
  • java中抽象工厂模式_Java设计模式之抽象工厂模式

    转自http blog csdn net jason0539 article details 44976775 本文继续介绍23种设计模式系列之抽象工厂模式 前面已经介绍过简单工厂模式和工厂方法模式 这里继续介绍第三种工厂模式 抽象工厂模式
  • js倒计时

    html部分代码 div class time span 60 span span s span div js部分代码 var second document getElementById second var m 60 var time
  • 计算机产业能否迅速发展,工控机产业迅速发展:未来体系结构将更具交互性与可操作性...

    工控机 Industrial Personal Computer IPC 即工业控制计算机 是一种采用总线结构 对生产过程及机电设备 工艺装备进行检测与控制的工具总称 工控机具有重要的计算机属性和特征 如具有计算机CPU 硬盘 内存 外设及
  • 50行Python代码实现代理服务器的详细教程

    代理服务器是一种位于客户端与目标服务器之间的中间服务器 它可以代表客户端发送请求 并将响应返回给客户端 通过搭建自己的代理服务器 我们可以实现请求的拦截 修改和转发等功能 本文将为大家介绍如何使用50行Python代码实现代理服务器 一 准
  • [QT编程系列-37]:数据存储 - 日志文件、日志等级的支持:qDebug、Log4Qt

    目录 1 概述 2 qDebug 2 1 概述 2 2 qDebug对调试等级的支持 通过不同的宏来实现 2 3 qt日志等级的设置 1 概述 在 Qt 中 日志文件的支持通常是通过日志库 日志框架或自定义代码实现的 Qt 本身没有提供内置
  • vue3中实现音频播放器APlayer

    前言 vue2的时候 分享了一个很好用的插件是vue aplayer 但是他是不支持vue3的 这里分享vue3使用APlayer来实现一个播放器的方法 实现效果 官方 git地址 点我 api地址 点我 实现步骤 1 安装 npm npm
  • Spring Boot 过滤器、监听器和拦截器使用

    1 过滤器和监听器 Spring Boot中对于过滤器和监听器的使用跟一般web工程中使用方式没什么不同 使用注解方式就可以快速创建 只是要使用注解方式需要在Application类加上 ServletComponentScan 注解表明开
  • LIO-SAM运行自己数据包遇到的问题解决--SLAM不学无数术小问题

    LIO SAM 成功适配自己数据集 注意本文测试环境 Ubuntu18 04 ROS melodic版本 笔者用到的硬件以简单参数 激光雷达 速腾聚创16线激光雷达 RS Lidar 16 IMU 超核电子CH110型 9轴惯导 使用频率1
  • Ionic3开发教程 - 开发(2)

    Ionic3开发系列教程Ionic3开发教程 环境准备 1 Ionic3开发教程 开发 2 Ionic3开发教程 发布Android版本 3 Ionic3开发教程 发布IOS版本 4 Ionic3开发教程 更新 5 本文中介绍的Ionic3
  • mybatis在xml文件中处理大于号小于号的方法

    第一种方法 用了转义字符把 gt 和 lt 替换掉 然后就没有问题了 SELECT FROM test WHERE 1 1 AND start date lt CURRENT DATE AND end date gt CURRENT DAT
  • JAVA依赖冲突解决

    一 问题 启动时报错 二 原因 导入的包中存在依赖冲突 应该是打印日志的 三 解决办法 1 mvn dependency tree 打印项目的依赖树 2 安装MAVEN HELPER 2 1 查看依赖图 2 2 直接查看 四 解决 1 比如
  • SpriteKit框架详细解析(四) —— 创建一个简单的2D游戏(二)

    转自 https www jianshu com p 33f28911db17 版本记录 版本号 时间 V1 0 2017 08 12 前言 SpriteKit框架使用优化的动画系统 物理模拟和事件处理支持创建基于2D精灵的游戏 接下来这几
  • element级联懒加载多选不能回显问题

    1 定位原因 懒加载的级联下拉框无法回显是因为 只绑定了model的值 没有options的数据支撑的话 获取不到节点的内容导致 2 方案 拿到选中的项的时候 用这些值去递归循环获取相应的节点的一些属性 赋值给options 然后注意最后一
  • yolo v3 fatal : Memory allocation failure

    torch版的 yolov3报错 fatal Memory allocation failure parser add argument n cpu type int default 8 help number of cpu threads
  • 蚂蚁笔记私有部署

    说明 其实官方的教程中已经写得很清楚了 我写这个主要是为了记录一下我自己当时安装的过程 方便后续查询 官方文档请查阅 https github com leanote leanote wiki 环境要求 CentOS6 5 Nginx Mo
  • (原理及配置)nginx配置负载均衡

    背景介绍 早期的网站流量和业务功能都比较简单 单台服务器就可以满足基本需求 但是随着互联网的发展 业务流量越来越大并且业务逻辑也越来越复杂 单台服务器的性能及单点故障问题就凸显出来了 因此需要多台服务器组成应用集群 进行性能的水平扩展以及避
  • 一台电脑双 GitHub 账户配置,同时两个 SSH 密钥

    前言 本人搞了两个 GitHub 账号 一个用来正常的和别人合作项目 另一个用来自己写一些代码 希望能做到两个本地账户和远程账号都完全隔离 没有联系 也不会被混淆使用 但是这样就会有一个问题 设置本地用户 user email 时候 如果两
  • 嵌入式物联网协议--MQTT

    本文使用MQTT 3 1 1版本 目录 一 MQTT简介 1 什么是MQTT 2 MQTT本质 3 MQTT报文类型 4 MQTT Qos质量 二 14个报文详解 1 CONNECT报文 1 C gt S 固定报头 可变报头 负载 1 固定