MQTT实现IM即时通讯

摘要:
MQTT是一种基于发布订阅模型的即时通讯协议,由于轻巧,开源,易用,耗能少,支持QOS/遗言等特性,正被广泛应用于物联网和移动互联网。ClientID由两部分组成,组织形式为GroupID@@@DeviceID。注意,p2p消息,二级Topic必须是p2p字样,三级Topic是目标设备的ClientID。

MQTT 是一种基于发布订阅模型的即时通讯协议,由于轻巧,开源,易用,耗能少,支持 QOS/遗言(WILL)等特性,正被广泛应用于物联网和移动互联网。
消息队列 MQ 提供了对 MQTT 协议的支持,完全兼容 MQTT 标准协议,但是在使用 MQ MQTT 时,对比标准协议,需要注意两点:
1. 父级 Topic 需要提前创建
根据标准 MQTT 协议,Topic 存在多级,且拥有动态的特性(不需要用户提前定义和创建),但是使用过消息队列 MQ 的用户都知道,MQ Topic是需要通过 MQ 控制台提前创建的,这是因为 MQ MQTT是队列(消息持久化),且 MQ 不仅支持 MQTT 协议,还支持 TCP, HTTP 协议的接入,为了能将不同方式接入的消息互通,比如:用 MQTT 方式发送的消息,用 TCP 方式可以收到;用 HTTP 方式发送的消息,用 MQTT 方式也能收到,故 MQ MQTT 做了以下变通:
定义第一级 Topic 为父 Topic,使用前,需要在 MQ 控制台创建父 Topic,子级 Topic 无需创建,直接在代码中使用。
2. MQ MQTT 支持 p2p,且不需要显示订阅
这一点弥补了标准 MQTT 协议不支持 p2p 的遗憾。而且通过 TCP/HTTP 接入的客户端都可以收发 p2p 消息。

MQTT Topic的动态特性给设计者们带来了很多发挥空间,但是有些地方需要注意:
1)名称不能带/和空格
2)短小精干,简洁明了
3)使用 UTF-8,避免不可见字符
4)在一些特殊场景里,考虑将唯一设备号嵌入到 Topic 名称,便于辨识消息发送者
比如,只有 client1 可以发布消息到client1/status, 且不能发布到client2/status,那么当你收到client1/status时,可以肯定就是client1发送的消息。
5)谨慎使用通配符#
比如,订阅 news/sport/#, 那么你就会收到下面所有这些 Topic 的消息
news/sport
news/sport/player1
news/sport/player2
news/sport/player1/score
不可预计的消息数量,会对接收端(移动端,嵌入式设备)造成负担。
6)业务可延伸
订阅关系需要事先建立,所以发送端和接收端都需要提前意识到 Topic 的存在,这就要求我们合理设计 Topic 的结构,在增加新业务需求时,适当增加子级 Topic 即可,而不用修改,甚至推翻 Topic 原先的结构。
比如,订阅李娜的新闻,可以设计成订阅 news/lina, 但是文体娱乐圈里有很多和李娜重名的,后续业务需要,用户想订阅网球李娜的新闻时,整个 Topic 结构将被迫改变,所以,在业务设计之初,尽可能在延伸性上多考虑一些。
这样设计较之前就更稳妥些:
news/sport/tennis/lina
news/sport/tennis/lina/ranking
news/sport/tennis/lina/score/australianopen
下面结合 MQ MQTT 特点,提供一个社交 IM 场景下的实现雏形,欢迎大家讨论。
准备工作:在 MQ 控制台创建父级 Topic 和 GroupID
每个设备接入 MQ MQTT 服务时,都要提供 Client ID,这是每个客户端的唯一标识,要求全局唯一。
Client ID 由两部分组成,组织形式为 GroupID@@@DeviceID。
GroupID: 需要在 MQ 控制台申请创建,用于指定一组逻辑功能完全一致的节点共用组名,代表一类相同功能的设备。
DeviceID: 每个设备独一无二的标识,由业务方自己指定,无需在 MQ 控制台创建。
我们在 MQ 控制台创建父级 Topic:IMS 和 GroupID:GID_IMS,且假设
用户A使用设备GID_IMS@@@DeviceID_A
用户B使用设备GID_IMS@@@DeviceID_B
用户C使用设备GID_IMS@@@DeviceID_C
场景1,用户A请求加用户B为好友,并进行一对一聊天
方案一,使用 p2p 消息。
优点是无需双方提前订阅(其实 p2p 功能也是通过订阅来实现的,只是用户在使用时无感知),缺点是如果DeviceID_B同时收到多个好友申请(见2),如何分辨是谁发送的请求呢?
从消息 Topic 是无法得知的,只能通过解析 message body 来辨识。
注意,p2p 消息,二级 Topic 必须是 p2p 字样,三级Topic是目标设备的 Client ID。
方案二,给每一个用户设计一个 Inbox,每个用户在客户端登录时都要订阅自己的 Inbox。
优点是每个用户收到消息时,可以通过解析 Topic 知道是谁要加他为好友,也能知道谁通过了他的好友添加请求。
当 USER B 收到消息 IMS/UserB/Inbox/Add/GFReq/UserA (见4),就知道是来自于 USER A 的好友添加请求。
当 USER A 收到消息 IMS/UserA/Inbox/Add/GFResp/UserB (见6),就知道是来自于 USER B 的反馈。
场景2,用户A关注好友B动态,B更新朋友圈,A收到更新
用户 A 想关注好友 B 的朋友圈动态,可以订阅 IMS/UserB (见1)。
好友 B 有好东东想晒一下,可以发布 IMS/UserB (见2),发布之后,所有订阅 IMS/UserB 的好友都可以看见这条分享(MQ MQTT 会负责将消息发送给所有订阅的好友)。
如果 A 不想看 B 的朋友圈动态了,那么就取消订阅 IMS/UserB (见4)。
如果是 B 不想让 A 看见自己晒的东东,该怎么办呢?
也可以利用 Inbox。
用户 A 登录时订阅 IMS/UserA/Inbox/Update/# (见2)
用户 B 发送一条消息到 IMS/UserA/Inbox/Update/UserB/Unsub (见3),A 在收到这条消息后,取消订阅 IMS/UserB (见5),在此之后,B 在朋友圈所有的分享,好友 A 都是看不到的。
当然,A 在收到 B 的取消订阅请求(见4)后,是弹窗通知到 A 本人(让 A 知晓被 B 拉黑)还是静默(A 被默默拉进 B 的黑名单),就完全由应用设计来决定了。
场景3,用户A邀请B,C好友进行群聊(B,C非好友关系)
群聊创建者 A 首先要订阅 IMS/Group123/# (见1)。
邀请用户 B, C 加入群聊,可以使用 p2p 消息(见2,4)。
用户 B, C 同意加入群聊,订阅 IMS/Group123/# (见6,7)。
加入群聊组中的成员 B 想要发言,可以携带自己的身份信息发布到 IMS/Group123/UserB (见8), 这样一来,所有订阅 IMS/Group123/# 的成员都能看到 B 的这条发言了。
场景4,逢年过节,给多个好友发送祝福信息(群发消息,不是群聊噢)
可以逐一给好友发送 p2p 消息,或者发送消息到各好友的 Inbox 中。
这种方式的缺点是需要多次 Publish,有几个好友,就需要 publish 几次(见4,6)。
不想 publish 多次,该怎么办呢?
Sorry,目前确实没有更好的办法。
其实我们希望可以创建一个虚拟 Group,好友们不用显示订阅这个 Group,由系统根据业务配置动态创建订阅关系。完成的效果是,好友们能收到发送给这个 Group 的消息,但是不会意识到这个 Group 的存在,因为客户端没有发起过订阅虚拟 Group 的动作(原理类似 p2p 订阅)。
目前 MQ MQTT 还不支持这样的功能,我们期待后续它可以提供这样功能的 Plugin,方便业务端扩展更多功能。
场景5,商业推广,系统给不同种类/定位的用户推送消息
想给不同地域的用户推送系统的新年祝福,消息的内容根据用户地域不同而变化。
正如之前的群发场景一样,使用 p2p 或者 Inbox 固然可以做到,但是整个系统,那么多用户,逐一发送并不是理想的方式。
而目前 MQ MQTT 又不支持虚拟 Group,如何完成这个功能呢?
业务设计之初,预留一个给系统广播使用的 Topic, 比如 IMS/System,每一个用户除了订阅自己的 Inbox,好友之外,也要根据自己的属地订阅系统预留的 Topic (见1,2)。
如:
北京用户订阅 IMS/System/Beijing
杭州用户订阅 IMS/System/Hangzhou
系统发送一条消息到 IMS/System/Beijing(见3), 所有北京用户都会收到(见4),系统发送一条消息到 IMS/System/Hangzhou(见5), 所有杭州用户都会收到这条消息(见6)。
用户登录客户端时,业务应用就需要预先判断其属地,并订阅相应的预留 Topic。
这种方案其实不够灵活,因为当后续扩展新业务功能时,程序需要升级(订阅新的 Topic 来满足新业务),但就目前来说,这也不失为一种可行的解决方案了。

免责声明:文章转载自《MQTT实现IM即时通讯》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇go开发工具goclipse的安装Windows SMBv3 CVE-2020-0796 漏洞分析和l漏洞复现下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Unity碰撞消息(OnCollisionXXXX)和触发消息(OnTriggerXXXX)的调用情境

MonoBehaviour中的消息非常多,一共有62个! 除了必须关注的脚本生命周期的一系列函数外,还有其他两组比较常混淆的消息:碰撞和触发。 按3D和2D物体区分,又分为碰撞:Collision、Collision2D。触发:Trigger、Trigger2D。 以3D物体为例做了如下实验,分别测试下OnColiisionXXXX碰撞消息和OnTrigg...

web中打开word为什么老是提示无法打开宏储存?

是因为用户没有在服务器端运行Word的权限,应在服务器端做如下操作:1.开始--运行--dcomcnfg--Microsoft Word 文档--属性--身份标识--交互式用户否则会出现“消息筛选器显示应用程序正在使用中”的错误2.开始--运行--dcomcnfg--Microsoft Word 文档--属性--安全性--使用自定义访问权限--添加Ever...

Netty(4)Stream by codec(粘包与拆包)

TCP/IP,传输的是byte[],将byte[]放入队列中。可能会发生粘包和拆包。 比如,客户端向服务端发送了2条消息,分别为D1,D2,可能产生的情况,如下图所示: 情况一:正常的。 情况二:粘包。 情况三:拆包。即:部分数据不是一次完整发送的,而是分了至少2次发送。 如本例,D2拆成了D2_1和D2_2,这是拆包。 服务端分2次收到包,第一次收到了...

OpenSSL 介绍和使用

转自:https://www.jianshu.com/p/fb2ae3dc7986 一、SSL 简介 按照我的理解来解释下,为了让网络通信更安全,需要认证和加密,认证是说明你是要找的人,加密是为了让截获中间报文第三者无法得到消息内容。 为此有人设计了SSL,即套接字上的安全层,简单来说就是在TCP之上做一个安全通信层,HTTP on SSL 即是HTT...

kafka集群搭建和使用Java写kafka生产者消费者

 kafka集群搭建 Java代码   1.zookeeper集群  搭建在110, 111,112      2.kafka使用3个节点110, 111,112   修改配置文件config/server.properties   broker.id=110   host.name=192.168.1.110   log.dirs=/usr/...

微信5.0新功能体验

微信5.0今日内部体验版发布,老裴第一时间拿到了邀请并进行安装体验,下面将体验的结果与大家分享一下: 首先是安装之后的登陆界面: 登陆之后,微信5.0与以往一段风骚的段子作为开幕所不同的是,这次是先要亲“打飞机”,没错是打飞机: 微信为什么会让你打飞机呢?目的还是有的,微信5.0的发现中多了一个游戏中心,也就是说微信5引入了游戏。 另外在添加朋友里面...