提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
Mosquitto库是一个开源的消息代理项目,用于实现MQTT(Message Queuing Telemetry Transport)协议。MQTT是一种轻量级的通信协议,适用于低带宽、高延迟或不稳定网络环境下的物联网设备通信。Mosquitto库提供了MQTT协议的服务器和客户端实现,可以用于构建物联网应用和设备之间的通信。Mosquitto库支持多种平台和编程语言,并提供了丰富的功能和灵活的配置选项。
一、创建阿里云产品
如何创建产品的详细过程可查看我上篇文章介绍,链接如下:
二、下载mosquitto库
1.下载源码
wget http://mosquitto.org/files/source/mosquitto-1.6.10.tar.gz
2.解压源码
tar -zxvf mosquitto-1.6.10.tar.gz
3.进入源码目录,编译下载安装
cd mosquitto-1.6.10/
make
sudo make install
三、连接阿里云
主要用到的API如下:
1.MQTT初始化
int mosquitto_lib_init(void)
功能:
使用mosquitto库函数前,要先初始化,使用之后就要清除。清除函数;int mosquitto_lib_cleanup()
返回值:MOSQ_ERR_SUCCESS
2.MQTT清除
int mosquitto_lib_cleanup(void)
功能:
使用MQTT之后,清除工作
返回值MOSQ_ERR_SUCCESS
3.新建客户端
struct mosquitto *mosquitto_new(const char * id, bool clean_session, void * obj)
参数
id:如果为NULL,将生成一个随机客户端ID。如果id为NULL,clean_session必须为true。
clean_session:设置为true以指示代理在断开连接时清除所有消息和订阅,设置为false以指示其保留它们,客户端将永远不会在断开连接时丢弃自己的传出消息就是断开后是否保留订阅信息true/false
obj:用户指针,将作为参数传递给指定的任何回调
返回
成功时返回结构mosquitto的指针,失败时返回NULL,询问errno以确定失败的原因:ENOMEM内存不足。EINVAL输入参数无效。
4.释放客户端
void mosquitto_destroy(struct mosquitto * mosq)
功能
释放客户端
参数:mosq: struct mosquitto指针
5.设置账号密码
int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *passworp)
参数
struct mosquitto *mosq :客户端
const char *username : 以字符串形式发送的用户名,或以NULL形式关闭认证。
const char *passworp:以字符串形式发送的密码。 当用户名有效时,设置为NULL,以便只发送一个用户名。
返回值
成功时返回MOSQ_ERR_SUCCESS。
如果输入参数无效,返回MOSQ_ERR_INVAL。
如果发生内存不足的情况,返回MOSQ_ERR_NOMEM。
6.确认连接回调函数
void mosquitto_connect_callback_set(struct mosquitto * mosq, void (*on_connect)(struct mosquitto *mosq, void *obj, int rc) )
功能:连接确认回调函数,当代理发送CONNACK消息以响应连接时,将调用此方法。
参数:
struct mosquitto * mosq:客户端通配符
void (*on_connect):回调函数
struct mosquitto *mosq:客户端数据
void *obj:创建客户端的回调参数(mosquitto_new中提供的用户数据)
int rc:
0-成功
1-连接被拒绝(协议版本不可接受)
2-连接被拒绝(标识符被拒绝)
3-连接被拒绝(经纪人不可用)
4-255-保留供将来使用
7.连接MQTT代理/服务器
int mosquitto_connect(struct mosquitto * mosq, const char * host, int port, int keepalive)
功能: 连接到MQTT代理/服务器(主题订阅要在连接服务器之后进行)
参数:
struct mosquitto * mosq:客户端
const char * host:服务器ip
int port:服务器端口号
int keepalive:保持连接的时间间隔, 单位秒
返回:
MOSQ_ERR_SUCCESS 成功。
MOSQ_ERR_INVAL 如果输入参数无效。
MOSQ_ERR_ERRNO 如果系统调用返回错误。变量errno包含错误代码
8.网络事件循环处理
int mosquitto_loop_start(struct mosquitto * mosq)
功能:网络事件循环处理函数,通过创建新的线程不断调用mosquitto_loop() 函数处理网络事件,不阻塞
参数:
struct mosquitto * mosq:客户端
返回:
MOSQ_ERR_SUCCESS 成功。
MOSQ_ERR_INVAL 如果输入参数无效。
MOSQ_ERR_NOT_SUPPORTED 如果没有线程支持。
9.发布主题
int mosquitto_publish(struct mosquitto * mosq, int * mid, const char * topic, int payloadlen, const void * payload, int qos, bool retain)
功能:主题发布的函数
参数:
struct mosquitto * mosq:客户端
int * mid:指向int的指针。如果不为NULL,则函数会将其设置为该特定消息的消息ID
const char * topic:要发布的主题,以'\0'结尾的字符串
int payloadlen:主题消息的内容长度
const void * payload:主题消息的内容,指向要发送的数据的指针,如果payloadlen >0,则它必须时有效的存储位置
int qos:整数值0、1、2指示要用于消息的服务质量
bool retain:设置为true以保留消息
返回:
MOSQ_ERR_SUCCESS 成功。
MOSQ_ERR_INVAL 如果输入参数无效。
MOSQ_ERR_NOMEM 如果发生内存不足的情况。
MOSQ_ERR_NO_CONN 如果客户端未连接到代理。
MOSQ_ERR_PROTOCOL 与代理进行通信时是否存在协议错误。
MOSQ_ERR_PAYLOAD_SIZE 如果payloadlen太大。
MOSQ_ERR_MALFORMED_UTF8 如果主题无效,则为UTF-8
MOSQ_ERR_QOS_NOT_SUPPORTED 如果QoS大于代理支持的QoS。
MOSQ_ERR_OVERSIZE_PACKET 如果结果包大于代理支持的包。
10.断开MQTT代理/服务器
int mosquitto_disconnect( struct mosquitto * mosq )
功能:断开与代理/服务器的连接。
返回:
MOSQ_ERR_SUCCESS 成功。
MOSQ_ERR_INVAL 如果输入参数无效。
MOSQ_ERR_NO_CONN 如果客户端未连接到代理。
主函数代码如下
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include "mqtt_get_config.h"
#include "mosquitto.h"
#include "cJSON.h"
#define KEEPALIVE 60
#define PATH "./config.ini"
int get_devsn(char *devsn, int size);
int get_time(char *date_time, int size);
int dht11_get_temperature(float *temp);
void mosq_connect_callback(struct mosquitto *mosq, void *obj, int rc);
int main(int argc, char *argv[])
{
int rv = 0;
struct mosquitto *mosq = NULL;
mqtt_user_data_t mqtt;
int rc = 0;
void *obj = NULL;
float temp = 0;
cJSON *cjson = NULL;
cJSON *root = NULL;
char *str = NULL;
char devsn_buf[8] = {0};
char time_buf[32] = {0};
memset(&mqtt, 0, sizeof(mqtt));
rv = get_config(PATH, &mqtt, PUB);
printf("1-%s\n 2-%d\n 3-%s\n 4-%s\n 5-%s\n 6-%s\n",mqtt.brokeraddress,mqtt.brokerport,mqtt.username,mqtt.password,mqtt.clientid,mqtt.identifier);
if(rv)
{
printf("get config\n");
}
rv = mosquitto_lib_init();
if (rv < 0)
{
printf("mosquitto init failed: %s\n", strerror(errno));
goto cleanup;
}
mosq = mosquitto_new(mqtt.clientid, true, (void *)&mqtt);
if ( !mosq )
{
printf("mosquitto create failed: %s\n", strerror(errno));
goto cleanup;
}
rv = mosquitto_username_pw_set(mosq, mqtt.username, mqtt.password);
if(rv != MOSQ_ERR_SUCCESS)
{
printf("mqtt set failed\n");
}
printf("Create mosquitto successfully!\n");
mosquitto_connect_callback_set(mosq, mosq_connect_callback);
rv = mosquitto_connect(mosq, mqtt.brokeraddress, mqtt.brokerport, KEEPALIVE);
if( rv != MOSQ_ERR_SUCCESS)
{
printf("mosquitto connect failed: %s\n", strerror(errno));
}
mosquitto_loop_start(mosq);
while(1)
{
memset(devsn_buf, 0, sizeof(devsn_buf));
rv = get_devsn(devsn_buf, sizeof(devsn_buf));
if (rv)
{
printf("get devsn failed\n");
return 0;
}
memset(time_buf, 0, sizeof(time_buf));
rv = get_time(time_buf, sizeof(time_buf));
if (rv)
{
printf("get time failed\n");
return 0;
}
rv = dht11_get_temperature(&temp);
if(rv)
{
printf("get temperature failed\n");
return 0;
}
cjson = cJSON_CreateObject();
root = cJSON_CreateObject();
cJSON_AddStringToObject(cjson, "method", mqtt.method);
cJSON_AddStringToObject(cjson, "id", devsn_buf);
cJSON_AddStringToObject(cjson, "time", time_buf);
cJSON_AddNumberToObject(root, "CurrentTemperature", temp);
cJSON_AddItemToObject(cjson, "params", root);
cJSON_AddStringToObject(cjson, "version", mqtt.version);
str = cJSON_Print(cjson);
printf("%s\n", str);
rv = mosquitto_publish(mosq, NULL, mqtt.topic, strlen(str), str, 0, true);
if(rv != MOSQ_ERR_SUCCESS)
{
printf("mosquitto publish failed: %s\n", strerror(errno));
return 0;
}
sleep(5);
}
mosquitto_disconnect(mosq);
return 0;
cleanup:
mosquitto_lib_cleanup();
mosquitto_destroy(mosq);
return 0;
}
int get_devsn(char *devsn, int size)
{
strncpy(devsn, "0001", size);
return 0;
}
int get_time(char *date_time, int size)
{
time_t utc_time;
struct tm dt;
char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
time(&utc_time);
localtime_r(&utc_time, &dt);
snprintf(date_time, size, "%04d-%02d-%02d--%s--%02d:%02d:%02d", 1900+dt.tm_year, 1+dt.tm_mon, dt.tm_mday, wday[dt.tm_wday], dt.tm_hour, dt.tm_min, dt.tm_sec);
return 0;
}
int dht11_get_temperature(float *temp)
{
int fd = 0;
int length = 0;
char buf[6] = {0};
float a = 0;
fd = open("/dev/dht11", O_RDONLY);
if(fd < 0)
{
printf("open fail\n");
return -1;
}
length = read(fd, buf, 6);
if( length < 0)
{
printf("open fail\n");
return -2;
}
a = buf[2]*10 + buf[3];
*temp = a/10;
close(fd);
return 0;
}
void mosq_connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
printf("connect sucessfully\n");
}
gitee仓库:mqtt-aliyun: 使用mosquitto连接阿里云
可见温度实时上报
总结
连接阿里云使用Mosquitto进行MQTT通信的步骤为:创建阿里云公共实例、下载安装Mosquitto客户端、配置连接参数、进行发布操作。可见,我们可以采集不同的数据通过MQTT协议上报到阿里云。