使用mosquitto实现MQTT通信

1 MQTT 编程的前期准备

MQTT通信时,使用发布/订阅消息模式,其通信模型如下:
使用mosquitto实现MQTT通信_第1张图片
在编写客户端程序时,需要准备好服务器(broker)的ip地址和端口号。
获取 ip地址:
1 如果是本地服务器,ip地址设为localhost即可。
2 通过ipconfig指令查看ip地址

$ ipconfig
ens33: flags=4163  mtu 1500
        inet 192.168.0.109  netmask 255.255.255.0  broadcast 192.168.0.255
 ..........

io地址为:192.168.0.109

端口号:默认服务器监听的端口是1883

2 MQTT 发布者(客户端):

2.1 libmosquitto 库初始化

int res = 0;
res = mosquitto_lib_init();
if(res < 0)
{
	std::cout<<"mosquitto_lib_init()失败"<<std::endl;
	return;
}

2.2 创建发布者客户端实例

Mosq *pub_mosq = NULL;
pub_mosq = mosquitto_new(NULL,session,NULL);
if(pub_mosq == NULL)
{
	std::cout<<"mosquitto_new()失败"<<std::endl;
	mosquitto_lib_cleanup();
	return;
}

2.3 连接服务器:ip地址、端口号、保持连接的时间间隔

char HOST[] = "localhost";
int PORT = 1883 ;
int KEPP_LIVE = 10;
if(mosquitto_connect(pub_mosq,HOST,PORT,KEPP_LIVE)
{
	std::cout<<"mosquitto_connect()失败"<<std::endl;
	mosquitto_destroy(pub_mosq);
	mosquitto_lib_cleanup();
	return;
}

2.4 开启线程,处理网络信息

int res;
res = mosquitto_loop_start(pub_mosq);
if(res != MOSQ_ERR_SUCCESS)
{
	std::cout<<"mosquitto_loop_start()失败"<<std::endl;
	return;
}

2.5 发布消息:话题名、负载、Qos

int *mid =NULL; //消息的id
char topic[] = "temp";
char buffer[MSG_MAX_SIZE];
int len = strlen(buffer)+1;
int qos = 0;
bool retain = false;//是否保留消息
mosquitto_publish(pub_mosq,mid,topic,len,buffer,qos,retain);

2.6 销毁发布者客户端,清除libmosquitto库

 mosquitto_destroy(mosq);
 mosquitto_lib_cleanup();

mqtt_pub.cpp代码:

#include 
#include 
//#include 
//#include 
#include 

#define HOST "localhost" //连接本地服务器broker
#define PORT 1883  //端口号
#define KEPP_LIVE 10
#define MSG_MAX_SIZE 512

bool session = true;
typedef struct mosquitto Mosq; 

int main()
{
    int res = 0;
    char buffer[MSG_MAX_SIZE];
    Mosq *pub_mosq = NULL;

    //libmosquitto 库初始化
    res = mosquitto_lib_init();
    if(res < 0)
    {
        std::cout<<"mosquitto_lib_init()失败"<<std::endl;
        return 1;
    }

    //创建发布者客户端实例
    pub_mosq = mosquitto_new(NULL,session,NULL);
    if(pub_mosq == NULL)
    {
        std::cout<<"mosquitto_new()失败"<<std::endl;
        mosquitto_lib_cleanup();
        return 1;
    }

    // 连接服务器:ip地址、端口号、保持连接的时间间隔
    if(mosquitto_connect(pub_mosq, HOST,PORT,KEPP_LIVE) )
    {
        std::cout<<"mosquitto_connect()失败"<<std::endl;
        mosquitto_destroy(pub_mosq);
        mosquitto_lib_cleanup();
        return 1;
    }

    // 开启线程,处理网络信息
    res = mosquitto_loop_start(pub_mosq);
    if(res != MOSQ_ERR_SUCCESS)
    {
        std::cout<<"mosquitto_loop_start()失败"<<std::endl;
        return 1;
    }

    //发布消息:话题名、负载、Qos
    while(fgets(buffer,MSG_MAX_SIZE,stdin) != NULL)
    {
        int *mid = NULL; 
        mosquitto_publish(pub_mosq,mid,"temp",strlen(buffer)+1,buffer,0,0);
        memset(buffer,0,sizeof(buffer));
    }

    //销毁发布者客户端,清除libmosquitto 库
    mosquitto_destroy(pub_mosq);
    mosquitto_lib_cleanup();
    return 0;
}

3 MQTT 订阅者(客户端):

订阅者客户端和发布者客户端在编写步骤上差不多,订阅者客户端在回调函数对话题消息进行处理。

3.1 libmosquitto 库初始化

int res = 0;
res = mosquitto_lib_init();
if(res < 0)
{
	std::cout<<"mosquitto_lib_init()失败"<<std::endl;
	return ;
}

3.2 创建客户端实例

Mosq *mosq = NULL;
mosq = mosquitto_new(NULL,session,NULL);
if(mosq == NULL)
{
	std::cout<<"mosquitto_new()失败"<<std::endl;
	mosquitto_lib_cleanup();
	return ;
}

3 设置回调函数

//建立连接后,订阅话题的回调函数
void mqtt_connect_calllback(Mosq *mosq,void *userdata, int result)
{
    int ret;
    if(!result)
    {
        ret = mosquitto_subscribe(mosq, NULL ,"temp",2);
        if(ret <0)
        {
            std::cout<<"订阅失败"<<std::endl;
        }
        else 
        {
            std::cout<<"订阅成功"<<std::endl;
        }
    }
    else
    {
        std::cout<<"订阅者连接失败"<<std::endl;
    }
}
//订阅成功后的回调函数
void mqtt_subscriber_callback(Mosq *mosq, void *userdata,int mid,int qos_count,const int *granted_qos)
{
    int i;
    std::cout<<"订阅者(消息的id是:  "<<mid<<"}:"<<granted_qos[0];
    for(int i=0; i< qos_count;i++)
    {
        std::cout<<granted_qos[0]<<std::endl;
    }
}
//消息送达时的回调函数
void mqtt_message_callback(Mosq *mosq,void *userdata,const struct mosquitto_message *message)
{
    if(message->payloadlen)
    {
        printf("订阅的消息的话题:%s \n", message->topic, (char *)message->payload);
    }
    else
    {
         std::cout<<"话题的负载(内容):%s \n"<<message->payload<<std::endl;
    }
}

//断开连接时的回调函数
void my_disconnect_callback(Mosq *mosq,void *obj,int rc)
{
    std::cout<<"断开连接"<<std::endl;
    running = 0;
}

//日志回调函数
void mqtt_log_callback(Mosq *mosq ,void *userdata,int level,const char*str)
{
    std::cout<<"日志级别"<<level<<":"<<str<<std::endl;
}

// 设置回调函数
mosquitto_connect_callback_set(sub_mosq,mqtt_connect_calllback);
mosquitto_subscribe_callback_set(sub_mosq,mqtt_subscriber_callback);
mosquitto_message_callback_set(sub_mosq,mqtt_message_callback);
mosquitto_disconnect_callback_set(sub_mosq,my_disconnect_callback);
mosquitto_log_callback_set(sub_mosq,mqtt_log_callback);

4 连接服务器:ip地址,端口号,保持连接的时间间隔

if(mosquitto_connect(mosq,HOST,PORT,KEEP_LIVE))
    {
        std::cout<<"mosquitto_connect()失败"<<std::endl;
        return 1;
    }

5 开启线程,处理网络信息

static int running = 1;
while(running)
    {
        mosquitto_loop(mosq,-1,1);
    }

6 销毁订阅者客户端,清除libmosquitto 库

mosquitto_destroy(mosq);
mosquitto_lib_cleanup();

mqtt_sub.cpp代码:

#include 
#include 

#define HOST "localhost" 
#define PORT 1883
#define KEEP_LIVE 60

bool session = true; //?为什么要设计成全局变量

typedef struct mosquitto Mosq;
static int running = 1;

//建立连接后,订阅话题的回调函数
void mqtt_connect_calllback(Mosq *mosq,void *userdata, int result)
{
    int ret;
    if(!result)
    {
        ret = mosquitto_subscribe(mosq, NULL ,"temp",2);
        if(ret <0)
        {
            std::cout<<"订阅失败"<<std::endl;
        }
        else 
        {
            std::cout<<"订阅成功"<<std::endl;
        }
    }
    else
    {
        std::cout<<"订阅者连接失败"<<std::endl;
    }
}

//订阅成功后的回调函数
void mqtt_subscriber_callback(Mosq *mosq, void *userdata,int mid,int qos_count,const int *granted_qos)
{
    int i;
    std::cout<<"订阅者(消息的id是:  "<<mid<<"}:"<<granted_qos[0];
    for(int i=0; i< qos_count;i++)
    {
        std::cout<<granted_qos[0]<<std::endl;
    }
}

//消息送达时的回调函数
void mqtt_message_callback(Mosq *mosq,void *userdata,const struct mosquitto_message *message)
{
    if(message->payloadlen)
    {
        printf("订阅的消息的话题:%s \n 话题的负载:%s \n", message->topic, (char *)message->payload);
    }
    else
    {
         std::cout<<"订阅的消息的话题:"<<message->payload<<std::endl;
    }
}

//断开连接时的回调函数
void my_disconnect_callback(Mosq *mosq,void *obj,int rc)
{
    std::cout<<"断开连接"<<std::endl;
    running = 0;
}

//日志回调函数
void mqtt_log_callback(Mosq *mosq ,void *userdata,int level,const char*str)
{
    std::cout<<"日志级别"<<level<<":"<<str<<std::endl;
}

int main()
{
    int res = 0;
    std::cout<<"mosq 订阅者初始化"<<std::endl;
    Mosq *sub_mosq = NULL;

    //libmosquitto 库初始化
    res = mosquitto_lib_init();
    if(res < 0)
    {
        std::cout<<"mosquitto_lib_init()失败"<<std::endl;
        mosquitto_lib_cleanup();
        return 1;
    }
    
    //创建客户端实例
    sub_mosq = mosquitto_new(NULL,session,NULL);
    if(!sub_mosq)
    {
        std::cout<<"mosquitto_new()失败"<<std::endl;
        mosquitto_lib_cleanup();
        return 1;
    }
        
    // 设置回调函数
    mosquitto_connect_callback_set(sub_mosq,mqtt_connect_calllback);
    mosquitto_subscribe_callback_set(sub_mosq,mqtt_subscriber_callback);
    mosquitto_message_callback_set(sub_mosq,mqtt_message_callback);
    mosquitto_disconnect_callback_set(sub_mosq,my_disconnect_callback);
    mosquitto_log_callback_set(sub_mosq,mqtt_log_callback);

    //连接服务器:ip地址,端口号,保持连接的时间间隔
    if(mosquitto_connect(sub_mosq,HOST,PORT,KEEP_LIVE))
    {
        std::cout<<"mosquitto_connect()失败"<<std::endl;
        return 1;
    }

    while(running)
    {
        mosquitto_loop(sub_mosq,-1,1);
       
    }

    mosquitto_destroy(sub_mosq);
    mosquitto_lib_cleanup();

    return 0;
}

4 Makefile编译

Makefile文件

all:Subscriber Publiser
	@echo ""
	@echo "Start compiling"
	@echo ""

Subscriber:
	@g++  -o Subscriber mqtt_sub.cpp -lmosquitto -lpthread -ldl -lssl -lcrypto

Publiser:
	@g++  -o Publisher mqtt_pub.cpp -lmosquitto -lpthread -ldl -lssl -lcrypto
clean:
	-rm Publiser Subscriber

5运行

打开一终端,启动mosquitto服务器

$ mosquitto -v

另起一终端,运行订阅者

$ ./Subscriber

再起一终端,运行发布者

$./Publisher

使用mosquitto实现MQTT通信_第2张图片

当前文件结构
使用mosquitto实现MQTT通信_第3张图片

你可能感兴趣的:(iot)