Linux环境下使用Eclipse Paho C 实现(MQTT Client)异步订阅Message

news2024/11/29 20:40:28

目录

概述

1 认识Eclipse Paho C

1.1 paho.mqtt.c简介

1.2 下载和安装paho.mqtt.c

1.3 一些重要的函数

2 异步订阅消息实现

2.1 编写异步订阅消息功能

2.1.1 初始化MQTT参数

2.1.2 初始化函数

2.1.3 订阅消息的回调函数

2.1.4 取消订阅Topic

2.2 编译代码和测试

3 验证MQTT Client功能

3.1 EMQX服务器上查看MQTT Client

3.2 MQTT.fx发布Topic

4 完整实验代码 


概述

本文主要介绍在linux环境(ubuntu)环境下,下载和安装Eclipse Paho C MQTT 软件包,还编写一个范例实现异步订阅Message的功能,并使用基于EMQX的服务验证其功能,使用MQTT.fx发布消息,以验证订阅消息功能的可靠性。

1 认识Eclipse Paho C

1.1 paho.mqtt.c简介

paho.mqtt.c是一个使用C语言编写的MQTT客户端库,用于连接和与MQTT代理进行通信。它是Eclipse Paho项目的一部分,旨在为C开发人员提供一个易于使用、可靠和高性能的MQTT解决方案。

这个库允许开发人员创建MQTT客户端,该客户端可以连接到远程MQTT代理,并实现与代理之间的消息发布、订阅和管理等功能。paho.mqtt.c库提供了一套简单而直观的API,使开发人员能够轻松地使用MQTT协议进行通信。

paho.mqtt.c库支持多种MQTT协议版本,包括MQTTv3.1和MQTTv3.1.1。它提供了多种操作和配置选项,以适应不同的需求和场景。该库还提供了一些高级功能,例如支持SSL/TLS加密、持久化会话、消息保持和遗嘱消息等。

paho.mqtt.c库在多个平台上都可以使用,包括Windows、Linux、macOS和嵌入式系统等。它具有良好的可移植性和可扩展性,可以方便地与其他C语言项目集成。

总之,paho.mqtt.c是一个强大而灵活的MQTT客户端库,适用于使用C语言开发MQTT应用程序的开发人员。它简化了与MQTT代理的通信过程,并提供了丰富的功能和选项,使开发人员能够快速构建高性能的MQTT应用程序。

1.2 下载和安装paho.mqtt.c

登录mqtt官网,点击Software,可以看见如下页面,选择Eclipse Paho C进入下载页面

https://mqtt.org/

点击Eclipse Paho C后,会自动跳转到下载页面

笔者选择使用命令直接安装该软件包,具体操作步骤如下:

Step -1: 下载软件包执行命令:

git clone https://github.com/eclipse/paho.mqtt.c.git

step-2: 进入paho.mqtt.c目录,执行make

cd paho.mqtt.c
make

系统会自动编译代码,等待编译结果。

编译完成后,会自动生成build文件,这时可以安装

step-3 : 执行如下命令就可以安装软件

sudo make install

1.3 一些重要的函数

函数名称功能介绍
MQTTClient_create创建一个MQTT Client Object
MQTTClient_connect连接MQTT服务器
MQTTClient_disconnect断开MQTT服务器
MQTTClient_subscribe订阅Topic
MQTTClient_setCallbacks设置回调函数
MQTTClient_publishMessage发布消息
MQTTClient_unsubscribe取消订阅消息
MQTTClient_destroy销毁MQTT Client Object

2 异步订阅消息实现

2.1 编写异步订阅消息功能

2.1.1 初始化MQTT参数

参数功能介绍:

参数名称参数值描述
ADDRESStcp://192.168.1.11:1883mqtt broker的IP地址
CLIENTIDmqtt_ubuntu_asys设备ID
TOPICswitch订阅的Topic
QOS1服务质量等级=1
TIMEOUT10000L
USERNAMEmqtt_ubuntu_user终端认证username
PASSWORD123456终端认证username对应的password

在代码中修改的参数:

2.1.2 初始化函数

初始化MQTT终端需要完成以下4个步骤:

step-1: 创建MQTT Client

step-2: 配置回调函数

step-3: 连接服务器

step-4: 订阅Topic

具体实现代码如下:

代码57行:创建MQTT Client,需要传入服务器IP和Client ID信息

代码65行:配置callback函数,函数原型,见源码

代码72行: 心跳包时间间隔设置为20s

代码73行: 清除会话 标记设置为1,不接受离线消息

代码74行: 配置设备终端用户

代码75行: 配置设备终端用户password

代码76行: MQTT连接Broker

代码85行: 订阅topic

2.1.3 订阅消息的回调函数

该函数主要实现接收订阅的topic信息,并通过终端打印出来。

代码37行:打印订阅的Topic名称

代码38行:打印payload数据长度和payload原始数据

代码39行: 释放存储poyload信息内存

代码40行: 释放存储topic名称信息内存

2.1.4 取消订阅Topic

要取消订阅的Topic,调用MQTTClient_unsubscribe函数可以实现该功能。实现范例如下:

2.2 编译代码和测试

使用如下命令编译代码

 gcc test_02_Asynsubscription.c -lpaho-mqtt3c

执行.out文件后,打印的log提示,MQTT Client已经订阅了 topic为switch的消息。

3 验证MQTT Client功能

3.1 EMQX服务器上查看MQTT Client

在ubuntu上运行MQTT Client后,EMQX服务器会显示MQTT Client的运行状态,登录EMQX服务器可以看见

在订阅管理面板上,也可以看见mqtt_ubuntu_asys订阅了Topic为"switch"的消息

3.2 MQTT.fx发布Topic

使用MQTT.fx发布Topic为switch的消息,Client ID 为mqtt_ubuntu_asys的客户端订阅了该消息,那么当MQTT.fx发布消息之后,mqtt_ubuntu_asys会收到该消息,并在终端上打印出来。

要使用MQTT.fx MQTT Client工具订阅MQTTAsync,首先保证MQTT.fx能正常连接至EMQX服务器

使用MQTT.fx发布Topic为switch的消息

{ 
   "switch": false 
}

使用MQTT.fx发布Topic为switch的消息

{ 
   "switch": true 
}

在EMQX的保留信息页面,查看MQTT.fx发布Topic为switch的消息,该信息和Client ID 为mqtt_ubuntu_asys的客户端收到的信息一致

4 完整实验代码 

创建test_02_Asynsubscription.c,编写如下代码:

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名  : test_02_Asynsubscription.c
作者    : tangmingfei2013@126.com
版本    : V1.0
描述    : mqtt异步订阅消息
日志    : 初版V1.0 2024/03/13

***************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
 
#define ADDRESS     "tcp://192.168.1.11:1883"
#define CLIENTID    "mqtt_ubuntu_asys"
#define TOPIC       "switch"
#define QOS         1
#define TIMEOUT     10000L

#define USERNAME    "mqtt_ubuntu_user"
#define PASSWORD    "123456" 

 
volatile MQTTClient_deliveryToken deliveredtoken;
 
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}
 
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    printf("Message arrived\n");
    printf("     topic: %s\n", topicName);
    printf("   message: %.*s\n", message->payloadlen, (char*)message->payload);
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    
    return 1;
}
 
void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}
 
int main(int argc, char* argv[])
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;
 
    if ((rc = MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to create client, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto exit;
    }
 
    if ((rc = MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to set callbacks, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }
 
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;
    conn_opts.username = USERNAME;   //用户名
    conn_opts.password = PASSWORD;   //密码
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }
 
    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
    if ((rc = MQTTClient_subscribe(client, TOPIC, QOS)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to subscribe, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
    else
    {
        int ch;
        do
        {
                ch = getchar();
        } while (ch!='Q' && ch != 'q');
 
        if ((rc = MQTTClient_unsubscribe(client, TOPIC)) != MQTTCLIENT_SUCCESS)
        {
                printf("Failed to unsubscribe, return code %d\n", rc);
                rc = EXIT_FAILURE;
        }
    }
 
    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to disconnect, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
destroy_exit:
    MQTTClient_destroy(&client);
exit:
    return rc;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1529743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Lvs+keepalived+nginx搭建高可用负载均衡集群

环境配置 master主机192.168.199.149&#xff0c;虚拟IP192.168.199.148 back备机192.168.199.150 真实服务器1 192.168.199.155 真实服务器2 192.168.199.156 关闭防火墙和selinux master配置&#xff08;149&#xff09; 添加虚拟IP ip addr add 192.168.199.148/24 …

web前端之多种方式实现switch滑块功能、动态设置css变量、after伪元素、选择器、has伪类

MENU 效果图htmlcsshtmlcssJS 效果图 htmlcss html <div class"s"><input type"checkbox" id"si" class"si"><label for"si" class"sl"></label> </div>style * {margin: 0;pad…

IO多路复用、域套接字

思维导图 面试题TCP通信中的三次握手和四次&#xff1a; 客户端像向服务器端发送连接请求 服务器应答连接请求 客户端与服务器简历连接 客户端向服务器发送断开请求 服务器应答断开请求 服务器请求关闭连接 客户端发送确认应答 并行和并发的区别&#xff1a; 并行&#xff1a…

使用ChatGPT高效完成简历制作[中篇3]-有爱AI实战教程(十)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、导读&#xff1a; 在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#xff0c;…

【Linux】线程封装 | 线程互斥 | 基于阻塞队列的生产消费者模型

文章目录 一、线程封装二、Linux线程互斥进程线程间的互斥相关背景概念互斥量mutex为什么上面的抢票代码可能无法获得正确结果&#xff1f;&#xff08;票数为负&#xff09;互斥量的接口1. 初始化互斥量方法一&#xff1a;静态分配方法二&#xff1a;动态分配: 2. 销毁互斥量3…

性能优化(CPU优化技术)-NEON指令详解

原文来自ARM SIMD 指令集&#xff1a;NEON 简介 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xf…

如何让自己上百度百科?个人百科词条创建

百度百科&#xff0c;作为我国最大的中文百科全书&#xff0c;其影响力和权威性不言而喻。能够登上百度百科&#xff0c;意味着个人的知名度、成就和社会影响力得到了广泛认可。那么&#xff0c;如何才能让自己上百度百科呢&#xff1f;接下来伯乐网络传媒就来给大家讲解一下。…

HarmonyOS NEXT应用开发之Navigation实现多设备适配案例

介绍 在应用开发时&#xff0c;一个应用需要适配多终端的设备&#xff0c;使用Navigation的mode属性来实现一套代码&#xff0c;多终端适配。 效果图预览 使用说明 将程序运行在折叠屏手机或者平板上观看适配效果。 实现思路 本例涉及的关键特性和实现方案如下&#xff1a…

[AIGC] 在Spring Boot中指定请求体格式

在使用Spring Boot开发Web应用的时候&#xff0c;我们经常会遇到需要接收并处理HTTP请求的情况。一个HTTP请求通常包括一个请求行、若干请求头和一个请求体。请求体在POST和PUT请求中特别重要&#xff0c;因为它通常用于向服务器传递数据。 文章目录 创建并使用一个Java Bean指…

分布式搜索引擎elasticsearch专栏三

1.数据聚合 聚合&#xff08;aggregations&#xff09;可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a; 什么品牌的手机最受欢迎&#xff1f; 这些手机的平均价格、最高价格、最低价格&#xff1f; 这些手机每月的销售情况如何&#xff1f; 实现这些…

3.19作业

1、思维导图 2、模拟面试题 1&#xff09;TCP通信中的三次握手和四次挥手 答&#xff1a;三次握手 客户端向服务器发送连接请求 服务器向客户端回复应答并向客户端发送连接请求 客户端回复服务端&#xff0c;并建立联系 四次挥手 进程a向进程b发送断开连接请求…

vue axios 缓存 接口请求实现缓存加载

文章写的多了&#xff0c;开头就不知道怎么写了&#xff0c;硬挤一些句子总觉的卖弄。其实更多的想留下各位看官&#xff0c;多多的点赞&#xff0c;多多的关注&#xff0c;多的收藏。为将来的博客化动作做好前期数据粉丝基础。哦哦哦&#xff0c;我在想啥呢。。这大下午的。。…

软件工程-第11章 内容总结

如果不想读这本书&#xff0c;直接看这一章即可。 11.1 关于软件过程范型 11.2 关于软件设计方法

java算法第28天 | 93.复原IP地址 78.子集 90.子集II

93.复原IP地址 思路&#xff1a; 这里startIndex为插入‘.’的位置&#xff0c;使用回溯法遍历所有插入的位置&#xff0c;直接在原始字符串上操作。要注意的是开闭区间的规定&#xff08;这里我规定的是左闭右闭区间&#xff09;。还要明确什么时候能return。 class Solution…

在 vite 开发环境,使用https自签证书 --- mkcert

在 vite 开发环境&#xff0c;使用https自签证书 — mkcert 使用basicSsl&#xff08;vitejs/plugin-basic-ssl&#xff09; 在vite开发环境中&#xff0c;使用 basicSsl 插件能暂时提供https服务&#xff0c;同时&#xff0c;也会面临总是提示一下的问题,如下图 提示https证…

2024.3.20 使用maven打包jar文件和保存到本地仓库

2024.3.20 使用maven打包jar文件和保存到本地仓库 使用maven可以很方便地打包jar文件和导入jar文件&#xff0c;同时还可以将该文件保存在本地仓库重复调用。 使用maven打包jar文件和保存到本地仓库 package打包文件。 install导入本地仓库。 使用maven导入jar文件 点击“…

智能合约 之 部署ERC-20

Remix介绍 Remix是一个由以太坊社区开发的在线集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在帮助开发者编写、测试和部署以太坊智能合约。它提供了一个简单易用的界面&#xff0c;使得开发者可以在浏览器中直接进行智能合约的开发&#xff0c;而无需安装任何额外的…

WPF —— 控件模版和数据模版

1:控件模版简介: 自定义控件模版&#xff1a;自己添加的样式、标签&#xff0c;控件模版也是属于资源的一种&#xff0c; 每一个控件模版都有一唯一的 key&#xff0c;在控件上通过template属性进行绑定 什么场景下使用自定义控件模版&#xff0c;当项目里面多个地方…

基于python考试分析系统的设计和实现-flask-django-nodejs-php

随着电子技术的普及和快速发展&#xff0c;线上管理系统被广泛的使用&#xff0c;有很多商业机构都在实现电子信息化管理&#xff0c;图书推荐也不例外&#xff0c;由比较传统的人工管理转向了电子化、信息化、系统化的管理。   本文的重点是对考试分析系统展开了详细的描述&a…

整型数组按个位值排序 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元素&#xf…