理解
- MQTT协议是应用层的协议,基于TCP协议(所以也是要建立全双工连接的)
- MQTT协议是publish/subscribe模式,不同于HTTP协议的client/server模式。。所以我的一个小小的理解就是:HTTP是一对一的数据通信,MQTT是一对多的通信(一个消息发布可能有很多订阅者接收),所以MQTT更适合物联网这种【app一键控制多个设备同时响应】的场景。
- 维基百科介绍:
MQTT 协议定义了两种网络实体:消息代理(message broker)与客户端(client)。其中,消息代理用于接收来自客户端的消息并转发至目标客户端。MQTT 客户端可以是任何运行有 MQTT 库并通过网络连接至消息代理的设备,例如微型控制器或大型服务器。
信息的传输是通过主题(topic)管理的。发布者有需要分发的数据时,其向连接的消息代理发送携带有数据的控制消息。代理会向订阅此主题的客户端分发此数据。发布者不需要知道订阅者的数据和具体位置;同样,订阅者不需要配置发布者的相关信息。
应用场景
在一个建筑里,通过手机app控制不同楼层、区域的灯、门、空调等设备的开关。
client的开发
比如app功能页面的开发。
也比如每个设备收到指令的动作,但那些就不是我做的部分了。
-
在网上找一个实现了MQTT协议的库 名字 | 开发者 | 开发语言 | 类型 | 初次发布日期 | 最新发布版本 | 最新发布日期 | 许可证 | | -- | --- | ---- | -- | ------ | ------ | ------ | --- Paho MQTT | Eclipse基金会 | C语言, C++, Java, Javascript, Python, Go | 客户端 | 2014-05-02 | 1.4.1[44] | 2019-02-25 | Eclipse公共许可证 1.0, Eclipse发行许可证 1.0 (BSD) |
-
添加依赖、注册服务
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
<service android:name="org.eclipse.paho.android.service.MqttService" /> <!--MqttService 加在AndroidManifest.xml的application节点里-->
- 连接message broker
private MqttAndroidClient mqttAndroidClient;
private MqttConnectOptions mMqttConnectOptions;
//broker地址(协议+ip地址+端口号)
private String HOST = "tcp://xx.com:xxx";
//根据业务场景确定,可为空
private final String CLIENTID = "";
//用户名
private final String USERNAME = "xxx";
//密码
private final String PASSWORD = "xxx";
//传输质量
private final int QOS = 2;
//是否在连接意外断开后保留最后一条publish
boolean retained = false;
public void connect() {
mqttAndroidClient = new MqttAndroidClient(context, HOST, CLIENTID);
mqttAndroidClient.setCallback(mqttCallback);
mMqttConnectOptions = new MqttConnectOptions();
mMqttConnectOptions.setCleanSession(true);
mMqttConnectOptions.setConnectionTimeout(10); //设置超时时间,单位:秒
mMqttConnectOptions.setKeepAliveInterval(20); //设置心跳包发送间隔,单位:秒
mMqttConnectOptions.setUserName(USERNAME);
mMqttConnectOptions.setPassword(PASSWORD.toCharArray());
if (!mqttAndroidClient.isConnected() && isConnectIsNomarl()) {
try {
mqttAndroidClient.connect(mMqttConnectOptions, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken token) {
LogUtils.i(TAG, "连接成功");
//然后做一些publish、subscribe之类的业务逻辑
}
@Override
public void onFailure(IMqttToken token, Throwable e) {
LogUtils.e(TAG, e);
}
});
} catch (MqttException e) {
LogUtils.e(TAG, e);
}
}
}
/**
* 判断网络是否连接
*/
private boolean isConnectIsNomarl() {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info != null && info.isAvailable()) {
String name = info.getTypeName();
LogUtils.i(TAG, "当前网络:" + name);
return true;
} else {
LogUtils.i(TAG, "没有可用网络");
return false;
}
}
- 发布和订阅
//发布
private void publish(String topic, String message) {
try {
mqttAndroidClient.publish(topic, message.getBytes(), QOS, retained);
} catch (MqttException e) {
LogUtils.e(e);
}
}
//订阅
private void subscribe(String topic) {
try {
mqttAndroidClient.subscribe(topic, QOS);
} catch (MqttException e) {
LogUtils.e(e);
}
}
- 收到订阅topic消息时的回调处理
private final MqttCallback mqttCallback = new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String msg = new String(message.getPayload(), "GB2312");
//根据topic和msg处理
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
LogUtils.i(TAG, "发送完毕 ");
}
@Override
public void connectionLost(Throwable e) {
LogUtils.i(TAG, "连接断开 ");
}
};
- 断开连接
public void disconnect() {
if (mqttAndroidClient != null && mqttAndroidClient.isConnected()) {
try {
mqttAndroidClient.disconnect();
} catch (MqttException e) {
LogUtils.e(e);
}
mqttAndroidClient.unregisterResources();
}
}
项目里是在app的功能页面 create 的时候连接,destroy 的时候断开连接。
broker
项目里的broker是设备控制团队提供的,我只要做个app页面就可以。不过也可以自己本地起一个broker服务做测试:
- 参考这篇博客下载ActiveMQ,ActiveMQ把broker的转发等功能都实现好了
- 解压进入bin目录,在命令行执行
./activemq.bat start启动,ctrl+c关闭 - 启动日志会打印出broker服务监听的端口号
INFO | Listening for connections at: mqtt://myname:1883?maximumConnections=1000&wireFormat.maxFrameSize=268435456
INFO | Connector mqtt started
- 用上文代码连接broker,其中
HOST = "tcp://本机电脑ip:1883";
USERNAME = "admin";
PASSWORD = "admin";