Android MQTT的发布与订阅
一、MQTT介绍
链接1(菜鸟教程):https://www.runoob.com/w3cnote/mqtt-intro.html
连接2(MQTT中文网):http://mqtt.p2hp.com/
连接3(Android开发之Mqtt的使用):https://blog.csdn.net/asjqkkkk/article/details/80714234
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)。一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议。构建于TCP/IP协议上,由IBM在1999年发布。
二、程序示例
public class MqttManager {
private static boolean initFirst = true;//是否第一次初始化mqtt标识符
private static String host = "tcp://47.106.172.221:8081";
private static String userName; //mqtt用户名
private static String passWord; //mqtt登陆密码
private static MqttManager manager;
private static MqttClient mqttClient;
private static MqttConnectOptions options;
private static String topic;//订阅的主题
private static String clientId; //客户端id
private static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
KLog.d(msg.obj);
EventBus.getDefault()
.post(new MessageEventBean(AppConstants.MQTT_EVENT_TYPE, (String) msg.obj));
} else if (msg.what == 2) {
KLog.d("连接成功");
try {
KLog.d("订阅的主题:" + topic);
mqttClient.subscribe(topic, 0);
} catch (Exception e) {
e.printStackTrace();
}
} else if (msg.what == 3) {
KLog.d("连接失败,系统正在重连");
}
}
};
private MqttManager() {
}
private static MqttCallback myMqttCallback = new MqttCallback(){
@Override
public void messageArrived(String topic, MqttMessage message){
//subscribe后得到的消息会执行到这里面
KLog.d("messageArrived topic:"+topic);
Message msg = new Message();
msg.what = 1;
msg.obj = message.toString();
handler.sendMessage(msg);
}
@Override
public void connectionLost(Throwable cause) {
KLog.d("connectionLost cause = "+cause);
//连接丢失后,一般在这里面进行重连
try{
KLog.d("mqtt重连");
manager.startReconnect();
}catch (Exception e){
KLog.d("Exception = "+ e);
e.printStackTrace();
}
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//publish后会执行到这里
KLog.d("deliveryComplete");
}
};
private ScheduledExecutorService scheduler;
public static MqttManager getInstance() {
if (manager == null) {
manager = new MqttManager();
}
return manager;
}
public void initConnection() {
if (initFirst){
KLog.d("第一次调用initConnection");
try {
clientId = Preferences.getUserAccount() + System.currentTimeMillis();//客户端标识符(本机mac地址+当前时间ms)
userName = Preferences.getUserAccount();//用户名
passWord = Preferences.getUserToken();//密码
topic = userName;
//host为主机名;clientid即连接MQTT的客户端ID,是客户端的唯一标识符;MemoryPersistence设置clientid的保存形式,默认为以内存保存
mqttClient = new MqttClient(host, clientId, new MemoryPersistence());
//MQTT的连接设置
options = new MqttConnectOptions();
//设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(true);
//断开后,是否自动连接
options.setAutomaticReconnect(true);
//设置连接的用户名
options.setUserName(userName);
//设置连接的密码
options.setPassword(passWord.toCharArray());
// 设置超时时间 单位为秒
options.setConnectionTimeout(10);
// 设置会话心跳时间 单位为秒 服务器会每隔1.5*(20)秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
options.setKeepAliveInterval(20);
//setWill方法,如果项目中需要知道客户端是否掉线可以调用该方法。设置最终端口的通知消息
// options.setWill(topic,"close".getBytes(),2,true);
//设置回调
mqttClient.setCallback(myMqttCallback);
KLog.d("clientId: "+clientId +", userName: "+userName+", passWord: "+passWord+", topic: "+topic);
//设置标识符状态
initFirst = false;
//mqtt第一次连接
manager.startReconnect();
} catch (Exception e) {
KLog.d("initConnection Exception: " + e);
e.printStackTrace();
}
}else {
KLog.d("网络重连后调用initConnection");
manager.startReconnect();
}
}
public void startReconnect() {
if (NetworkUtils.isConnected()){
if (!mqttClient.isConnected()) {
//重新连接
connect();
KLog.d("mqtt连接结束");
}else {
KLog.d("mqttClient.isConnected");
}
// scheduler = Executors.newSingleThreadScheduledExecutor();
// scheduler.scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
//
// if (!mqttClient.isConnected()) {
// connect();
// KLog.d("mqtt连接结束");
// }
// }
// }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
}else {
KLog.d("网络不可用");
// scheduler.shutdown();
}
}
public void sendMsg(String msg) {
KLog.d("sendMsg");
if (mqttClient != null && mqttClient.isConnected()) {
try {
KLog.d("发送的主题:" + Preferences.getUserAccount());
String topic = Preferences.getUserAccount();
KLog.d(topic);
byte[] msgBytes = msg.getBytes();
KLog.d("0000");
mqttClient.publish(topic, msgBytes, 0, false);
KLog.d("11111111111111111");
} catch (MqttException e) {
KLog.d(e);
}
}
}
//发布的主题设为pubTopic = "owh" + Preferences.getUserAccount();
//发布主题(发布主题和订阅主题应设为不同值)
public void publish(String topicName, String payload) {
if (mqttClient != null && mqttClient.isConnected()) {
// 创建和配置一个消息
MqttMessage message = new MqttMessage(payload.getBytes());
message.setPayload(payload.getBytes());
message.setQos(0);
try {
KLog.d("1111");
mqttClient.publish(topicName, message);
KLog.d("2222");
} catch (MqttException e) {
KLog.d("publish : " + e.toString());
}
}
}
private void connect() {
ThreadPoolManager.getInstance().execute(new Runnable() {
@Override
public void run() {
try {
mqttClient.connect(options);
Message msg = Message.obtain();
msg.what = 2;
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
Message msg = Message.obtain();
msg.what = 3;
handler.sendMessage(msg);
}
}
});
// new Thread(new Runnable() {
//
// @Override
// public void run() {
// try {
// mqttClient.connect(options);
// Message msg = new Message();
// msg.what = 2;
// handler.sendMessage(msg);
// } catch (Exception e) {
// e.printStackTrace();
// Message msg = new Message();
// msg.what = 3;
// handler.sendMessage(msg);
// }
// }
// }).start();
}
//断开连接
public static void mqttDisconnect(){
if(mqttClient !=null && mqttClient.isConnected()){
try{
mqttClient.disconnect();
}catch (MqttException e){
KLog.d("mqtt disconnect error");
e.printStackTrace();
}
}
}
}
三、注意事项
1、MQTT的客户端id(clientId)须唯一。在此项目中clientId = 本机mac地址 + 当前时间(ms)。
2、一个客户端的一个MQTT连接最好只new一个对象,避免一台设备产生多个客户端账号。
当多个发布(/订阅)的clientId相同时,会发生Mqtt反复重连的现象,无法正常发送或接收消息。
当多个发布(/订阅)的clientId不同时,会造成一台设备多个Mqtt账号同时在线,占用了多余的服务器资源。
3、一个客户端的发布Topic和订阅Topic不应相同。
Android MQTT的发布与订阅的更多相关文章
- MQTT介绍(3)java模拟MQTT的发布,订阅
MQTT目录: MQTT简单介绍 window安装MQTT服务器和client java模拟MQTT的发布,订阅 在此强调一下mqtt的使用场景: 1.不可靠.网络带宽小的网络 2.运行的设备CPU. ...
- 转MQTT--Python进行发布、订阅测试
前言 使用python编写程序进行测试MQTT的发布和订阅功能.首先要安装:pip install paho-mqtt 测试发布(pub) 我的MQTT部署在阿里云的服务器上面,所以我在本机上编写 ...
- MQTT 消息 发布 订阅
当连接向一个mqtt服务器时,clientId必须是唯一的.设置一样,导致client.setCallback总是走到 connectionLost回调.报connection reset.调查一天才 ...
- (转)SqlServer 数据库同步的两种方式 (发布、订阅),主从数据库之间的同步
最近在琢磨主从数据库之间的同步,公司正好也需要,在园子里找了一下,看到这篇博文比较详细,比较简单,本人亲自按步骤来过,现在分享给大家. 在这里要提醒大家的是(为了更好的理解,以下是本人自己理解,如有错 ...
- (原)3.2 Zookeeper应用 - 数据的发布与订阅
本文为原创文章,转载请注明出处,谢谢 数据的发布与订阅 1.应用 服务端监听数据改变,客户端创建/更新节点数据,客户端提供数据,服务端处理 2.原理 客户端监控节点数据改变事件(例如配置信息,下图的c ...
- MSSQL复制中的发布与订阅
准备条件 1.2台服务器 2.WINDOWS SERVER 2008 64bit + 3.SQL SERVER 2008 R2 + 4.MSSQLSERVER服务与MSSQLAGENT服务正常运行中 ...
- 知方可补不足~SQL2008中的发布与订阅模式
回到目录 作用:完成数据库与数据库的数据同步 原理:源数据库发布需要同时的表,存储过程,或者函数:目标数据库去订阅它,当源发生变化时,目标数据库自己同步,注意,由于这个过程是SQL自动完成的,所以要求 ...
- RabbitMQ官方中文入门教程(PHP版) 第三部分:发布/订阅(Publish/Subscribe)
发布/订阅 在上篇教程中,我们搭建了一个工作队列.每个任务之分发给一个工作者(worker).在本篇教程中,我们要做的之前完全不一样——分发一个消息给多个消费者(consumers).这种模式被称为“ ...
- 【SQL Sever】实现SQL Sever的发布。订阅。 双机热备
实现SQL Sever的发布和订阅 最大的好处就是: 可以实现读写分离,增删改操作在主数据库服务器上进行,查询在备份数据库服务器上进行.一方面提高软件执行效率,另一方面也减轻主库压力. 本次实现发布 ...
随机推荐
- 模板 - Prim
Kruskal算法要对边排序,然后打个并查集维护,但是实际上Prim有他好玩的地方,就把Dijkstra的到点的距离从dis[v]:dis[u]+w改成边dis[v]:w. 那肯定是Prim好写一点. ...
- 学习WPF-1
学习WPF-1 最近到新公司,需要使用WPF来做界面开发,我原先是使用WinForm来做界面开发的,所以对于现在使用WPF来开发,需要先学习一段时间了,考核的内容目前也还没定下来做什么, 但终归是使用 ...
- Jquery复习(四)之text()、html()、val()
三个简单实用的用于 DOM 操作的 jQuery 方法: text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元素的内容(包括 HTML 标记) val() - 设置或返回 ...
- 企业面试题|最常问的MySQL面试题集合(三)
分区表的原理 分库分表的原理 延伸: MySQL的复制原理及负载均衡 分区表的工作原理 对用户而言,分区表是一个独立的逻辑表,但是底层MySQL将其分成了多个物理子表,这对用户来说是透明的,每一个分区 ...
- Servlet监听器——实现在线登录人数统计小例子
一.概念 servlet监听器的主要目的是给web应用增加事件处理机制,以便更好的监视和控制web应用的状态变化,从而在后台调用相应处理程序. 二.监听器的类型 1.根据监听对象的类型和范围,分为3类 ...
- 关于css中touch-action属性 在移动端开发中遇到的问题
初次接触第一次接触touch-action这个属性 是在之前一个网约车公众号项目中遇到的 当时采用的是vue做框架 cube-ui做组件库 当时在版本迭代的时候增加了余额支付的功能 需要一个密码键盘 ...
- MapUtils
一. package com.wang.utils; import java.util.HashMap; import java.util.Map; import java.util.Set; pub ...
- linux 下shell中if的“-e,-d,-f”的用法
文件表达式-e filename 如果 filename存在,则为真-d filename 如果 filename为目录,则为真 -f filename 如果 filename为常规文件,则为真-L ...
- Ubuntu下Cmake编译C++程序Helloworld
1.首选新建工程目录 mkdir helloworld 2.新建文件目录 cd helloworld mkdir bin mkdir lib mkdir src mkdir include mkdir ...
- 【10】Python urllib、编码解码、requests、多线程、多进程、unittest初探、__file__、jsonpath
1 urllib urllib是一个标准模块,直接import就可以使用 1.1get请求 from urllib.request import urlopen url='http://www.nnz ...