Linux:MQTT通信协议之四 -- 编写mosquitto的C例程(异步函数)

  上一篇文章简单提及了以异步函数和同步函数对比,由于异步函数是非阻塞的,所以性能上比同步函数要稍好些,所以也就常用异步函数来实现MQTT的通讯。
  异步函数与同步函数两者的差别就是在连接服务器的connect函数、loop循环函数。那接下来就简单探究一下loop函数的调用方式:同步函数是调用mosquitto_loop函数来阻塞等待实现的一种通信;而查看源码我们就会发现,异步方式的"loop"函数就是创建了一个线程去完成同步方式中导致阻塞等待的mosquitto_loop函数,其调用过程如下:

mosquitto_loop_start(mosq);		// 异步方式的loop
	pthread_create(&mosq->thread_id, NULL, mosquitto__thread_main, mosq)
		mosquitto_loop_forever(mosq, 1000*86400, 1);
			mosquitto_loop(mosq, timeout, max_packets);		// 同步方式的loop

mosquitto_loop_stop(mosq, false);
	pthread_cancel(mosq->thread_id);
	pthread_join(mosq->thread_id, NULL);

了解同步异步函数的调用区别之后,我们继续看一下异步方式连接服务器函数mosquitto_connect_async的官方说明:

Connect to an MQTT broker. This is a non-blocking call. If you use mosquitto_connect_async your client must use the threaded interface mosquitto_loop_start. If you need to use mosquitto_loop, you must use mosquitto_connect to connect the client.
May be called before or after mosquitto_loop_start.

现在我们可以根据connect函数与loop函数的匹配关系编写异步方式的通讯程序:

订阅端
#include 
#include 
#include 
#include 
#include "mosquitto.h"


/* 设置打印开关 */
#define DEBUG_PROCESS   printf
#define DEBUG_ERROR     printf
#define DEBUG_MSG       printf


// 定义运行标志决定是否需要结束
static int g_iRunFlag = 1;


/* 回调函数里添加自己的额外操作即可,mosquitto_xx函数已实现底层操作 */
void on_connect(struct mosquitto *mosq, void *obj, int rc);
void on_disconnect(struct mosquitto *mosq, void *obj, int rc);
void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos);
void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg);


int main()
{
        int ret;
        struct mosquitto *mosq;

        // 初始化mosquitto库
        ret = mosquitto_lib_init();
        if(ret){
                DEBUG_ERROR("Init lib error!\n");
                return -1;
        }

        // 创建一个实例
        // 参数:id(不需要则为NULL)、clean_start、用户数据
        mosq =  mosquitto_new("Rookie_sub", true, NULL);
        if(mosq == NULL){
                DEBUG_ERROR("New error!\n");
                mosquitto_lib_cleanup();
                return -1;
        }


        // 设置连接的用户名与密码:,
        // 参数:句柄、用户名、密码
        ret = mosquitto_username_pw_set(mosq, "user_test", "123456");
        if(ret){
                DEBUG_ERROR("Set username and password error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

        // 设置回调函数
        // 参数:句柄、回调函数
        mosquitto_connect_callback_set(mosq, on_connect);
        mosquitto_disconnect_callback_set(mosq, on_disconnect);
        mosquitto_subscribe_callback_set(mosq, on_subscribe);
        mosquitto_message_callback_set(mosq, on_message);

        // 连接至服务器
        // 参数:句柄、ip(host)、端口、心跳
        // ret = mosquitto_connect_async(mosq, "127.0.0.1", 2020, 60);
        ret = mosquitto_connect_async(mosq, "127.0.0.1", 2020, 60);
        if(ret){
                DEBUG_ERROR("Connect server error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

        ret = mosquitto_loop_start(mosq);
        if(ret){
                DEBUG_ERROR("Start loop error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

        // 开始通信:循环执行、直到运行标志g_iRunFlag被改变
        DEBUG_PROCESS("Start!\n");
        while(g_iRunFlag)
        {
                //mosquitto_loop(mosq, -1, 1);
                sleep(1);
        }

        // 结束后的清理工作
        mosquitto_loop_stop(mosq, false);
        mosquitto_destroy(mosq);
        mosquitto_lib_cleanup();
        DEBUG_PROCESS("End!\n");

        return 0;
}


void on_connect(struct mosquitto *mosq, void *obj, int rc)
{
        DEBUG_PROCESS("Call the function: on_connect\n");

        if(rc){
                // 连接错误,退出程序
                DEBUG_ERROR("on_connect error!\n");
                exit(1);
        }else{
                // 订阅主题
                // 参数:句柄、id、订阅的主题、qos
                if(mosquitto_subscribe(mosq, NULL, "test/+", 2)){
                        DEBUG_ERROR("Set the topic error!\n");
                        exit(1);
                }
        }
}

void on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
        DEBUG_PROCESS("Call the function: on_disconnect\n");

        g_iRunFlag = 0;
}

void on_subscribe(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
{
        DEBUG_PROCESS("Call the function: on_subscribe\n");
}

void on_message(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
        DEBUG_PROCESS("Call the function: on_message\n");
        DEBUG_MSG("Recieve a message: %s\n", (char *)msg->payload);

        if(0 == strcmp(msg->payload, "quit")){
                mosquitto_disconnect(mosq);
        }
}
发布端
#include 
#include 
#include 
#include 
#include "mosquitto.h"

#define DEBUG_PROCESS   printf
#define DEBUG_ERROR     printf
#define DEBUG_MSG       printf

static int g_iRunFlag = 1;

void on_connect(struct mosquitto *mosq, void *obj, int rc);
void on_disconnect(struct mosquitto *mosq, void *obj, int rc);
void on_publish(struct mosquitto *mosq, void *obj, int mid);


int main()
{
        int ret;
        struct mosquitto *mosq;

        ret = mosquitto_lib_init();
        if(ret){
                DEBUG_ERROR("Init lib error!\n");
                return -1;
        }

        mosq =  mosquitto_new("Rookie_pub", true, NULL);
        if(mosq == NULL){
                DEBUG_ERROR("New error!\n");
                mosquitto_lib_cleanup();
                return -1;
        }

        // 设置MQTT遗言信息
        // 参数:句柄、主题、消息长度、消息内容、qos、是否保留
        ret = mosquitto_will_set(mosq, "test/will", strlen("pub_will_message"), "pub_will_message", 2, false);
        if(ret){
                DEBUG_ERROR("Set will message error!\n");
                return -1;
        }

        ret = mosquitto_username_pw_set(mosq, "user_test", "123456");
        if(ret){
                DEBUG_ERROR("Set username and password error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

        mosquitto_connect_callback_set(mosq, on_connect);
        mosquitto_disconnect_callback_set(mosq, on_disconnect);
        mosquitto_publish_callback_set(mosq, on_publish);

                ret = mosquitto_loop_start(mosq);
        if(ret){
                DEBUG_ERROR("Start loop error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

                // ret = mosquitto_connect(mosq, "127.0.0.1", 2020, 60);
        ret = mosquitto_connect_async(mosq, "127.0.0.1", 2020, 60);
        if(ret){
                DEBUG_ERROR("Connect server error!\n");
                mosquitto_destroy(mosq);
                mosquitto_lib_cleanup();
                return -1;
        }

        DEBUG_PROCESS("Start!\n");
        while(g_iRunFlag)
        {
                //mosquitto_loop(mosq, -1, 1);
                sleep(1);
        }

        mosquitto_loop_stop(mosq, false);
        mosquitto_destroy(mosq);
        mosquitto_lib_cleanup();
        DEBUG_PROCESS("End!\n");

        return 0;
}


void on_connect(struct mosquitto *mosq, void *obj, int rc)
{
        DEBUG_PROCESS("Call the function: on_connect\n");

        if(rc){
                DEBUG_ERROR("on_connect error!\n");
                exit(1);
        }else{
                        // 参数:句柄、id、主题、消息长度、消息、Qos、是否保留
                if(mosquitto_publish(mosq, NULL, "test/common", strlen("hello"), "hello", 2, false)){
                        DEBUG_ERROR("Set the topic error!\n");
                        exit(1);
                }
        }
}

void on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
        DEBUG_PROCESS("Call the function: on_disconnect\n");

        g_iRunFlag = 0;
}

void on_publish(struct mosquitto *mosq, void *obj, int mid)
{
        DEBUG_PROCESS("Call the function: on_publish\n");

        sleep(2);

        mosquitto_disconnect(mosq);
}

你可能感兴趣的:(MQTT)