工具 mosquitto

一、mosquitto基本使用

1、下载与编译

wget http://mosquitto.org/files/source/mosquitto-1.5.5.tar.gz
解压后 make && make install

2、交叉编译

更改CMakeLists.txt
添加:
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
SET(CMAKE_C_COMPILER /home/test/am3352/ti-processor-sdk-linux-rt-am335x-evm-04.03.00.05/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER /home/test/am3352/ti-processor-sdk-linux-rt-am335x-evm-04.03.00.05/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-linux-gnueabihf-g++)

然后执行:
mkdir cross && cd cross && cmake … & make
编译完成后cross目录下就出现了lib、src/mosquitto、client/测试程序。

3、启动mosquitto mosquitto -d -v

mosquitto [-c config file] [ -d | --daemon ] [-p port number] [-v]
参数说明:
-c 后面跟的是启动mosquitto可以调整的参数,比如是否开启基本认证,端口是什么,SSL单向和双向的认证配置等等。
-d 表示MQTT mosquitto将在后台运行。
-p 代表当前的mosquitto服务实例启动以后,其监听端口号,这个配置的覆盖[-c config file] 指定的配置文件中的端口。
-v 代码调试模式(verbose)在终端输出更多的信息。

4、测试

(1)订阅命令mosquitto_sub参数说明
-d 打印debug信息
-h 指定要连接的域名 默认为localhost
-i 指定clientId
-I 指定clientId前缀
-k keepalive 每隔一段时间,发PING消息通知broker仍处于连接状态,默认为60秒。
-q 指定希望接收到QoS为什么的消息 默认QoS为0
-R 不显示陈旧的消息
-t 订阅topic
-v 打印消息
–will-payload 指定一个消息,该消息当客户端与broker意外断开连接时发出。该参数需要与–will-topic一起使用
–will-qos Will的QoS值。该参数需要与–will-topic一起使用
–will-retain 指定Will消息被当做一个retain消息(即消息被广播后,该消息被保留起来)。该参数需要与–will-topic一起使用
–will-topic 用户发送Will消息的topic
(2)发布命令mosquitto_pub参数说明
-d 打印debug信息
-f 将指定文件的内容作为发送消息的内容
-h 指定要连接的域名 默认为localhost
-i 指定要给哪个clientId的用户发送消息
-I 指定给哪个clientId前缀的用户发送消息
-m 消息内容
-n 发送一个空(null)消息
-p 连接端口号

-q 指定QoS的值(0,1,2)
-t 指定topic
-u 指定broker访问用户
-P 指定broker访问密码
-V 指定MQTT协议版本
–will-payload 指定一个消息,该消息当客户端与broker意外断开连接时发出。该参数需要与–will-topic一起使用
–will-qos Will的QoS值。该参数需要与–will-topic一起使用
–will-retain 指定Will消息被当做一个retain消息(即消息被广播后,该消息被保留起来)。该参数需要与–will-topic一起使用
–will-topic 用户发送Will消息的topic
(3)测试详情,三个客户端同时订阅另一客户端的消息
在这里插入图片描述

5、问题解决

(1)mosquitto_sub: error while loading shared libraries: libmosquitto.so.1: cannot open shared object file: No such file or directory

ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1

(2)Starting in local only mode. Connections will only be possible from clients running on this machine

大于2.0.0版本的mosquitto,默认配置只会绑定到localhost,如果希望其他机器访问,
需要使用配置文件添加:
listener 1883
默认情况下,不允许匿名连接(没有用户名/密码),如果想允许匿名连接:
allow_anonymous true

二、mosquitto库

1、常用函数说明

1、库的初始化与清除

(1)初始化mosquitto库,必须在任何其他mosqtto函数前调用

int mosquitto_lib_init (NULL);
返回值:
MOSQ_ERR_SUCCESS:成功。
MOSQ_ERR_UNKNOWN:在 Windows 上,无法初始化套接字。

(2)释放与库关联的资源

int mosquitto_lib_cleanup (NULL);
返回值:MOSQ_ERR_SUCCESS 总是

2、客户端创建与销毁

(1)创建一个新的 mosquitto 客户端实例

struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);
.id::用作客户端 ID 的字符串。如果为 NULL,将生成一个随机客户端 ID。如果 id 为 NULL,则 clean_session 必须为真。
.clean_session:设置为 true 指示代理在断开连接时清除所有消息和订阅。设置为 false 指示它保留它们,注意,客户端永远不会在断开连接时丢弃自己的传出消息。调用mosquitto_connect或mosquitto_reconnect将导致消息被重新发送。使用mosquitto_reinitialise将客户端重置为其原始状态。如果 id 参数为 NULL,则必须设置为 true。
.obj: 用户指针,将作为参数传递给指定的任何回调。
返回值:成功则指向struct mosquitto类型的指针。失败时为 NULL。可查询 errno 以确定失败的原因。

(2)释放与 mosquitto客户端实例关联的内存

void mosquitto_destroy(struct mosquitto  *mosq);

3、用户名和密码

(1)为 mosquitto实例配置用户名和密码。默认情况下,不发送用户名或密码。此函数必须在调用mosquitto_connect之前调用,是否需要调用此函数取决于broker设置了匿名访问。

int mosquitto_username_pw_set(struct  mosquitto  *mosq, const  char  *username, const char  *password);
.mosq:mosquitto实例。
.username:用户名字符串,或 NULL 以禁用身份验证。
.password:密码字符串。当用户名有效时设置为 NULL,则仅发送用户名。

4、连接

(1)连接到broker

int mosquitto_connect(struct mosquitto *mosq, const char *host, int port, int keepalive);
.mosq:mosquitto实例。
.host:broker的主机名或 IP 地址。
.port:网络端口,通常是 1883 。
.keepalive:如果在这段时间内(秒数)没有交换其他消息,broker应该向客户端发送 PING 消息。

(2)重新连接到broker,可使用此函数在连接丢失后重新连接,它使用mosquitto_connect调用中提供的值。不能在mosquitto_connect之前调用。

int mosquitto_reconnect(struct mosquitto *mosq);

(3)断开连接

int mosquitto_disconnect(struct mosquitto *mosq);

5、发布与订阅

(1)发布给定主题的消息

int mosquitto_publish(struct mosquitto *mosq,int *mid, const char *topic,int payloadlen, const void *payload,int qos,bool retain);
.mosq:mosquitto实例。
.mid:指向 int 的指针。如果不为 NULL,该函数会将其设置为此特定消息的消息 ID。然后可以将其与发布回调一起使用,以确定何时发送消息。请注意,尽管 MQTT 协议不对 QoS=0 的消息使用消息 ID,但 libmosquitto 会为它们分配消息 ID,以便可以使用此参数跟踪它们。
.topic:要发布到的主题的以 null 结尾的字符串。
.payloadlen:有效载荷的大小(字节)。有效值介于 0 和 268,435,455 之间。
.payload:有效载荷,指向要发送的数据的指针。如果 payloadlen > 0 这必须是一个有效的内存位置。
.qos:服务质量,整数值0、1 或 2,指示要用于消息的服务质量。
.retain:保持,设置为 true 以使消息保留

(2)订阅一个主题,需等待客户端连接成功后才可订阅,连接断开重连后需要重新订阅,所以订阅一般放在连接回调中。

int mosquitto_subscribe(struct mosquitto *mosq, int *mid, const char *sub,int qos);
.mosq:mosquitto实例。
.mid:指向 int 的指针。如果不为 NULL,该函数会将其设置为此特定消息的消息 ID。然后可以将其与 subscribe 回调一起使用,以确定消息何时发送。
.sub:订阅主题。
.qos:服务质量,此订阅请求的服务质量。

(3)退订一个主题

int mosquitto_unsubscribe(struct mosquitto *mosq, int *mid, const char *sub);
.mosq:一个有效的mosquitto实例。
.mid:指向 int 的指针。如果不为 NULL,该函数会将其设置为此特定消息的消息 ID。然后可以将其与取消订阅回调一起使用,以确定消息何时发送。
.sub:退订主题。

6、回调设置

(1)连接成功回调设置

void mosquitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int));
.mosq:mosquitto实例。
.on_connect:回调函数,形式为 void callback(struct mosquitto *mosq, void *obj, int rc)。
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据
	.rc:连接响应的返回码。这些值由使用的MQTT协议版本定义。

(2)断开连接回调设置

void mosquitto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int));
.mosq:mosquitto实例。
.on_disconnect:回调函数,形式为void callback(struct mosquitto *mosq, void *obj, int rc)。
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据
	.rc:指示断开连接原因的整数值。值 0 表示客户端已调用mosquitto_disconnect。任何其他值表示断开是意外的。

(3)发布回调设置,消息成功发送到broker后执行

void mosquitto_publish_callback_set(struct 	mosquitto *mosq,void (*on_publish)(struct mosquitto *, void *, int))
.mosq:mosquitto实例。
.on_disconnect:回调函数,形式为 void callback(struct mosquitto *mosq, void *obj, int mid);
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据
	.mid:已发送消息的消息 ID。

(4)订阅回调设置,broker响应订阅请求时调用

void mosquitto_subscribe_callback_set(struct  mosquitto *mosq,
void  (*on_subscribe)(struct mosquitto *, void *, int, int, const int *));
.mosq:mosquitto实例。
.on_subscribe:回调函数,形式为 void callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos);
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据。
	.mid:订阅消息的消息 ID。
	.qos_count:授予订阅的数量(granted_qos 的大小)。
	.grant_qos:一个整数数组,指示每个订阅的授予 QoS。

(5)消息回调设置,从broker接收到消息时调用

void mosquitto_message_callback_set(struct mosquitto *mosq, void  (*on_message)(struct mosquitto *, void *, const struct mosquitto_message *))
.mosq:mosquitto实例。
.on_message:回调函数,形式为void callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据。
	.message:消息数据。回调完成后,该变量和关联的内存将由库释放。客户应该复制它需要的任何数据。

(6)取消订阅回调设置,当broker响应取消订阅请求时调用

void mosquitto_unsubscribe_callback_set(struct mosquitto *mosq, void (*on_unsubscribe)(struct mosquitto *, void *, int));
.mosq:mosquitto实例。
.on_unsubscribe:回调函数,形式为 void callback(struct mosquitto *mosq, void *obj, int mid)
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据
	.mid:取消订阅消息的消息 ID。

(7)日志记录回调设置,如果需要来自客户端库的事件日志信息,则应使用此选项

void mosquitto_log_callback_set(struct 	mosquitto 	*mosq, void (*on_log)(struct mosquitto *, void *, int, const char *));
.mosq:mosquitto实例。
.on_log:回调函数,形式为void callback(struct mosquitto *mosq, void *obj, int level, const char *str)
	.mosq:mosquitto 实例。
	.obj:mosquitto_new中提供的用户数据
	.level:来自值的日志消息级别: MOSQ_LOG_INFO、 MOSQ_LOG_NOTICE、 MOSQ_LOG_WARNING、 MOSQ_LOG_ERR、 MOSQ_LOG_DEBUG
	.str:消息字符串。

7、循环

(1)libmosquitto必须循环处理一些网络消息,必须经常调用如下函数以保持客户端与broker之间的通信正常,此函数不能在回调中调用。此函数一般不使用,一般使用mosquitto_loop_forever和mosquitto_loop_start

int mosquitto_loop(struct 	mosquitto 	*mosq, int timeout, int max_packets);
.mosq:mosquitto实例。
.timeout:在超时之前等待 select() 调用中的网络活动的最大毫秒数。设置为 0 以立即返回。设置负数以使用默认值 1000 毫秒。
.max_packets:此参数当前未使用,应设置为 1 以便将来兼容。

(2)阻塞循环调用loop,如果服务器连接丢失,它会处理重新连接。如果在回调中调用 mosquitto_disconnect(),它将返回。

int mosquitto_loop_forever(struct mosquitto  *mosq, int  timeout, int  max_packets);
.mosq:mosquitto实例。
.timeout:在超时之前等待 select() 调用中的网络活动的最大毫秒数。设置为 0 以立即返回。设置负数以使用默认值 1000 毫秒。
.max_packets:此参数当前未使用,应设置为 1 以便将来兼容。

(3)非阻塞方式调用loop,其实就是创建了一个线程

int mosquitto_loop_start( struct mosquitto *mosq);
.mosq:mosquitto实例。

(4)停止使用mosquitto_loop_start创建的网络线程。此调用将阻塞,直到网络线程完成。要结束网络线程,必须调用mosquitto_disconnect或将 force 参数设置为 true。

int mosquitto_loop_stop(struct mosquitto *mosq, bool  force);

2、示例

1、订阅sub.c

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

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

struct sub {
    struct mosquitto *mosq;
    int running;
    int private;
} sub;

static void connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    int ret;
    struct sub *sub = (struct sub *)obj;
    printf("%s private:%x\n", __func__, sub->private);
    if (!rc) {
        sub->running = 1;
        ret = mosquitto_subscribe(mosq, NULL, "sub1", 2);
        if (ret) {
            perror("subscribe failed");
            exit(-1);
        }
        ret = mosquitto_subscribe(mosq, NULL, "sub2", 2);
        if (ret) {
            perror("subscribe failed");
            exit(-1);
        }
    } else {
        perror("connect failed");
    }
}

static void disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    struct sub *sub = (struct sub *)obj;
    sub->running = 0;
    printf("%s\n", __func__);
}

void subscribe_callback(struct mosquitto *mosq, void *obj, int mid, int qos_count, const int *granted_qos)
{
    printf("%s\n", __func__);
}

void message_callback(struct mosquitto *mosq, void *obj,
                      const struct mosquitto_message *msg)
{
    struct sub *sub = (struct sub *)obj;
    printf("%s\n", __func__);
    printf("Recieve message:\n \ttopic:%s\n\tpayload:%s\n\tpayloadlen:%d\n",
           (char *)msg->topic, (char *)msg->payload, msg->payloadlen);
}

void log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
{
    printf("%s\n", __func__);
    printf("log level:%d str:%s\n", level, str);
}

int main(int argc, char **argv)
{
    struct mosquitto *mosq = sub.mosq;
    sub.private = 0xaa55;
    sub.running = 0;
    int ret = 0;

    mosquitto_lib_init();

    mosq = mosquitto_new("sub", true, &sub);
    if (mosq == NULL) {
        perror("create mosquitto failed");
        ret = -1;
        goto cleanup_lib;
    }
    mosquitto_connect_callback_set(mosq, connect_callback);
    mosquitto_disconnect_callback_set(mosq, disconnect_callback);
    mosquitto_subscribe_callback_set(mosq, subscribe_callback);
    mosquitto_message_callback_set(mosq, message_callback);
    //mosquitto_log_callback_set(mosq, log_callback);

    ret = mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE);
    if (ret) {
        perror("connect failed");
        goto destroy_mosquitto;
    }

    ret = mosquitto_loop_start(mosq);
    if (ret) {
        perror("loop failed");
        goto destroy_mosquitto;
    }
    while (!sub.running) {
        sleep(1);
    }
    getchar();

destroy_mosquitto:
    mosquitto_destroy(mosq);
cleanup_lib:
    mosquitto_lib_cleanup();
end:
    return ret;
}

2、发布pub.c

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

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

struct pub {
    struct mosquitto *mosq;
    int running;
    int private;
} pub;

static void connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    int ret;
    struct pub *pub = (struct pub *)obj;
    printf("%s private:%x\n", __func__, pub->private);
    if (!rc) {
        pub->running = 1;
    } else {
        perror("connect failed");
    }
}

static void disconnect_callback(struct mosquitto *mosq, void *obj, int rc)
{
    struct pub *pub = (struct pub *)obj;
    pub->running = 0;
    printf("%s\n", __func__);
}

void subscribe_callback(struct mosquitto *mosq, void *obj, int mid,
                        int qos_count, const int *granted_qos)
{
    printf("%s\n", __func__);
}

void message_callback(struct mosquitto *mosq, void *obj,
                      const struct mosquitto_message *msg)
{
    struct pub *pub = (struct pub *)obj;
    printf("%s\n", __func__);
    printf("Recieve message:\n \ttopic:%s\n\tpayload:%s\n\tpayloadlen:%d\n",
           (char *)msg->topic, (char *)msg->payload, msg->payloadlen);
}

void publish_callback(struct mosquitto *mosq, void *obj, int mid)
{
    printf("%s\n", __func__);
}

void log_callback(struct mosquitto *mosq, void *obj, int level, const char *str)
{
    printf("%s\n", __func__);
    printf("log level:%d str:%s\n", level, str);
}

int main(int argc, char **argv)
{
    struct mosquitto *mosq = pub.mosq;
    pub.private = 0xaa55;
    pub.running = 0;
    int ret = 0, i;
    char buf[32] = {0};

    mosquitto_lib_init();

    mosq = mosquitto_new("pub", true, &pub);
    if (mosq == NULL) {
        perror("create mosquitto failed");
        ret = -1;
        goto cleanup_lib;
    }
    mosquitto_connect_callback_set(mosq, connect_callback);
    mosquitto_disconnect_callback_set(mosq, disconnect_callback);
    mosquitto_publish_callback_set(mosq, publish_callback);
    // mosquitto_log_callback_set(mosq, log_callback);

    ret = mosquitto_connect(mosq, HOST, PORT, KEEP_ALIVE);
    if (ret) {
        perror("connect failed");
        goto destroy_mosquitto;
    }

    ret = mosquitto_loop_start(mosq);
    if (ret) {
        perror("loop failed");
        goto destroy_mosquitto;
    }
    while (!pub.running) {
        sleep(1);
    }
    for (i = 0; i < 100; i++) {
        snprintf(buf, sizeof(buf), "pub:%d", i);
        ret = mosquitto_publish(mosq, NULL, "sub1", strlen(buf), buf, 0, 1);
        if(ret){
            perror("pub failed");
        }
        ret = mosquitto_publish(mosq, NULL, "sub2", strlen(buf), buf, 0, 1);
        if(ret){
            perror("pub failed");
        }
        sleep(1);
    }
    getchar();

destroy_mosquitto:
    mosquitto_destroy(mosq);
cleanup_lib:
    mosquitto_lib_cleanup();
end:
    return ret;
}

3、测试在这里插入图片描述

三、实用工具

1、mqtt.fx
http://mqttfx.jensd.de/index.php/download
MQTT.fx是MQTT客户端工具,支持通过Topic订阅和发布消息,可以方便测试我们自己的程序是否正确发布了或者订阅了消息。
2、mosquitto window
https://mosquitto.org/download/
windows下的mosquitto可以帮助我们测试客户端程序。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值