首先我们需要一个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版本)
在下载时我们可以先配置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设置中文显示即可)
使用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安装信息
这里我们直接在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
修改完成如上所示,主要是修改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
运行结果如下:
前面步骤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里面的其他例子了:)