使用HiveMQ实现Android MQTT

MQTT官网:https://mqtt.org/

百度Android MQTT,或者B站上搜索,发现大多使用https://github.com/eclipse/paho.mqtt.android,这是Eclipse的一个Android MQTT客户端实现库,但是我发现这个库在运行到高版本的手机上时报错了,这个库也是N年没有更新的了,而且这个库不支持MQTT5.0的,所以我找了新的库。

在查看MQTT官网的时候,发现关于MQTT的很多介绍是链接到了HiveMQ上面的,不知道它们是什么关系,我发现HiveMQ即有提供MQTT的服务器端,也有提供客户端,而且官方都给他跳转了,那我就用它的库来实现吧!使用了之后才发现,这个库是真的好用啊,封装的非常好,代码写起来特别简洁,响应式编程,支持异步,可以使用Java自带的,也可以使用RxJava或Reactor,HiveMQ的断线自动重连做的也比较好。库地址:https://github.com/hivemq/hivemq-mqtt-client,这个库好像没有限定Android,所以在普通的Java项目中也是可以使用的。android示例代码如下:

  1. 添加依赖

    implementation("com.hivemq:hivemq-mqtt-client:1.3.0")
    
  2. 权限声明

    <uses-permission android:name="android.permission.INTERNET"/>
    

    可以看到,相比paho.mqtt.android,HiveMQ的只需要声明一个互联网权限。

  3. 界面UI
    在这里插入图片描述

  4. MQTT实现代码:Mqtt.kt

    object Mqtt {private const val clientId = "9527"private const val host = "192.168.1.188"private const val port = 1883private const val topic = "message/topic"private var client: Mqtt3AsyncClient? = nullprivate fun createMqttClient(): Mqtt3AsyncClient =Mqtt3Client.builder().identifier(clientId).serverHost(host).serverPort(port)// 认证设置/*.simpleAuth().username("admin").password("password".toByteArray()).applySimpleAuth()*/// 重连设置.automaticReconnect().initialDelay(1, TimeUnit.SECONDS) // 断线1秒后开始自动重连,如果重连还失败,则下次会等时间会按指数增长,比如2秒、4秒、8秒,双倍增长等待时间,但是不会超过最大值,由maxDelay函数来指定最大值。.maxDelay(32, TimeUnit.SECONDS)    // 断线后最多32秒就会自动重连,第5次连会来到32的位置,前面4次已用掉31秒的等待时间了。.applyAutomaticReconnect()// 连接状态监听器设置.addConnectedListener {println("MQTT${it.clientConfig.serverHost}:${it.clientConfig.serverPort}连接成功")}.addDisconnectedListener {// 客户端断开连接,或者连接失败都会回调这里println("MQTT${it.clientConfig.serverHost}:${it.clientConfig.serverPort}连接断开:${it.cause.message},连接状态:${it.clientConfig.state.name}")/*when (it.clientConfig.state) {MqttClientState.CONNECTING -> println("手动连接失败")             // 即主动调用connect时没连接成功MqttClientState.CONNECTING_RECONNECT -> println("自动重连失败")   // 即连接成功后异常断开自动重连时连接失败MqttClientState.CONNECTED -> println("连接正常断开或异常断开")else -> println("连接断开:${it.clientConfig.state.name}")}*/}.buildAsync()// 消息监听器设置.also {// 接收订阅的消息。publishes必须在subscribe之前调用以确保消息不会丢失,可以在connect之前调用它以便接收前一个会话的消息。it.publishes(MqttGlobalPublishFilter.ALL) { publish: Mqtt3Publish ->println("收到${publish.topic}的消息:${String(publish.payloadAsBytes)}")}}fun connect() {disconnect()// 断开连接后的client没法再复用,复用的client重新再连接时会收不到离线时的消息。所以每次连接时创建一个新的client。val client = createMqttClient().also { this.client = it }client.connectWith().cleanSession(false) // false为持久会话,这样离线再上线时还能收到离线时别人推送的消息。.keepAlive(60)  // 心跳时间间隔,单位为秒.send().whenComplete { ack, e ->if (ack != null) {// 连接成功之后订阅主题println("手动连接成功:$ack")client.subscribeWith().topicFilter(topic).qos(MqttQos.EXACTLY_ONCE).send()} else if (e != null) {println("手动连接失败: ${e.message}")}}}fun disconnect() {client?.let {it.disconnect().thenAccept { println("手动断开了连接") }client = null}}fun subscribe(topic: String = this.topic, qos: MqttQos = MqttQos.EXACTLY_ONCE) {val client = this.client ?: returnclient.subscribeWith().topicFilter(topic).qos(MqttQos.EXACTLY_ONCE).send()}fun unsubscribe(topic: String = this.topic) {val client = this.client ?: returnclient.unsubscribeWith().topicFilter(topic).send()}fun publish(message: String, topic: String = this.topic,  qos: MqttQos = MqttQos.EXACTLY_ONCE, retain: Boolean = false) {val client = this.client ?: returnclient.publishWith().topic(topic).qos(qos).retain(retain).payload(message.toByteArray()).send()}fun clearRetainMessage(topic: String = this.topic) {val client = this.client ?: return// 发送一条空的retain消息即可清除retain消息client.publishWith().topic(topic).retain(true).send()}}
    
  5. Activity调用Mqtt相关功能:MainActivity.kt

    class MainActivity : AppCompatActivity() {private val testTopic = "topic/hello"override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}fun connect(view: View) = Mqtt.connect()fun disconnect(view: View) = Mqtt.disconnect()fun subscribe(view: View) = Mqtt.subscribe(testTopic)fun unsubscribe(view: View) = Mqtt.unsubscribe(testTopic)fun publish(view: View) = Mqtt.publish("How are you?", testTopic)fun publishRetain(view: View) = Mqtt.publish("I'm a retain message!", testTopic, retain = true)fun clearRetain(view: View) = Mqtt.clearRetainMessage(testTopic)}
    

    示例完整代码:https://gitee.com/daizhufei/HelloMQTT

    这里MQTT的服务器端我使用的是ActivityMQ,它目前的ActiveMQ Classic最新版本是6.0.1,只支持MQTT3.13.1.1ActiveMQ Artemis的最新版本是2.32.0,支持支持MQTT3.1MQ3.1.1MQTT5.0,官方说明如下:

    • https://activemq.apache.org/components/classic/documentation/mqtt
    • https://activemq.apache.org/components/artemis/documentation/latest/mqtt.html

    随着时间的推移,它支持的版本可能会发生变化。这里截图如下:
    在这里插入图片描述
    在这里插入图片描述

MQTT其他知识总结:

  • 关于MQTT的基础知识,可查看:https://www.hivemq.com/blog/mqtt-essentials-part-10-alive-client-take-over/
  • clientId , 连接的时候用到这个参数,(也叫identifier)应该唯一,可以使用账号做为clientId,比如我们公司的需求是先使用账号密码登录一个Web接口,然后再连接MQTT,但是这个账号是可以在多台设备上同时登录的,所以使用直接使用账号的话会出现重复,可以为每台设备生成一个唯一标识然后持久化存储,然后clientId就可以使用账号和唯一标识组合一起使用。比如:username + uuid,而uuid是持久化保存的。
  • cleanSession , 连接的时候用到这个参数,持久会话设置,如果设置为false,则是持久的,true为非持久,持久的意思是当设备离线后,如果有消息推过来,上线时还能收到。如果是非持久的则收不到离线时的消息。
  • keepAlive,连接的时候用到这个参数,用于设置发送心跳的时间间隔,在客户端和服务器没有交流时,在指定的keepAlive时间到达后会发送心跳给服务器,以证明客户端还活着(也就是说确保连接是正常的)。MQTT是使用TCP的,虽然理论上TCP/IP会在套接字中断时通知您,但在实践中,特别是在移动和卫星链路等情况下,它们经常在空中“伪造”TCP并在每一端放回报头,TCP会话很可能会“黑洞”,即它看起来仍然打开,但只是将您写入的任何内容倾倒到地板上,内容来自:https://www.hivemq.com/blog/mqtt-essentials-part-10-alive-client-take-over/
  • qos 订阅主题和推送消息的时候用到这个参数,有0、1、2,2是最好的质量,现在的手机网络已经比以前好太多了,所以我就选最好的质量了,质量越好需要的流量越多,但是现在的流量已经不像从前那样贵了,所以无所谓。
  • retain 推送消息的时候用到这个参数,如果设置为true,则推送的这条消息会在客户端每次连接时都接收到,比如连接了收到了,然后断开连接,然后再连接上,还是能收到这条消息。如果需要清除这样的消息,则往这个主题再发送一条空的retain为true的消息即可,这样客户端在连接成功时就不会再收到这条消息了。
  • lastWill 简称遗嘱,遗嘱是一条普通的消息,设置遗嘱后,当客户端异常断开时,服务器会给遗嘱指定的主题推送这条消息。一开始我在想,客户端都断开了,怎么推送消息的啊,这是在客户端上线的时候把遗嘱先传给服务器了,所以客户端断线,则服务器来推送这条消息。如果是正常的断开连接,则服务器不会推送遗嘱消息。
  • MQTT测试客户端:MQTTX,目前感觉这个测试的客户端是非常好用的,而且这个网站上也有很多关于MQTT的教程。需要注意的是,新建连接是默认选的MQTT5.0协议,需要选择服务器支持的协议。
  • MQTT入门:https://www.hivemq.com/mqtt/

关于ActiveMQ服务器:

  • 服务器默认是启用了MQTT的,也就是说安装好ActiveMQ之后不需要配置就可以使用客户端来进行MQTT的连接了
  • 默认没有启用MQTT认证,也就是MQTT客户端连接时不需要提供用户名和密码就能连接
  • 默认的MQTT端口是1883
  • 目前的最新版本 ActiveMQ Classic 6.0.1支持 MQTT v3.1v3.1.1
  • 目前的最新版本 ActiveMQ Artemis 2.32.0支持 MQTT v3.1v3.1.1v5.0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2804270.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

第九节HarmonyOS 常用基础组件27-Rating

1、描述 提供在给定范围内选择评分的组件。 2、接口 Rating(options?:{rating:number, indicator?:boolean}) 3、参数 参数名 参数类型 必填 描述 rating number 是 设置并接收评分值。默认值&#xff1a;0&#xff1b;取值范围[0, stars]&#xff0c;小于0取0&am…

运维SRE-17 自动化批量管理-ansible3

--- - hosts:alltasks:- name: 01 打开冰箱门shell: echo 01 >> /tmp/bingxiang.log- name: 02 把大象放进冰箱里shell: echo 02 >> /tmp/bingxiang.log- name: 03 关上冰箱门shell: echo 03 >> /tmp/bingxiang.log[rootm01 /server/ans/playbook]# cat 05-n…

Spring Boot WebFlux:实现web(Server-Sent Events)事件异步推送

WebFlux 在Spring Boot中&#xff0c;Flux是一个重要的概念&#xff0c;它是Spring Framework 5.0以后引入的响应式编程框架WebFlux的核心组件之一。Flux是Reactor项目的一部分&#xff0c;它实现了Reactive Streams规范&#xff0c;用于处理异步、非阻塞的数据流。 与传统的…

Grounded-SAM(最强Zero-Shot视觉应用):本地部署及各个模块的全网最详细使用教程!

本篇文章主要对Grounded-SAM项目的部署以及使用进行讲解&#xff0c;目的是使读者可以直接参考文档去使用Grounded-SAM&#xff0c;而无需再去参考Github一步步自己去分析尝试&#xff08;也算是我使用过程中的心得&#xff09;。 对于Grounded-SAM 技术报告的paper阅读可以跳转…

介绍 CI / CD

目录 一、介绍 CI / CD 1、为什么要 CI / CD 方法简介 1、持续集成 2、持续交付 3、持续部署 2、GitLab CI / CD简介 3、GitLab CI / CD 的工作原理 4、基本CI / CD工作流程 5、首次设置 GitLab CI / CD 6、GitLab CI / CD功能集 一、介绍 CI / CD 在本文档中&#x…

echarts 实现x轴文字过长时折行展示

代码如下&#xff1a; this.options {color: ["#0075FF", "#00E2C4", "#FCA884", "#FFCB11"],grid: {top: "25%",bottom: "6%",right: "8%",left: "8%",containLabel: true,},legend: {top…

springboot751社区维修平台

springboot751社区维修平台 获取源码——》公主号&#xff1a;计算机专业毕设大全

TikTok账号注册指南:TikTok的注册方式有哪些?

随着全球数字化浪潮的加速&#xff0c;TikTok已成为跨越文化和国界的社交媒体巨头。对于寻找跨境电商机会的卖家来说&#xff0c;一个有效的TikTok账号都是打开通往成功之门的钥匙。本文将为大家详细介绍TikTok账号的注册方式&#xff0c;并提供一些实用的技巧&#xff0c;帮助…

018—pandas 生成笛卡尔积排列组合合并多列字符串数据

思路&#xff1a; 本需求需要将给定的几列数据&#xff0c;生成一个排列组合形式的数据列&#xff0c;利用到 Pandas 多层索引生成的笛卡尔积的方法。 二、使用步骤 1.引入库 代码如下&#xff08;示例&#xff09;&#xff1a; import pandas as pd2.读入数据 代码如下&…

【动态规划】【回文】【字符串】1147. 段式回文

作者推荐 【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子 本文涉及知识点 动态规划汇总 LeetCode1147段式回文 你会得到一个字符串 text 。你应该把它分成 k 个子字符串 (subtext1, subtext2&#xff0c;…&#xff0c; subtextk) &#xff0c;要求满足: subtext…

LeetCode104.二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3思路 计算二叉树的最大深度通常可以使用 递归 来实现。我们可以从根…

第九节HarmonyOS 常用基础组件26-Radio

1、描述 单选框&#xff0c;提供相应的用户交互选择项。 2、接口 Radio(options:{value:string, group:string}) 3、参数 参数名 参数类型 必填 描述 value string 是 当前单选框的值。 group string 是 当前单选框的所属组名称&#xff0c;相同group的Radio只能…

C语言-指针初学速成

1.指针是什么 C语言指针是一种特殊的变量&#xff0c;用于存储内存地址。它可以指向其他变量或者其他数据结构&#xff0c;通过指针可以直接访问或修改存储在指定地址的值。指针可以帮助我们在程序中动态地分配和释放内存&#xff0c;以及进行复杂的数据操作。在C语言中&#…

【算法分析与设计】1的个数

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位…

钧达股份:光伏跨界新贵只身赴港股,光伏“秩序重塑”?

2月21日&#xff0c;钧达股份终是在“千呼万唤”之中披露最新业绩快报。 快报显示&#xff0c;钧达股份预计2023年经调整后营业收入183.97亿元&#xff0c;同比增长58.65%&#xff0c;归母净利润8.32亿元&#xff0c;同比增长16.00%。 其中&#xff0c;由于Q4完整计提了9.5GW…

洛谷 【算法1-2】排序

【算法1-2】排序 - 题单 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 鄙人不才&#xff0c;刷洛谷&#xff0c;迎蓝桥&#xff0c;【算法1-2】排序 已刷&#xff0c;现将 AC 代码献上&#xff0c;望有助于各位 P1271 选举学生会 【深基9.例1】选举学生会 - 洛谷 题目 解答…

概率密度函数(PDF)与神经网络中的激活函数

原创:项道德(daode3056,daode1212) 在量子力学中&#xff0c;许多现象都是统计的结果&#xff0c;基本上用的是正态分布&#xff0c;然而&#xff0c;从本质上思考&#xff0c;应该还存在低阶的分布&#xff0c;标准的正态分布是它的极限&#xff0c;这样一来&#xff0c;或许在…

《论文阅读》通过识别对话中的情绪原因来提高共情回复的产生 EMNLP 2021

《论文阅读》通过识别对话中的情绪原因来提高共情回复的产生 EMNLP 2021 前言简介方法实现Emotion ReasonerResponse Generator实验结果示例总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Improv…

备战蓝桥杯—— 双指针技巧巧答链表1

对于单链表相关的问题&#xff0c;双指针技巧是一种非常广泛且有效的解决方法。以下是一些常见问题以及使用双指针技巧解决&#xff1a; 合并两个有序链表&#xff1a; 使用两个指针分别指向两个链表的头部&#xff0c;逐一比较节点的值&#xff0c;将较小的节点链接到结果链表…

【ECharts】调用接口获取后端数据的四种方法

使用eacharts做大屏&#xff0c;需要使用后端数据&#xff0c;下面的方法是自己试过有效的&#xff0c;有什么不对的&#xff0c;望各位大佬指点。 目录 方法一&#xff1a;在mounted中使用定时器调用eacharts方法&#xff08;定时器可以获取到data中的数据&#xff09; 方法…