使用Mosquitto实现MQTT客服端C语言

2021年9月11日 3点热度 0条评论 来源: 浇筑菜鸟

  上一篇文章已经将mosquitto移植到了arm平台上,现在将使用mosquitto完成mqtt客服端的demo,了解过mqtt协议的小伙伴都知道,mqtt主要分为代理服务器、发布者、订阅者三部分。接下来通过mqtt发布者和订阅者两个demo了解mosquitto库函数的使用。

一、Mosquitto库函数的API

mosquitto的api说明文档:https://mosquitto.org/api/files/mosquitto-h.html
mosquitto库中常见的函数应用总结:https://blog.csdn.net/makunIT/article/details/107283260
上面这位博主总结的比较好,我就在这里引用一下,需要的小伙伴可以看看。

二、mqtt发布者源码

mqtt_pub_demo.c

#include <stdio.h>
#include <stdlib.h>
#include <mosquitto.h>
#include <string.h>

#define HOST "192.168.2.99"
#define PORT  1883
#define KEEP_ALIVE 60
#define MSG_MAX_SIZE  512

bool session = true;

int main(void)
{

    int err = 0;

    printf("mqtt publish init...\n");
    struct mosquitto *mosq = NULL;
    char buff[MSG_MAX_SIZE];

    //libmosquitto 库初始化
    err = mosquitto_lib_init();
    if (err < 0){
        printf("mosquitto lib int fail...");
        goto fail_mosquitto_lib;
    }

    //创建mosquitto客户端
    mosq = mosquitto_new(NULL,session,NULL);
    if (mosq == NULL){
        printf("create client failed...\n");
        err = -1;
        goto fail_mosquitto_new;
    }

    //客户端连接服务器
    err = mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE);
    if (err < 0){
        printf("connect fail");    
        goto fail_mosq_conn;
    }

    //不阻塞,库函数中将自动创建线程实现
    err = mosquitto_loop_start(mosq);
    if(err != MOSQ_ERR_SUCCESS){
        printf("mosquitto loop error\n");
        goto fail_mosq_loop_start;
    }

    while(fgets(buff, MSG_MAX_SIZE, stdin) != NULL)
    {
        mosquitto_publish(mosq, NULL, "temp", strlen(buff)+1, buff, 0, 0);
        memset(buff, 0, sizeof(buff));
    }

    mosquitto_disconnect(mosq);
    mosquitto_loop_stop(mosq, true);
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();

    return 0;
fail_mosq_loop_start:
    mosquitto_disconnect(mosq);
fail_mosq_conn:
    mosquitto_destroy(mosq);
fail_mosquitto_new:
    mosquitto_lib_cleanup();
fail_mosquitto_lib:
    return err;
}

Makefile

INCLUDES = -lmosquitto -lpthread -ldl -lssl -lcrypto  \
-I/home/linux/arm-lib/mosquitto/include \
-L/home/linux/arm-lib/mosquitto/lib \
-L/homelinux/arm-lib/openssl/lib

SOURCE = $(wildcard ./*.c)

OBJ = $(patsubst ./%.c, ./%.0, $(SOURCE))

#INCLUDES = $(wildcard ./*.h)

TARGET = mqtt_pub_demo
CC = arm-linux-gnueabihf-gcc

$(TARGET):$(OBJ)
    $(CC) $(OBJ) -o $(TARGET) $(INCLUDES)

%.0:%.c
    $(CC) -c $< -o $@ $(INCLUDES)

clean:
    rm -rf $(OBJ) $(TARGET)

三、mqtt订阅者源码

mqtt_sub_demo.c

#include <stdio.h>
#include <stdlib.h>
#include <mosquitto.h>
#include <string.h>

#define HOST "192.168.2.99"
#define PORT  1883
#define KEEP_ALIVE 60

bool session = true;

void mqtt_subscribe_callback(struct mosquitto *mosq,
                void *userdata, int mid, int qos_count, const int *granted_qos)
{
    int i;
    printf("subscribed (mid: %d): %d", mid, granted_qos[0]);
    for(i=1; i < qos_count; i++){
        printf(", %d", granted_qos[i]);
    }
    printf("\n");
}

//消息回调函数,收到订阅的消息后调用
void mqtt_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
    if (message->payloadlen){
        printf("%s %s \n", message->topic, (char *)message->payload);
    }else{
        printf("%s (null)\n",message->topic);
    }
}

//mqtt连接回调
void mqtt_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
    int ret;
    if (!result){
        ret = mosquitto_subscribe(mosq, NULL, "temp", 2);
        if(ret < 0){
            printf("Subscription failed\n");
        }else{
            printf("Subscription succeeded\n");
        }
    }else{
        printf("connect failed\n");
    }
}

//日志回调函数
void mqtt_log_callback(struct mosquitto *mosq, void *userdata, int level, const char *str)
{
    printf("log__   %s\n", str);    
}

int main(void)
{

    int err = 0;
    printf("mqtt client init...\n");

    struct mosquitto *mosq = NULL;

    //libmosquitto 库初始化
    err = mosquitto_lib_init();
    if (err < 0){
        printf("mosquitto lib int fail...");
        goto fail_mosquitto_lib;
    }

    //创建mosquitto客户端
    mosq = mosquitto_new(NULL,session,NULL);
    if (mosq == NULL){
        printf("create client failed...\n");
        err = -1;
        goto fail_mosquitto_new;
    }

    //设置回调函数
    mosquitto_log_callback_set(mosq, mqtt_log_callback);
    mosquitto_connect_callback_set(mosq, mqtt_connect_callback);
    mosquitto_message_callback_set(mosq, mqtt_message_callback);
    mosquitto_subscribe_callback_set(mosq, mqtt_subscribe_callback);

    //客户端连接服务器
    err = mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE);
    if (err < 0){
        printf("connect fail");    
        goto fail_mosq_conn;
    }
    
    //主线成将被阻塞至此
    err = mosquitto_loop_forever(mosq, -1, 1);
    if (err < 0){
        printf("mosquitto loop fail");
        goto fail_mosq_loop_stop;
    }

    mosquitto_disconnect(mosq);
    mosquitto_loop_stop(mosq, false);
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();

    return 0;

fail_mosq_loop_stop:
    mosquitto_disconnect(mosq);
fail_mosq_conn:
    mosquitto_destroy(mosq);
fail_mosquitto_new:
    mosquitto_lib_cleanup();
fail_mosquitto_lib:
    return err;

}

Makefile

INCLUDES = -lmosquitto -lpthread -ldl -lssl -lcrypto  \
-I/home/xfg/linux/arm-lib/mosquitto/include \
-L/home/xfg/linux/arm-lib/mosquitto/lib \
-L/home/xfg/linux/arm-lib/openssl/lib

SOURCE = mqtt_sub_demo.c

TARGET = mqtt_sub_demo
CC = arm-linux-gnueabihf-gcc

$(TARGET):$(SOURCE)
    $(CC) $(SOURCE) -o $(TARGET) $(INCLUDES)

clean:
    rm -rf $(TARGET)

四、测试

  1. 在虚拟机上打开代理服务器,并将编译生成的mqtt_sub_demo和mqtt_pub_demo移动到ARM开发版上
  2. 打开mqqt订阅者
  3. 打开mqtt发布者,发布信息

    完成后,可以看订阅者接受的信息是否正确

    由此可以看出编写的测试程序没问题。

五、参考文献

mosquitto库中常见的函数应用总结:https://blog.csdn.net/makunIT/article/details/107283260
基于MQTT协议的Mosquitto的使用及libmosquitto客户端编程:https://blog.csdn.net/danwuxie/article/details/86517568
基于mosquitto的MQTT客户端实现C语言:https://www.cnblogs.com/y-c-y/p/11686916.html
Qt官方MQTT库的使用,附一个MqttClient例子:https://www.cnblogs.com/yexiaopeng/p/8542894.html
mosquitto的api说明文档:https://mosquitto.org/api/files/mosquitto-h.html

    原文作者:浇筑菜鸟
    原文地址: https://www.cnblogs.com/jzcn/p/15252983.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。