了解MQTT
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
MQTT是一个基于客户端-服务器的消息发布/订阅传输协议。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下,包括受限的环境中,如:机器与机器(M2M)通信和物联网(IoT)。其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居、及一些小型化设备中已广泛使用。
更多可查看以下链接MQTT 入门介绍 | 菜鸟教程
搭建MQTT服务器(Broker)
tar xf mosquitto-1.6.3.tar.gz
cd mosquitto-1.6.3/
make
sudo make install
安装完成后,终端输入mosquitto命令即可运行。端口默认是1883
$ mosquitto
1639476502: mosquitto version 1.6.3 starting
1639476502: Using default config.
1639476502: Opening ipv4 listen socket on port 1883.
1639476502: Opening ipv6 listen socket on port 1883.
客户端库移植
编译安装
unzip paho.mqtt.c-1.3.0.zip
cd paho.mqtt.c-1.3.0/
mkdir install(在源码目录新建一个安装目录)
cmake -DCMAKE_INSTALL_PREFIX=/xxx/paho.mqtt.c-1.3.0/install(xxx代表你自己的路径)
make
make install //最后错误可以忽略
最后会在安装目录中看到头文件和库文件
cd install/
install$ ls
bin CONTRIBUTING.md edl-v10 epl-v10 include lib notice.html README.md samples
install/samples中是官方示例demo,可修改demo中MQTTClient_subscribe.c(订阅)和MQTTClient_publish.c(发布),编写我们需要的代码。
代码分析
/*******************************************************************************
* Copyright (c) 2012, 2017 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Ian Craggs - initial contribution
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#define ADDRESS "tcp://192.168.31.240:1883"
#define CLIENTID "ExampleClientSub"
#define TOPIC "MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#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;
}
/**
* @brief
*
* @param context
* @param topicName 收到来自哪个主题的消息
* @param topicLen 主题的长度
* @param message 消息体:payload(消息体,字符串) payloadlen:消息的长度
* @return int
*/
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
int i;
char* payloadptr;
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: ");
#if 0
payloadptr = message->payload;
for(i=0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
#endif
printf("recv msg = %s\n", (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;
int ch;
//创建客户端,并且指定客户端连接的mqtt服务器地址和客户端ID
MQTTClient_create(&client, ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
//初始化连接参数
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
//设置回调接口,只需要关注msgarrvd:消息到达后,会自动调用这个接口
MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
//连接到broker
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<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
//订阅某个主题,指定订阅主题的名字,可以指定qos服务质量
MQTTClient_subscribe(client, TOPIC, QOS);
//死循环,直到收到了一个q就退出
do
{
ch = getchar();
} while(ch!='Q' && ch != 'q');
MQTTClient_unsubscribe(client, TOPIC);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
编码测试
以MQTTClient_subscribe.c为例,修改代码中IP地址和主题即可完成最简单的通信。

使用如下命令编译代码,头文件和库文件路径根据自己实际情况指定。
gcc MQTTClient_subscribe.c -I ../include/ -l paho-mqtt3c -L ../lib
首次执行会出现错误,因为运行时所需要的库找不到,Linux运行时默认查找目录为/lib或者/usr/lib
$ ./a.out
./a.out: error while loading shared libraries: libpaho-mqtt3c.so.1: cannot open shared object file: No such file or directory
所以,我们需要把编译出来的库拷贝到上面两个路径中任意一个。拷贝命令中需要增加-d选项,保持库的软链接属性。
install/lib$ sudo cp libpaho-mqtt3* /usr/lib -d
拷贝完成后再执行就可以了