stm32\QT\MFC MQTT客户端程序记录


前言

MQTT客户端程序,仅大概记录一下,源码可能存在问题(记录时是使用的MFC源码,项目结束有大半年了,记事本内凭感觉删减、修改了一下供stm32用户观看)

其实MQTT即是在TCP连接的基础上,将数据进行了指定格式的封装后发送出去,和json、http很类似。


一、mqtt协议程序实现方式记录

一共在3种产品上验证了此MQTT程序的可行性,可移植性较高。

最开始是在stm32的产品上实现mqtt,后来的wince、linux环境下,直接拿过来稍加修改使用也正常通信,就没有去使用mqtt相关的库
1、stm32+esp8266+ucosii

2、wince+esp8266+mfc

3、arm-linux+qt+tplink无线网卡(移植的RTL8192EU驱动)

程序逻辑:
1、TCP连接服务器(Socket)
2、MQTT连接协议组帧----ConnectMqtt
3、订阅、取消订阅主题–MqttSubscribeTopic
4、发布消息–MqttPublishData

具体mqtt协议在tcp下的数据帧网上有很多资料,就不记录了。

二、核心源码

1.mqtt_client.c

#include "StdAfx.h"
#include "mqtt_msg.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
/*******************************************************************************
		 源码是MFC(C++)在记事本内改过来的,因为离职后家里只有这个版本程序,
		 没有了stm32源码,可能删减\修改得有点问题
*******************************************************************************/
/**
* @brief  连接服务器的帧数据
* @param  ClientID:设备ID
* @param  will:遗嘱,用于掉线时mqtt协议通知服务器
* @param  Username:服务器账号 mqtt服务器和数据库一样是可以设置账号密码的
* @param  Password:服务器密码 如果没有账号密码,则随便传入一个参数,服务器没有设置密码就不会检测
* @retval 
* @example 
* 客户端连接服务器首先使用此函数组帧
**/
int ConnectMqtt(char *ClientID,char *will, char *Username, char *Password)
{
	int ClientIDLen = strlen(ClientID);
	int WillLen = strlen(will);
	int UsernameLen = strlen(Username);
	int PasswordLen = strlen(Password);
	int DataLen = 0;
	int Index = 2;
	int i = 0;
	DataLen = 12 + 2 + 2 + 2 + 2 + ClientIDLen + WillLen + UsernameLen + PasswordLen;
	MqttSendData[0] = 0x10;                //MQTT Message Type CONNECT
	MqttSendData[1] = DataLen;    //剩余长度(不包括固定头部)
	MqttSendData[Index++] = 0;        // Protocol Name Length MSB    
	MqttSendData[Index++] = 4;        // Protocol Name Length LSB    
	MqttSendData[Index++] = 'M';        // ASCII Code for M    
	MqttSendData[Index++] = 'Q';        // ASCII Code for Q    
	MqttSendData[Index++] = 'T';        // ASCII Code for T    
	MqttSendData[Index++] = 'T';        // ASCII Code for T    
	MqttSendData[Index++] = 4;        // MQTT Protocol version = 4    
	MqttSendData[Index++] = 0xce;        // conn flags 
	MqttSendData[Index++] = 0;        // Keep-alive Time Length MSB    
	MqttSendData[Index++] = 60;        // Keep-alive Time Length LSB  60S心跳包  
	MqttSendData[Index++] = (0xff00 & ClientIDLen) >> 8;// Client ID length MSB    
	MqttSendData[Index++] = 0xff & ClientIDLen;    // Client ID length LSB  

 	for (i = 0; i < ClientIDLen; i++)
	{
		MqttSendData[Index + i] = ClientID[i];
	}
	Index = Index + ClientIDLen;
	//遗嘱
	if (WillLen > 0)
	{
		MqttSendData[Index++] = (0xff00 & WillLen) >> 8;
		MqttSendData[Index++] = 0xff & WillLen;
		for (i = 0; i < WillLen; i++)
		{
			MqttSendData[Index + i] = will[i];
		}
		Index = Index + WillLen;
		MqttSendData[Index++] =0;
		MqttSendData[Index++] = 0;
	}
	if (UsernameLen > 0)
	{
		MqttSendData[Index++] = (0xff00 & UsernameLen) >> 8;//username length MSB    
		MqttSendData[Index++] = 0xff & UsernameLen;    //username length LSB    
		for (i = 0; i < UsernameLen; i++)
		{
			MqttSendData[Index + i] = Username[i];
		}
		Index = Index + UsernameLen;
	}

	if (PasswordLen > 0)
	{
		MqttSendData[Index++] = (0xff00 & PasswordLen) >> 8;//password length MSB    
		MqttSendData[Index++] = 0xff & PasswordLen;    //password length LSB    
		for (i = 0; i < PasswordLen; i++)
		{
			MqttSendData[Index + i] = Password[i];
		}
		Index = Index + PasswordLen;
	}
	return Index;
}


/**
* @brief  MQTT订阅/取消订阅数据打包函数
* @param  SendData
* @param  topic                主题
* @param  qos         消息等级    个人觉得qos=0就行,否则可能出现一个指令收到多次,没有试过不清楚
* @param  whether     订阅=true/取消=false    请求包
* @retval
* @example
**/
int MqttSubscribeTopic(char *topic, char qos, char whether)
{
	int topiclen = strlen(topic);
	int i = 0, index = 0;

	if (whether)
		MqttSendData[index++] = 0x82;                   //0x82 //消息类型和标志 SUBSCRIBE 订阅
	else
		MqttSendData[index++] = 0xA2;                   //0xA2 取消订阅
	MqttSendData[index++] = topiclen + 5;                //剩余长度(不包括固定头部)
	MqttSendData[index++] = 0;                          //消息标识符,高位
	MqttSendData[index++] = 0x01;                    //消息标识符,低位
	MqttSendData[index++] = (0xff00 & topiclen) >> 8;    //主题长度(高位在前,低位在后)
	MqttSendData[index++] = 0xff & topiclen;              //主题长度 

	for (i = 0; i < topiclen; i++)
	{
		MqttSendData[index + i] = topic[i];
	}
	index = index + topiclen;

	if (whether)
	{
		MqttSendData[index] = qos;//QoS级别
		index++;
	}
	return index;
}


/**
* @brief  MQTT发布数据打包函数
* @param  mqtt_message
* @param  topic       主题
* @param  qos         消息等级
* @retval
* @example
**/
int MqttPublishData(char * topic, char * message, char qos)
{
	int topic_length = strlen(topic);
	int message_length = strlen(message);
	int i, index = 0;
	static int id = 0;

	MqttSendData[index++] = 0x32;    // MQTT Message Type PUBLISH  


	if (qos)
		MqttSendData[index++] = 2 + topic_length + 2 + message_length;//数据长度
	else
		MqttSendData[index++] = 2 + topic_length + message_length;   // Remaining length  


	MqttSendData[index++] = (0xff00 & topic_length) >> 8;//主题长度
	MqttSendData[index++] = 0xff & topic_length;

	for (i = 0; i < topic_length; i++)
	{
		MqttSendData[index + i] = topic[i];//拷贝主题
	}
	index += topic_length;

	if (qos)
	{
		MqttSendData[index++] = (0xff00 & id) >> 8;
		MqttSendData[index++] = 0xff & id;
		id++;
	}

	for (i = 0; i < message_length; i++)
	{
		MqttSendData[index + i] = message[i];//拷贝数据
	}
	index += message_length;
	
	return index;
}

2.mqtt_client.h

/*******************************************************************************
		 源码是MFC(C++)在记事本内改过来的,因为离职后家里只有这个版本程序,
		 没有了stm32源码,可能删减\修改得有点问题
*******************************************************************************/
	int ConnectMqtt(char *ClientID,char *will, char *Username, char *Password);
	int MqttSubscribeTopic(char *topic, char qos, char whether);
	int MqttPublishData(char * topic, char * message, char qos);
	typedef struct MQTT
	{
		/***** mqtt组帧发送缓冲区 通过以上3个函数组帧后  TCP直接发送MqttSendData内容即可**********/
		unsigned char MqttSendData[200];
		/***** 用户名 **********/
		char USER[30];
		/***** 密码 **********/
		char PWD[30];
		/***** 设备ID **********/
		char ID[50];
		/***** 遗嘱**********/
		char Will[50];
		/***** 上行主题 **********/
		char Topic_Up[50];
		/***** 下行主题 **********/
		char Topic_Down[50];
		/***** 消息 **********/
		char Msg[100];
		/***** 状态 1:连接成功  2:订阅成功 3:发布成功 4:心跳成功**********/
		char Status;
		/***** 调用返回值**********/
		int ret;
		/***** 收到数据长度**********/
		int retLen;
	}s_MQTT;

总结

1、连接服务器时:遗嘱可有可无,根据项目实际使用场景而定
2、数据的相关处理都在tcp线程内,离职没了源码,就不贴出来了,网上有很多mqtt协议的数据格式资料
3、ConnectMqtt内,有关协议版本问题,好像不同的协议版本,数据有微调,但是没有遇到其他版本的MQTT服务器,是不是要微调一下有待考证。
4、开发使用到的工具:
org.eclipse.paho.ui.app-1.0.2-win32.win32.x86_64.zip
apache-apollo-1.7.1-windows-distro.zip
在自己电脑上建立MQTT服务器,但是基于这个服务器开发的程序最后和软件人员对接时,TCP的数据错位了1位,莫名其妙消失了一个 ‘/’。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值