程序员人生 网站导航

Linkit 7688 DUO(六) 加入MQTT物联网协议

栏目:综合技术时间:2016-06-08 08:37:31

Linkit 系列博文:

联发科Linkit 7688 (1) 上手及在Mac下搭建OpenWrt交叉编译环境,C语言编译Hello,World

联发科Linkit 7688 (2)GPIO基本操作与C语言编程

联发科Linkit 7688 DUO(3): 通过 Arduino 控制外设和传感器

Linkit 7688 DUO(4): 接上各种Arduino传感器和模块——基础篇

Linkit 7688 DUO(5) 接上各种Arduino传感器和模块—扩大篇

Linkit 7688 DUO(6) 加入MQTT物联网协议


本篇介绍 将 MQTT物联网协议加载到 Linkit 7688 DUO开发板上 ( 其中的源码和方法也适用于所有的Linux系统、也合适于Windows系统)

MQTT是IBM开发的1种物联网即时通讯协议,该协议支持所有平台,几近可以把所有联网物品、电脑APP、手机APP、网页等连接起来,让它们随时相互交换信息。

有了MQTT协议,Linkit 7688开发板就能够称得上物联网开发板了,可以实现很多场景,比如:手机远程控制、网页远程控制、服务器监测物体状态等等。


1、MQTT协议简介

1,MQTT是1种基于TCP的网络消息协议,用于发送和接收消息。 

在1个MQTT网络中,有1个服务器和多个客户端。 每一个客户端以TCP Socket与服务器连接,并保持为长连接。

客户端可以是1个联网物体、电脑软件、手机APP、乃至是网页。以下图:



2,  消息传输采取发布/定阅(publish/subscribe)模式。

  客户端可以发布(publish)消息, 每一个消息由1个主题(topic)和1个消息内容组成。比如:某温度传感器发布1个消息: topic = "sensor1/temperature", message="25“

  客户端可以定阅(subscribe)1个或多个主题的消息。 当网络中有人发布了这些主题的消息,则客户端将收到这条消息。比如: 手机App定阅了 “sensor1/temperature"消息,则上述消息将被收到, 手机App就知道sensor1的温度值了。

  由于客户端与服务器保持着Socket长连接,消息将立即实时推送到客户端,也就是说:PUSH到客户端。

  MQTT服务器的主要作用是接收-转发:接收消息、判断哪些客户端定阅了该主题的消息,PUSH给相应客户端。

  这类机制,可以实现1对1发送消息,也能够实现1对多发送消息(群发)。

利用场景举例:

场景1:  手机APP发布查温度的消息, 各个传感器装置收到消息后,发布温度消息。则手机就能够搜集到各个传感器的温度。

场景2:  当火警传感器装置检测到起火后,发布消息。 则定阅了该类型消息的手机、电脑等都可立即收到火警。


3,MQTT的消息包传输数据量很小(固定长度的头部仅为 2 字节),能充分下降网络流量,非常合适于低带宽、不可靠连接、嵌入式装备。 

同时非常合适于手机等移动通讯环境,可以省流量、省电。因此,有人用MQTT作为手机PUSH使用。


4, 为保障消息有效力到达,MQTT定义了3种消息发布服务质量(Qos, Quality Of Service):

“最多1次”(At most once),开消最小,消息发布完全依赖底层 TCP/IP 网络,会产生消息丢失或重复。这1级别可用于以下情况,环境传感器数据,丢失1次读记录无所谓,由于不久后还会有第2次发送。
“最少1次”(At least once),确保消息到达,但消息重复可能会产生。
“只有1次”(Exactly once),确保消息到达1次。这1级别可用于以下情况,在计费系统中,消息重复或丢失会致使不正确的结果。经常使用于精确控制。

每条消息都可以有自己的Qos定义。每个客户端定阅某主题时,也能够指定Qos.


5, MQTT协议由IBM公司于1999年提出,经过量年发展已比较成熟,目前版本是3.1.1。服务器和客户端均有多个开源实现,支持各类操作系统和开发语言。


2、合适嵌入式装备的MQTT协议客户端(C语言实现)

对Linkit 7688开发板,我选取 “Eclipse Paho C” 的MQTT 客户端开源代码库 。其主页在这:https://www.eclipse.org/paho/clients/c/

这个代码库是IBM公司提供的,Eclipse项目组保护的,可以称为官方的。

我的使用方式是: 将它作为1个函数库, 在Linkit 7688上编写C语言程序,实现MQTT消息收发。

这个库有1点点复杂,需要对协议比较了解。如果你要完全弄懂它,需要先读它的文档(http://www.eclipse.org/paho/files/mqttdoc/Cclient/index.html)

我们1般总是喜欢把复杂的事情简单化,因此,我对这个库进行了封装,  变成几个函数, 不需要懂太多就能够用.

库和例程在我的资源中下载:  MQTT客户端Paho C代码

解压后,其中mqtt目录是Paho C所有的库文件( 原本的文件都没改,我增加了 mqtt_client.c ,  mqtt_client.h 两个文件),使用时将mqtt目录复制到你的项目文件夹中便可。


在使用前,需要有1个测试用的MQTT服务器, 我用的是 IBM提供的测试服务器:  messagesight.demos.ibm.com, 端口是1883 (1883是MQTT的默许端口)

同时需要有1个测试用的MQTT客户端作为对端,我用的是IBM提供的网页版MQTT客户端:http://m2m.demos.ibm.com/mqttclient/


1, 在Linkit 7688上编1个发送MQTT消息的程序:

  用Eclipse 建立1个交叉编译项目 ( 开发环境搭建请见:联发科Linkit 7688 (1) 上手及在Mac下搭建OpenWrt交叉编译环境,C语言编译Hello,World)

  将mqtt目录复制到你的项目文件夹下。

  创建1个 mqtt_publish.c文件, 编写主程序以下:

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include "mqtt/mqtt_client.h"//这个是我对mqtt_client封装后的头文件 int publish(int argc, char ** argv) { mqtt_client *m; //mqtt_client 对象指针 int ret; //返回值 char *host = "messagesight.demos.ibm.com:1883";//测试服务器 char *topic = "test_topic"; //主题 char *client_id = "clientid33883";//客户端ID; 对测试服务器,可以随意写 char *username = NULL;//用户名,用于验证身份。对测试服务器,无。 char *password = NULL;//密码,用于验证身份。对测试服务器,无。 int Qos; //Quality of Service //create new mqtt client object m = mqtt_new(host, MQTT_PORT, client_id); //创建对象,MQTT_PORT = 1883 if ( m == NULL ) { printf("mqtt client create failure, return code = %d\n", errno); return 1; } else { printf("mqtt client created\n"); } //connect to server ret = mqtt_connect(m, username, password); //连接服务器 if (ret != MQTT_SUCCESS ) { printf("mqtt client connect failure, return code = %d\n", ret); return 1; } else { printf("mqtt client connect\n"); } //publish message Qos = QOS_EXACTLY_ONCE; //Qos ret = mqtt_publish(m, topic, "hello from Linkit 7688", Qos);//发布消息 printf("mqtt client publish, return code = %d\n", ret); mqtt_disconnect(m); //disconnect mqtt_delete(m); //delete mqtt client object return 0; }


主程序分为3个步骤:

1, 调用 mqtt_new()创建 客户端对象

2, 调用 mqtt_connect() 连接服务器

3, 调用 mqtt_publish() 发布消息


用Eclipse编译项目

如果出现毛病提示:

undefined reference to `pthread_create’
undefined reference to `pthread_mutexattr_init’

这是由于没有在编译连接时包括pthread库, 解决办法: 需在GCC中添加 -lpthread 参数。

如果出现毛病提示:

undefined reference to `dlclose’
undefined reference to `dlopen’
undefined reference to `dlsym
这是由于没有在编译连接时包括dl库, 解决办法: 需在GCC中添加 -ldl 参数

在eclipse中的操作是:   项目Property =>  C/C++ Build => Settings, 在"Tools Setting"页,选Cross GCC linker, 在 "Linker flags"编译框中填入:  -lpthread -ldl

OK, 编译成功了。


用scp将 mqtt_publish 程序上传到 linkit 7688:   scp mqtt_publish root@mylinkit.local:/root


先准备接收消息的网页客户端: 用阅读器打开 http://m2m.demos.ibm.com/mqttclient/

在Connect栏中, 点Connect.

在Subscribe栏中,将topic设为 test_topic, 按subscribe

OK, 网页客户端准备好接收主题(topic)为 test_topic的消息了。


用SSH登录入Linkit 7688,  运行 mqtt_publish 程序。

运行结果, 显示mqtt 创建、连接、发布消息的进程, return code >=0 表示成功

mqtt client created

mqtt client connect

mqtt client publish,  return code = 1


这时候,可以看到阅读器中的MQTT网页客户端收到了Linkit 7688发布的MQTT消息


 

成功了: Linkit 7688发布MQTT消息到服务器, 网页客户端实时收到服务器推送来的消息。



2, 在Linkit 7688上编1个接收MQTT消息的程序:

  用Eclipse 建立1个交叉编译项目 ( 开发环境搭建请见:联发科Linkit 7688 (1) 上手及在Mac下搭建OpenWrt交叉编译环境,C语言编译Hello,World)

  将mqtt目录复制到你的项目文件夹下。

  创建1个 mqtt_subscribe.c文件, 编写主程序以下:

#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include "mqtt/mqtt_client.h"//这个是我对mqtt_client封装后的头文件 int running = 1; void stop_running(int sig) { signal(SIGINT, NULL); running = 0; } int main(int argc, char ** argv) { mqtt_client *m; //mqtt_client 对象指针 int ret; //返回值 char *host = "messagesight.demos.ibm.com:1883";//测试服务器 char *topic = "test_topic"; //主题 char *client_id = "clientid33883";//客户端ID; 对测试服务器,可以随意写 char *username = NULL;//用户名,用于验证身份。对测试服务器,无。 char *password = NULL;//密码,用于验证身份。对测试服务器,无。 int Qos; //Quality of Service //create new mqtt client object m = mqtt_new(host, MQTT_PORT, client_id); //创建对象,MQTT_PORT = 1883 if ( m == NULL ) { printf("mqtt client create failure, return code = %d\n", errno); return 1; } else { printf("mqtt client created\n"); } //connect to server ret = mqtt_connect(m, username, password); //连接服务器 if (ret != MQTT_SUCCESS ) { printf("mqtt client connect failure, return code = %d\n", ret); return 1; } else { printf("mqtt client connect\n"); } //subscribe Qos = QOS_EXACTLY_ONCE; ret = mqtt_subscribe(m, topic, Qos);//定阅消息 printf("mqtt client subscribe %s, return code = %d\n", topic, ret); signal(SIGINT, stop_running); signal(SIGTERM, stop_running); printf("wait for message of topic: %s ...\n", topic); //loop: waiting message, 循环 while (running) { int timeout = 200; if ( mqtt_receive(m, timeout) == MQTT_SUCCESS ) { //recieve message,接收消息 printf("received Topic=%s, Message=%s\n", m->received_topic, m->received_message); } mqtt_sleep(200); //sleep a while } mqtt_disconnect(m); //disconnect printf("mqtt client disconnect"); mqtt_delete(m); //delete mqtt client object return 0; }

主程序分为几个步骤:

1, 调用 mqtt_new()创建 客户端对象

2, 调用 mqtt_connect() 连接服务器

3, 调用 mqtt_subscribe() 定阅消息

4, 进入循环:不断用 mqtt_receive()检测有否新消息,如有,则打印出来。

用Eclipse编译项目 (记得必须在GCC中加入连接选项:  -lpthread -ldl )

OK, 编译成功了。

用scp将 mqtt_subscribe 程序上传到 linkit 7688:   scp mqtt_subscribe root@mylinkit.local:/root


用SSH登录入Linkit 7688,  运行 mqtt_subscribe 程序。则此时出现:

mqtt client created

mqtt client connect

mqtt client subscribe,  return code = 0

wait for message of topic: test_topic ...


显示程序在等待消息到来


准备发送消息的网页客户端: 用阅读器打开 http://m2m.demos.ibm.com/mqttclient/

在Connect栏中, 点Connect.

在Publish栏中,将topic设为 test_topic, 将Message设为 “Say hello to linkit 7688” 按publish, 则发出1条MQTT消息。


这时候, 看Linkit 7688 SSH客户端,可以看到,Linkit7688立即收到了这条MQTT消息

mqtt client created

mqtt client connect

mqtt client subscribe,  return code = 0

wait for message of topic: test_topic ...

received Topic=test_topic, Message=Say hello to linkit 7688


成功了: Linkit 7688 实时收到了网页客户端发来的消息。

mqtt_subscribe 程序是死循环,1直在接收消息。 可按CTRL+C退出。



通用性: Eclipse Paho C 的 MQTT客户端代码,可以运行在Linux、Windows、Mac上。所以,上述的代码可以用于Linux、Windows、Mac操作系统,编写各种App。

对Android手机, Eclipse Paho另提供了Java的代码库。





------分隔线----------------------------
------分隔线----------------------------

最新技术推荐