MQTT---linux简单通信demo(从broker到client)

1.MQTT broker---EMQX

首先我们需要一个MQTT的服务器作为消息分发处理的核心,这里使用开源的EMQX---https://github.com/emqx/emqx

EMQX使用指南:https://docs.emqx.io/broker/v3/cn/

这个网址里面的是其官方的指导手册,内容非常齐全,可以参考

在github上下载对应的版本,由于我的pc机系统版本为ubuntu1604,所以我这边选择的版本是emqx-ubuntu16.04-v3.2.2.zip(我电脑选择deb版本的运行emqx失败,所以选择的是zip版本)

MQTT---linux简单通信demo(从broker到client)_第1张图片

在下载时我们可以先配置firewall防火墙策略(或者直接关闭linux防火墙):

#注意:这里只开放两个常用的端口,EMQ 还有其他一些服务端口(具体见文章末尾),大家可以按需开放。
firewall-cmd --permanent --add-port=1883/tcp
firewall-cmd --permanent --add-port=18083/tcp
firewall-cmd --reload

现在下载完成后执行

#解压生成emqx文件夹
unzip emqx-ubuntu16.04-v3.2.2.zip

#进入该emqx文件夹
cd emqx

#启动 emqx
./bin/emqx start
#执行该命令会在打印 successful。。。,但是安装deb包没有打印,奇怪,,,

#检查运行状态
./bin/emqx_ctrl status
#执行该命令同样也会打印,但是安装deb包没有打印,奇怪+1,,,

#停止 emqx命令
./bin/emqx stop

EMQ X 默认加载 Dashboard 插件,启动 Web 管理控制台。用户可通过 Web 控制台,查看服务器运行状态、统计数据、连接(Connections)、会话(Sessions)、主题(Topics)、订阅(Subscriptions)、插件(Plugins)等。

控制台地址: http://127.0.0.1:18083,获取ip换成PC机在局域网内的ip,默认用户名: admin,密码:public

显示如下(默认的显示是英文,在左下角setting设置中文显示即可)

MQTT---linux简单通信demo(从broker到client)_第2张图片

2.MQTT client---paho.mqtt.c

2.1 openssl安装

使用paho.mqtt.c之前,我们需要首先在ubuntu1604上安装openssl

首先在github(https://github.com/openssl/openssl)上下载tar包,这里我下载的是openssl-OpenSSL_1_1_1b.tar.gz

#首先解压源码包
tar xvf openssl-OpenSSL_1_1_1b.tar.gz

#进入文件夹
cd openssl-OpenSSL_1_1_1b

./config
sudo make
sudo make install

最终openssl的库文件被安装到了/usr/local/lib ,头文件位置为 /usr/local/include/openssl

执行 openssl version -a 命令,可以看到具体的openssl安装信息

2.2 paho.mqtt.c编译

这里我们直接在github上下载paho.mqtt.c源代码https://github.com/eclipse/paho.mqtt.c

这里我下载最新releases的paho.mqtt.c-1.3.1.tar.gz

#首先解压tar包
tar xvf paho.mqtt.c-1.3.1.tar.gz

#进入文件夹
cd paho.mqtt.c-1.3.1

在这里,我们需要修改paho.mqtt.c-1.3.1根目录下的Makefile

MQTT---linux简单通信demo(从broker到client)_第3张图片

修改完成如上所示,主要是修改paho.mqtt链接openssl库和头文件的位置信息

修改完成后继续执行编译

make

sudo make install

install后该库和头文件被安装到了/usr/local/lib /usr/local/include目录下

同时,在src/sample目录下有一些mqtt client的例子我们可以用来参考,了解如何调用paho.mqtt.c做订阅端和发布端

例如src/sample目录下的MQTTClient_publish.c MQTTClient_subscribe.c

MQTTClient_publish.c

#include 
#include 
#include 
#include 
#include "MQTTClient.h"

#define ADDRESS     "192.168.31.18:1883"
#define CLIENTID    "ExampleClientPub"
#define TOPIC       "test321"
#define PAYLOAD     "Hello World!"
#define QOS         2
#define TIMEOUT     10000L

int main(int argc, char* argv[])
{
	char publish_message[20];
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc;

    MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    pubmsg.payload = publish_message;
    //pubmsg.payloadlen = (int)strlen(PAYLOAD);
    pubmsg.payloadlen = 20;
    pubmsg.qos = QOS;
    pubmsg.retained = 0;
    
	int t = 0;
	while(1) {
		snprintf(publish_message,20,"message=%d",t++);
		pubmsg.payloadlen = (int)strlen(publish_message);
		MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
		printf("PUB>%s\n",publish_message);
		printf("--------------->QOS:%d.\n",pubmsg.qos);
		usleep(1000*5);

	}
	printf("Message with delivery token %d delivered\n", token);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return rc;
}

MQTTClient_subscribe.c

#include 
#include 
#include 
#include "MQTTClient.h"


#define ADDRESS     "192.168.31.18:1883"
#define CLIENTID    "ExampleClientSub"
#define TOPIC       "test321"
#define PAYLOAD     "Hello World!"
#define QOS         2
#define TIMEOUT     10000L

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)
{
    int i;
    char* payloadptr;

	printf("SUB>");
    payloadptr = message->payload;
    for(i=0; ipayloadlen; i++)
    {
        putchar(*payloadptr++);
    }
    putchar('\n');
	printf("--------------->QOS:%d.\n",message->qos);
    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;
    int ch;

    MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q to quit\n\n", TOPIC, CLIENTID, QOS);
    MQTTClient_subscribe(client, TOPIC, QOS);

    do 
    {
        ch = getchar();
    } while(ch!='Q' && ch != 'q');

    MQTTClient_unsubscribe(client, TOPIC);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return rc;
}

修改后重新make会在build/output/samples生成MQTTClient_subscribe 和 MQTTClient_publish

#往test321主题上发布消息
./MQTTClient_publish

#订阅test321主题的消息
./MQTTClient_subscribe

运行结果如下:

MQTT---linux简单通信demo(从broker到client)_第4张图片

3.mqttClient demo

前面步骤2 中我们讲openssl 和 paho.mqtt已经安装到系统中,现在我们新建一个简单的工程来实现mqtt 客户端,新建mqtt_client文件夹

我们将前面paho.mqtt.c-1.3.1/src/samples目录下的MQTTClient_publish.c MQTTClient_subscribe.c 拷贝到 mqtt_client目录下

新建Makefile

#CROSS_COMPILE	:= aarch64-linux-gnu-
#CC		:= $(CROSS_COMPILE)gcc
#CXX		:= $(CROSS_COMPILE)g++
CC		:= gcc

SRC_PUB	:= MQTTClient_publish.c
SRC_SUB	:= MQTTClient_subscribe.c

SHARED_TARGET_PUB	:= shared_publish 
SHARED_TARGET_SUB	:= shared_subscribe
#STATIC_TARGET_PUB	:= static_publish 
#STATIC_TARGET_SUB	:= static_subscribe

LDFLAGS	:= -L/usr/local/lib #链接库的路径
LDFLAGS	+= -L/usr/local/lib

INCLUDE	:= -I/usr/local/include #头文件路径
INCLUDE	+= -I/usr/local/include/openssl

#链接编译出来的动态库 libxxx.so
SHARED_LIBS	:= -lpaho-mqtt3a  \
		   -lpaho-mqtt3as \
		   -lpaho-mqtt3cs \
		   -lpaho-mqtt3c

#SHARED_LDFLAGS	:= -Wl,-rpath=./paho.mqtt_1.3.0/lib \
	               -Wl,-rpath=./openssl_1.1.1b/lib

#静态库链接编译选项
#STATIC_LIBS	:= -lpaho-mqtt3c-static -lpaho-mqtt3a-static #链接编译出来的静态库 libxxx.a
#STATIC_CFLAGS	:= -static -pthread


all: $(SHARED_TARGET_PUB) $(SHARED_TARGET_SUB)

#链接静态库编译
#$(STATIC_TARGET): $(SRC)
#	$(CC) -o $@ $^ $(STATIC_CFLAGS)  $(INCLUDE) $(LDFLAGS) $(STATIC_LIBS)


#链接动态库编译
$(SHARED_TARGET_PUB): $(SRC_PUB)
	$(CC) -o $@ $^  $(INCLUDE) $(LDFLAGS) $(SHARED_LIBS) $(SHARED_LDFLAGS)

$(SHARED_TARGET_SUB): $(SRC_SUB)
	$(CC) -o $@ $^  $(INCLUDE) $(LDFLAGS) $(SHARED_LIBS) $(SHARED_LDFLAGS)

clean:
	rm $(SHARED_TARGET_PUB) $(SHARED_TARGET_SUB)

执行 make,执行 ./shared_publish ./shared_subscribe 就实现了简单的mqtt客户端的发布和订阅

一个简单的mqtt的从broker到client的整个流程demo搭建基本是这个样子,关于openssl数据加密我们可以参考sample里面的其他例子了:)

 

你可能感兴趣的:(IOT)