最近接到新需求,需要使用 MQTT 把大屏设备上的信息,比如用户使用信息,常用需求设置等共享到服务器,且能通过服务器动态设置大屏。所以,这里简单学习一些MQTT的知识。
代码工程: https://github.com/LillteZheng/MQTTDemo
MQTT 是IBM 开发的一款轻量级的即时通信协议;通过 发布/订阅 的模式,专门为受限设备或低宽带,高延迟等弱网环境而设计。它的设计思想是轻巧、开放、简单、规范,易于实现。这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器的通信(M2M)以及物联网环境。
而在集控领域也越来越受欢迎,本文的最后目的就是用于服务器与大屏的集控关系。
首先,需要先搭建好后台服务器,虽然一般这个为后台搭建,但是作为Android研发,也可以自己简单搭建一个服务器用于调试。
搭建服务器,有很多选择,作为 Java 为基础开发语言的,所以需要 apache 的服务器,网上有很多教程,但都是 1.7.1 的版本,但是官网已经没有这个版本的软件了,不过可以通过以下链接去下载:
http://archive.apache.org/dist/activemq/activemq-apollo/1.7.1/
下载适合自己的版本,我这里是 window ,所以下载:
下载解压,然后添加系统变量,即解压路径下的bin:
接着,创建服务:在 cmd 上,输入: apollo create server ( 其中 server 是服务的名字,自己写一个)如下:
然后可以看到已经在 bin 文件下生成一个 server 的文件夹了:
其中 etc 中包含了你的用户名和密码,分别是 admin 和 password;建议不去修改它,后面会用到。
接着,通过cmd 进入 bin 目录,执行:apollo-broker.cmd run 其中服务:
说明服务已经启动完毕了。然后在浏览器上输入 http:127.0.0.1:61681 ,就可以看到画面了,账号密码就是 admin 和password。
上面还有 Accepting connections 的字段,表示可加入的host 和port ,这个接下来会用到。
服务器已经搭建好了,需要来熟悉一下流程,首先,先下载 MQTT.fx ,下载地址如下:
http://www.jensd.de/apps/mqttfx/
一路安装启动即可。
启动客户端之后,点击设置:
然后按照如下步骤:
点击ok之后,选择你刚才的profile,点击 connect
接着,点击 Subsribe 订阅,输入一个主题字段,这里用 dev/status 表示,然后点 subcribe 点阅即可。如下图:
接着,点击 Publish ,发布你的主题,这里跟订阅的字段一样,然后输入你想发送给 主题 dev/status 的信息即可,然后点击 publish,如下:
接着,回到 Subscribe ,就可以看到已经接受到信息了:
ok,这样一种 订阅/发布 ,类似于观察者模式的流程,我们就熟悉了。接着,我们来实践一下 Android 的。
要实现的效果是,Android 与 mqtt.fx 通信。
首先新建一个工程,然后再 project.gradle 中添加:
allprojects {
repositories {
google()
jcenter()
maven {
url "https://repo.eclipse.org/content/repositories/paho-releases/"
}
}
}
build.gradle 中添加:
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
然后,记得在 AndroidManifest.xml 中添加 MQTT 服务,不然会报错误:
添加权限:
接着,配置好我们的基本信息:
private static final String HOST = "tcp://192.168.49.41:61613";
private static final String USERNAME = "admin";
private static final String PASSWORD = "password";
private static final String SUBSCRIBE_TOPIC = "dev/status"; //订阅主题
private static final String PUBLISH_TOPIC = "dev/push"; //发布主题
private static final String CLIENT_ID = "ANDROID_ID"; //客户端ID,避免与 MQTT.fx 冲突
因为Android 也属于一个客户端,所以为了避免和 mqtt.fx 冲突,这里的 CLIENT_ID 要与 mqtt.fx 不一样。
接着就是一些配置了:
private void initMQTT() {
/**
* 新建一个客户端,HOST 为 MQTT 地址,CLIENT_ID 为唯一标识
*/
mClient = new MqttAndroidClient(this, HOST, CLIENT_ID);
mClient.setCallback(new MQTTMessageListener());
/**
* 通过 options 配置客户端的信息,比如账号,密码,和最后的遗嘱等
*/
MqttConnectOptions options = new MqttConnectOptions();
//清除缓存
options.setCleanSession(true);
//超时
options.setConnectionTimeout(10);
//心跳包
options.setKeepAliveInterval(20);
//用户名和密码
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
/**
* 设置最后的遗嘱,该方式可以让设备在掉线时,发送状态给服务器
*/
String topic = SUBSCRIBE_TOPIC;
String msg = "disconnect";
/**
* qos 表示传递的服务质量,它的参数有 0,1,2三种如下:
* 0:发送一次,不需要确认
* 1:至少一次确认
* 2:发送必须确认
* retained:是否在服务器保留断开连接后的最后一条消息
*/
options.setWill(topic,msg.getBytes(),2,false);
if (!mClient.isConnected()) {
try {
//连接服务器和监听消息
mClient.connect(options, null, IMqttActionListener);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
可以看到,我们最终要看到的是 mClient.connect()这个方法,其中 opstion 为要配置的属性,第二个参数为 context 上下文,这里传 null 即可,第三个参数则是 listener 用来监听,是否能连接上服务器:
/**
* 检测到 MQTT 是否连接服务器
*/
private IMqttActionListener IMqttActionListener = new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken arg0) {
//当连接上服务器,则可以订阅哪些主题了,这里也用 dev/status 这个主题
Log.d(TAG, "zsr - 连接成功 ");
try {
// 订阅Topic话题,然后用 mqtt.fx 发消息过来
mClient.subscribe(SUBSCRIBE_TOPIC,2);
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
arg1.printStackTrace();
// 连接失败,重连
Log.d(TAG, "zsr - onFailure: "+arg1.getMessage());
}
};
可以看到,在 onSuccess 方法中,订阅 topic 主题,这里用的是 dev/status 。其中当新消息过来的时候,在 MQTTMessageListener 里:
/**
* 监听是否收到信的消息
*/
class MQTTMessageListener implements MqttCallback{
@Override
public void connectionLost(Throwable cause) {
//连接失败
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
//新信息到达
Log.d(TAG, "zsr - 收到新消息了: "+message);
//当收到信息之后,我们回一条消息给 mqtt.fx
publish(PUBLISH_TOPIC,"msg from android");
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//发送成功
}
}
可以看到,当接收到 mqtt.fx 的信息之后,回送一条信息给 mqtt.fx ,内容非常简单。当然,还需要把 mqtt.fx 订阅的主题,改成我们android 客户端的 dev/push:
最终效果如下:
参考链接:
https://blog.csdn.net/qq_17250009/article/details/52774472
https://www.hivemq.com/blog/how-to-get-started-with-mqtt/
https://www.jianshu.com/p/73436a5cf855