最近做项目使用模块的MQTT功能,但是由于MQTT没有透传模式,发送接收使用AT指令太频繁的话容易出错。
今天在技术群里偶然听说了可以使用TCP模式,自己再在TCP的基础上封装一层MQTT数据协议,想了一下确实可行。
在网上找了一下,发现一段代码如下:
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<topic_len; subindex++) {
mqtt_message[6+subindex] = topic[subindex];
}
mqtt_message[topic_len+6+1] = 0;
return topic_len+7;
}
再根据MQTT协议:https://mcxiaoke.gitbooks.io/mqtt-cn/content/
对比发现应该是可行的,近期没有项目,就不测试了,下次测试会在此处更新测试结果。(已测试,代码好用,但是需要自己增加和修改,上面的代码只是起到封装数据的作用,另外还有其他相关的MQTT服务,后续我会自己写,写完会更新到这里)
代码取自博客:https://blog.csdn.net/pz0605/article/details/60964587
经过实际项目验证,上面的代码只能发送不超过128字节的数据,如果需要发送更多的数据,需要自己修改协议层代表数据长度的字节。这里贴一下我改过的,可以发送16000+字节。
int baseIndex;
int mqtt_connect_message(unsigned char *mqtt_message,char *client_id,char *username,char *password)
{
char i = 0;
char client_id_length = sel_strlen(client_id);
int username_length = sel_strlen(username);
int password_length = sel_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;
usart2_SendHex(mqtt_message,baseIndex);
return baseIndex;
}
int mqtt_publish_message( char *mqtt_message, char * topic, char * message,int message_len) {
//mqtt_message = 0;
// printf("111111\r\n");
int i = 0;
unsigned char len1,len2;
int topic_length = sel_strlen(topic);
int message_length = message_len;
printf("message_length = %d\r\n",message_length);
// printf("222222\r\n");
len1 = (2+topic_length +message_length)/128;
len2 = ((2+topic_length +message_length)%128) + 128;
if(len1>0)
{
mqtt_message[0] = 48; // MQTT Message Type CONNECT
mqtt_message[1] = len2; // Remaining length
mqtt_message[2] = len1; // MQTT Message Type CONNECT
mqtt_message[3] = 0;
mqtt_message[4] = topic_length; // MQTT Message Type CONNECT
// Topic
for(i = 0; i < topic_length; i++){
mqtt_message[5 + i] = topic[i];
}
// Message
for(i = 0; i < message_length; i++){
mqtt_message[5 + topic_length + i] = message[i];
}
printf("mqtt_message:");
for(i=0;i<(5 + topic_length + message_length);i++)
{
printf("%c",mqtt_message[i]);
}
printf("\r\n");
// printf("333333\r\n");
usart2_SendHex(mqtt_message,5 + topic_length + message_length);
}
else
{
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];
}
printf("mqtt_message:");
for(i=0;i<(4 + topic_length + message_length);i++)
{
printf("%c",mqtt_message[i]);
}
printf("\r\n");
// printf("333333\r\n");
usart2_SendHex(mqtt_message,4 + topic_length + message_length);
}
// printf("444444\r\n");
return 0;
}
int subindex = 0;
int mqtt_subscribe_message(unsigned char *mqtt_message,unsigned char *topic)
{
unsigned char topic_len = sel_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<topic_len; subindex++) {
mqtt_message[6+subindex] = topic[subindex];
}
mqtt_message[topic_len+6+1] = 0;
usart2_SendHex(mqtt_message,topic_len+7);
return 0;
}
还有一种方法就是使用C库,将模块设置入网,通过C库来建立socket连接MQTT服务器并发布订阅主题数据。
提供一下网上的C库:https://github.com/eclipse/paho.mqtt.embedded-c