基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅

1、MQTT介绍

MQTT协议就是一个通信协议,通信架构可以参考如下图片

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第1张图片topic可以理解为消息的中转地址,无论是订阅消息还是发布消息,都需要指定topic。发布者往指定topic发布消息,订阅者如果订阅了该topic,则可收到发布者的这一条消息。

2、paho-mqtt-embended库的介绍、编译及使用

https://www.eclipse.org/paho/index.php?page=downloads.php

用的是rv1126,属于嵌入式平台,所以选择Embedded C/C++版本,源码地址:GitHub - eclipse/paho.mqtt.embedded-c: Paho MQTT C client library for embedded systems. Paho is an Eclipse IoT project (https://iot.eclipse.org/)

首先进入paho.mqtt.embedded-c目录,修改Makefile

CC ?= arm-linux-gnueabihf-gcc

接下来开始编译,在终端输入以下命令:

zwx@ubuntu:~/rv1126/mqtt/paho.mqtt.embedded-c$ make
zwx@ubuntu:~/rv1126/mqtt/paho.mqtt.embedded-c$ sudo make install

编译完成如下图所示:

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第2张图片

编译生成的库文件保存在目录paho.mqtt.embedded-c/build/output下,将这三个库文件放在RV1126的/usr/lib目录下,就可以在板子上使用mqtt了。

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第3张图片

3、使用emqx和mqtt.fx进行订阅和发布的测试

emqx可以在本地搭建一个MQTT服务器,而mqtt.fx可以模拟一个mqtt客户端,测试思路如下:先用emqx搭建服务器,rv1126使用以太网接入电脑。mqtt.fx模拟的客户端和rv1126搭建的客户端可以通过emqx搭建的MQTT服务器进行通信。

Emqx的使用方法非常简单,解压之后打开bin文件夹,打开cmd,输入 emqx.cmd start 回车。Mqtt服务器就搭建完成了。可以在浏览器输入http://localhost:18083/ 进入服务器后台管理。

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第4张图片

 基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第5张图片

 mqtt.fx的使用方法也非常简单,打开软件后点击齿轮按钮进行设置,一般来说只需要修改IP地址就可以。

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第6张图片

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第7张图片

设置完成后就可以点击connect按钮来进行连接了,此时mqtt.fx模拟的MQTT客户端已经连接上我们刚才使用emqx搭建的服务器了。

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第8张图片

接下来需要在rv1126中搭建一个mqtt客户端,并向pub_test这一个topic发布消息。如果成功的话,mqtt.fx软件上将会订阅到由rv1126发布的消息内容,说明发送功能正常。再用mqtt.fx向pub_test发布消息,如果正常的话,rv1126将会订阅到这条消息。测试代码我贴上来了,代码实现了订阅和发送功能。将代码放到paho.mqtt.embedded-c/MQTTClient-C/samples/linux目录下编译,编译完之后将生成的可执行文件放到rv1126板子上运行即可。记得修改该目录下的build.sh文件哦。

#include 
#include 
#include "MQTTClient.h"

#include 
#include 

#include 


volatile int toStop = 0;


void usage()
{
	printf("MQTT stdout subscriber\n");
	printf("Usage: stdoutsub topicname , where options are:\n");
	printf("  --host  (default is localhost)\n");
	printf("  --port  (default is 1883)\n");
	printf("  --qos  (default is 2)\n");
	printf("  --delimiter  (default is \\n)\n");
	printf("  --clientid  (default is hostname+timestamp)\n");
	printf("  --username none\n");
	printf("  --password none\n");
	printf("  --showtopics  (default is on if the topic has a wildcard, else off)\n");
	exit(-1);
}


void cfinish(int sig)
{
	signal(SIGINT, NULL);
	toStop = 1;
}


struct opts_struct
{
	char* clientid;
	int nodelimiter;
	char* delimiter;
	enum QoS qos;
	char* username;
	char* password;
	char* host;
	int port;
	int showtopics;
} opts =
{
	(char*)"52JMT02RD002", 0, (char*)"\n", QOS1, NULL, NULL, (char*)"192.168.7.101", 1883, 1
};


void getopts(int argc, char** argv)
{
	int count = 2;
	
	while (count < argc)
	{
		if (strcmp(argv[count], "--qos") == 0)
		{
			if (++count < argc)
			{
				if (strcmp(argv[count], "0") == 0)
					opts.qos = QOS0;
				else if (strcmp(argv[count], "1") == 0)
					opts.qos = QOS1;
				else if (strcmp(argv[count], "2") == 0)
					opts.qos = QOS2;
				else
					usage();
			}
			else
				usage();
		}
		else if (strcmp(argv[count], "--host") == 0)
		{
			if (++count < argc)
				opts.host = argv[count];
			else
				usage();
		}
		else if (strcmp(argv[count], "--port") == 0)
		{
			if (++count < argc)
				opts.port = atoi(argv[count]);
			else
				usage();
		}
		else if (strcmp(argv[count], "--clientid") == 0)
		{
			if (++count < argc)
				opts.clientid = argv[count];
			else
				usage();
		}
		else if (strcmp(argv[count], "--username") == 0)
		{
			if (++count < argc)
				opts.username = argv[count];
			else
				usage();
		}
		else if (strcmp(argv[count], "--password") == 0)
		{
			if (++count < argc)
				opts.password = argv[count];
			else
				usage();
		}
		else if (strcmp(argv[count], "--delimiter") == 0)
		{
			if (++count < argc)
				opts.delimiter = argv[count];
			else
				opts.nodelimiter = 1;
		}
		else if (strcmp(argv[count], "--showtopics") == 0)
		{
			if (++count < argc)
			{
				if (strcmp(argv[count], "on") == 0)
					opts.showtopics = 1;
				else if (strcmp(argv[count], "off") == 0)
					opts.showtopics = 0;
				else
					usage();
			}
			else
				usage();
		}
		count++;
	}
	
}


void messageArrived(MessageData* md)
{
//	printf("messageArrived!!!!!!!!!\n");
	MQTTMessage* message = md->message;

	if (opts.showtopics)
		printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
	if (opts.nodelimiter)
		printf("%.*s", (int)message->payloadlen, (char*)message->payload);
	else
		printf("%.*s%s", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
	//fflush(stdout);
}


int main(int argc, char** argv)
{
	int rc = 0;
	unsigned char buf[100];
	unsigned char readbuf[100];
	
	if (argc < 2)
		usage();
	
	char* topic = argv[1];
    char* topic_sub = "/v1/devices/02_52JMT02RD002/command";
    int cnt = 0;
    unsigned int msgid = 0;

	if (strchr(topic, '#') || strchr(topic, '+'))
		opts.showtopics = 1;
	if (opts.showtopics)
		printf("topic is %s\n", topic);

	getopts(argc, argv);	

	Network n;
	MQTTClient c;

	signal(SIGINT, cfinish);
	signal(SIGTERM, cfinish);

	NetworkInit(&n);
	NetworkConnect(&n, opts.host, opts.port);
	MQTTClientInit(&c, &n, 1000, buf, 1024, readbuf, 1024);
 
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;       
	data.willFlag = 0;
	data.MQTTVersion = 3;
	data.clientID.cstring = opts.clientid;
	data.username.cstring = opts.username;
	data.password.cstring = opts.password;

	data.keepAliveInterval = 10;
	data.cleansession = 1;
	printf("Connecting to %s %d\n", opts.host, opts.port);
	
	rc = MQTTConnect(&c, &data);
	printf("Connected %d\n", rc);
    
    printf("Subscribing to %s\n", topic_sub);
	rc = MQTTSubscribe(&c, topic_sub, opts.qos, messageArrived);
	printf("Subscribed %d\n", rc);

	while (!toStop)
	{
		MQTTYield(&c, 1000);
        char msg_mqtt_uploadfile[1000] = "123123123";

        MQTTMessage msg =
                    {
                            QOS1,
                            0,
                            0,
                            0,
                            (void *)msg_mqtt_uploadfile,
                            strlen((char *)msg_mqtt_uploadfile),
                    };
        msg.id = ++msgid;
        rc = MQTTPublish(&c, topic, &msg);
        printf("MQTTPublish %d, msgid %d\n", rc, msgid);
	}

	printf("Stopping\n");

	MQTTDisconnect(&c);
	NetworkDisconnect(&n);

	return 0;
}

下面是我用home/garden/fountain这一个topic的测试成功截图

基于paho.mqtt库在rv1126平台实现MQTT消息的发布与订阅_第9张图片

 至此就大功告成啦~

你可能感兴趣的:(iot,linux,c++)