赞
踩
这里我只是根据我实际用的功能来实现MQTT协议,并没有把MQTT全部实现。接下来我会介绍我是怎么实现MQTT协议的,希望能给你帮助。
首先介绍一下大致思路。
在头文件中定义
MQTT的结构体
这个结构体来保存一些缓冲区的指针,报文的类型,结果代码,错误代码等等。
各种报文的结构体
因为每个报文都不同,不同的位,格式有差异,所以我们需要根据每种报文定义结构体。
枚举各个报文的值
比如枚举出各个报文,用来区分报文。
用宏定义定义一些需要修改的值。
超时等待时间
比如客户端连接服务端,客户端需要等待服务端相应,但是客户端不能一直等待下去,所以我们需要定义一个超时等待时间。
与服务端连接保活时间
这个时间在不同的情景下是有差异,所以需要单独拎出来。
缓冲区的大小
根据需要传输的数据最大大小来设置缓冲区的大小
接下来从头文件开始介绍。
在头文件中将MQTT协议中所以控制报文枚举出来。
注意下枚举的值必须要与MQTT协议中的值一一对应。
/* 报文类型枚举 */ typedef enum { MQTT_CONNECT = 0x10U, //连接 MQTT_CONNACK = 0x20U, //连接响应 MQTT_PUBLISH = 0x30U, //发布消息 MQTT_PUBACK = 0x40U, //发布消息响应 QoS = 1 MQTT_PUBREC = 0x50U, //发布消息响应 QoS = 2 MQTT_PUBREL = 0x60U, MQTT_PUBCOMP = 0x70U, MQTT_SUBSCRIBE = 0x82U, //订阅 MQTT_SUBACK = 0x90U, //订阅响应 MQTT_UNSUBSCRIBE = 0xA2U, //取消订阅 MQTT_UNSUBACK = 0xB0U, //取消订阅响应 MQTT_PINGREQ = 0xC0U, //保活 MQTT_PINGRESP = 0xD0U, //保活响应 MQTT_DISCONNECT = 0xE0U //断开连接 }MessageType_t;
定义了一个新的枚举类型MessageType_t
。
因为传输的数据有字符和实数,所以我们需要区分。
为什么实数的枚举值是-1
,而字符的枚举值是1
,我将在之后讲解。
/* 数据类型枚举 */
typedef enum
{
MQTT_NUM = -1, //数据是实数
MQTT_CHAR = 1, //数据是字符
}DataType_t;
定义了一个新的枚举类型DataType_t
。
正如上文提到的,定义了一些需要根据情景来修改的数值。
/* 最大超时等待时间 单位毫秒 */
#define MQTT_MAX_TIMES_OUT (1000U)
/* 连接保活时间 单位秒 */
#define MQTT_KEEP_ALIVE (300U)
/* 缓冲区的大小 单位字节 */
#define MQTT_BUFF_SIZE (200U)
/* MQTT结构体 */
typedef struct
{
MessageType_t messageType; //报文的类型
char* sendBuff; //指向数据发送缓冲区的指针
char* sendBuffPointNow; //指向数据发送缓冲区当前位置的指针
char resultCode; //结果返回代码
unsigned int remainLength; //解码获得的剩余长度
void* returnData; //指向服务端返回的对应的报文结构体的指针
int (*MQTTSendDataToServer)(const char* data, unsigned int length); //发送数据-----接口
void (*MQTTDelayms)(unsigned int ms); //延时毫秒函数-----接口
void (*MQTTReceiveDadaFromServer)(unsigned char* data, unsigned int length); //从服务器接收到数据-----接口
}MQTT_t;
说明一些需要注意的地方。
MessageType_t
的变量messageType
,sendBuff
,该数据发送缓冲区的大小是用宏定义MQTT_BUFF_SIZE
定义的。sendBuffPointNow
,解释一下就是当我们往数据发送缓冲区写入X个字节后,该指针就会增长X个字节。resultCode
,一些报文是需要根据服务端响应的数据来判断状态的,比如CONNECT报文,当我们连接服务端的时候,需要服务端返回CONNACK报文,来指示客户端是否连接成功。其中resultCode
的初始值也用了一个宏定义定义#define MQTT_RESULT_CODE_INIT (0x0F)
returnData
,举个例子,客户端连接服务端,服务端会返回一个CONNEACK报文,同时我们也定义一个与CONNACK对应的结构体s
,returnData
就是指向这个结构体s
。MQTTSendDataToServer
MQTTDelayms
MQTTReceiveDadaFromServer
三个函数指针,需要用户根据自己的平台来实现,使用MQTT前记得先给这三个函数指针赋值。可通过下面这三个函数来给三个函数指针赋值。void SetMQTTSendDataToServer(int (*MQTTSendDataToServer)(const char* data, unsigned int length));
void SetMQTTDelayms(void (*MQTTDelayms)(unsigned int ms));
void SetMQTTReceiveDadaFromServer(void (*MQTTReceiveDadaFromServer)(unsigned char* data, unsigned int length));
没啥可介绍,把报文中需要设置的位、需要发送的数据等等提取出来就可以。
这里我只贴上几个重要的结构体的定义。
/* 连接服务端结构体 */
typedef struct
{
unsigned char connectFlag; //连接标志
unsigned short keepAliveTime; //保活时间
const char *clientID; //客户端ID
const char *userName; //用户名
const char *password; //密码
}MQTTConnectStruct_t;
/* 发布消息结构体 */
typedef struct
{
char RETAIN;
char QoS;
char DUP;
unsigned short messageID; //报文标识符
const char *topic; //主题
const char *payload; //有效载荷
}MQTTPublishStruct_t;
/* 订阅主题结构体 */
typedef struct
{
unsigned short messageID; //报文标识符(客户端标识符)
char QoS;
const char *payload; //有效载荷
}MQTTSubscribeStruct_t;
源代码下载链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。