- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
这是个有趣的话题! 先来聊几个小故事.
我在人生第一个IoT项目里,第一次接触到MQTT协议。 我很快就理解了这个协议。因为,它和企业开发用的MQ产品实在是太像了。 在我职业生涯早期,是的,20年前,当时做一个银行的项目,就用过MQ这东西,那个项目使用了IBM MQ。随着工作经验的增加,在另外一些项目中,也会接触使用到MQ产品。 后来,我在做国产中间件的公司里开发中间件,当时我们有个团队,专门在做MQ产品。 所以,当我第一次读MQTT资料的时候,我心里立马浮现出了这样的看法:这不就是一个轻量级的、给IoT应用使用的MQ吗.
我和XMPP之间的故事要复杂很多。 那是中国电信的一个项目,电信想在手机里集成融合通信软件。运营商的思路也很直白,微信你不是牛逼吗,你用互联网短信来代替我的电信网短信、用互联网音视频来取代我的电信通话网络,夺取我的生意,抢夺我的通道。我们运营商必须反击,我们必须要有应对的解决方案! 当时中国电信想到的解决方案之一,就是手机内置融合通信软件。 简单点说,运营商每年要送出很多的手机,办套餐送手机,这是运营商常用的营销套路。运营商的思路,如果这个送的手机,用户拿到手里的时候,它就已经自带了微信所有的功能了,那为啥还要另外再安装一个微信呢? 在手机里预置电信运营商开发的一个软件,这个软件具有微信所有的功能,功能被直接紧密集成在手机电话簿里,用来和联系人来发信息、聊天、语音和视频了,走互联网通道。 这个电信运营商想内置在手机里替代微信的软件,被叫做融合通讯软件。 因为要做中国电信的这个项目,我第一次接触到了XMPP协议。 后面的故事不出所料,融合通讯软件并未能掀起风浪,微信依然被安装在每一台手机上。 是的,我和XMPP的情缘,从那时候开始了。 在这个电信的项目中,我使用了Openfire XMPP Server,这应该是Java界最出名的一个开源XMPP服务器了。 Openfire作为一个标准的XMPP Server,其实它还挺可以的。在开发项目过程中,我当然会读它的代码,我会时不时发出感慨:老外写代码还真是挺认真的! 老外写东西,真的是认真!但是Openfire开源XMPP服务器,它并不能让我满意。 融合通信软件,当然会有不少需要定制的功能。但是,看看下面这段摘自Openfire的源码,就应该会明白,为啥我并不是那么的满意。 以下代码,来自Openfire项目src/main/java/org/jivesoftware/openfire/XMPPServer.java文件.
... ...
private void loadModules() {
// Load boot modules
loadModule(RoutingTableImpl.class.getName());
loadModule(AuditManagerImpl.class.getName());
loadModule(RosterManager.class.getName());
loadModule(PrivateStorage.class.getName());
// Load core modules
loadModule(PresenceManagerImpl.class.getName());
loadModule(SessionManager.class.getName());
loadModule(PacketRouterImpl.class.getName());
loadModule(IQRouter.class.getName());
loadModule(MessageRouter.class.getName());
loadModule(PresenceRouter.class.getName());
loadModule(MulticastRouter.class.getName());
loadModule(PacketTransporterImpl.class.getName());
loadModule(PacketDelivererImpl.class.getName());
loadModule(TransportHandler.class.getName());
loadModule(OfflineMessageStrategy.class.getName());
loadModule(OfflineMessageStore.class.getName());
loadModule(VCardManager.class.getName());
// Load standard modules
loadModule(IQBindHandler.class.getName());
loadModule(IQSessionEstablishmentHandler.class.getName());
loadModule(IQPingHandler.class.getName());
loadModule(IQBlockingHandler.class.getName());
loadModule(IQPrivateHandler.class.getName());
loadModule(IQRegisterHandler.class.getName());
loadModule(IQRosterHandler.class.getName());
loadModule(IQEntityTimeHandler.class.getName());
loadModule(IQvCardHandler.class.getName());
loadModule(IQVersionHandler.class.getName());
loadModule(IQLastActivityHandler.class.getName());
loadModule(PresenceSubscribeHandler.class.getName());
loadModule(PresenceUpdateHandler.class.getName());
loadModule(IQOfflineMessagesHandler.class.getName());
loadModule(IQPEPHandler.class.getName());
loadModule(IQPEPOwnerHandler.class.getName());
loadModule(MulticastDNSService.class.getName());
loadModule(IQSharedGroupHandler.class.getName());
loadModule(AdHocCommandHandler.class.getName());
loadModule(IQPrivacyHandler.class.getName());
loadModule(DefaultFileTransferManager.class.getName());
loadModule(FileTransferProxy.class.getName());
loadModule(MediaProxyService.class.getName());
loadModule(PubSubModule.class.getName());
loadModule(IQDiscoInfoHandler.class.getName());
loadModule(IQDiscoItemsHandler.class.getName());
loadModule(UpdateManager.class.getName());
loadModule(InternalComponentManager.class.getName());
loadModule(MultiUserChatManager.class.getName());
loadModule(IQMessageCarbonsHandler.class.getName());
loadModule(ArchiveManager.class.getName());
loadModule(CertificateStoreManager.class.getName());
loadModule(EntityCapabilitiesManager.class.getName());
loadModule(SoftwareVersionManager.class.getName());
loadModule(SoftwareServerVersionManager.class.getName());
// Load this module always last since we don't want to start listening for clients
// before the rest of the modules have been started
loadModule(ConnectionManagerImpl.class.getName());
loadModule(ClusterMonitor.class.getName());
// Keep a reference to the internal component manager
componentManager = getComponentManager();
}
... ...
服务器装载的模块功能(Modules),居然是被硬编码写死的!!! 好吧,我承认,在那个项目中,我改过Openfire的源码,为了把项目定制的功能加到服务器中去。 帮客户做项目嘛,能够达到项目目标,能够按期交付,把款收回来就可以了啊!你还想干嘛? 我还想干嘛,是的,我还想干嘛? 在那个疯狂的年月,我想说,这个行业里,人人都会有个互联网英雄梦! 我也有梦,我有个社交领域的创业梦,我想去试试做这件事,干这事需要使用实时通讯技术。 于是,我开始开始读XMPP规范,我读 RFC3920(XMPP Core) 、 RFC3921(XMPP IM) 、 XEP-045(Multi-User Chat) ... ... 读了一些规范之后,我得出这样的结论,Openfire恐怕达不到我的创业要求,我最好是自己来写一个XMPP Server。 当然,凭我的技术能力,只要我愿意,我可以去改Openfire的代码,最终也可以实现创业项目的功能需求。 问题是,在那时,对,这时候说的那时,已经是在10年前。在那时,我还是如此的理想化,如此对未来充满了憧憬,我觉得自己可以干翻一切,何况只是需要去实现一个实时通讯协议标准和产品。 我可以搞定,我会做得很好!就这样定了,自己动手写一个。 于是,有了 Basalt 、 Chalk 、 Granite 这一系列XMPP基础架构项目。 2年后,我去尝试了自己的梦,使用XMPP来做自己的社交App项目。 项目最终失败了,这些XMPP的代码,也暂时被封存在了代码仓库里.
春去秋来,潮起潮落,时光飞逝。 2018年,我来到了一家做IoT的创业公司做CTO。我是第一次做IoT项目,我认真上网查资料,理解技术,设计系统。 由于是第一次做IoT项目,我非常谨慎的选择了技术方案。在网关到互联网服务器之间的互联网通讯协议选择上,我选择了使用MQTT,看上去这是一个大众流行的,也比较安全的解决方案。 产品做出来了,我们开始做推广,完善产品,继续融资,扩大推广。 其实那次,我们已经有点接近成功了。我们部署了3.5k智能锁节点,融了Pre-A轮1600w。机构方说,你们下一阶段的工作,就是1w个节点,然后融A轮,公司A轮估值不低于2亿,后续融资的事你们不用管,我们会搞定一切,你们就专心努力完成业绩要求。 然而,在经历一系列的决策错误后,创业最终失败了... ... 我又在思索了,在自己做社交创业失败后,我又呆了两家创业公司,做技术合伙人。一家做到A轮,一家做到Pre-A轮。然而,这两家公司最终都失败了。 因为这两家创业公司,我放弃了去阿里巴巴的工作机会,也放弃了到一家银行工作的机会(给的offer总包年薪超100w)。 我在重新思考自己的方向,毕竟年龄也不小了,我应该寻求稳定不是吗?
我选择了一家上市公司的中央研究院,他们的项目,又是IoT,做智慧城市里的智慧路灯杆。 我和IoT之间,情缘未了! 。
我对MQTT还是非常熟悉的,我用它做过IoT应用,开发过IoT产品。 我对XMPP应该说算是精通了,我写过XMPP基础开发库、XMPP服务器、实现过XMPP的各种标准,并基于XMPP做了了IoT开发平台。 我尝试客观的来评价这两种协议,如果抛开我更擅长XMPP,以及Lithosphere基于XMPP技术开发的主观立场,我如何评价这两种协议呢? 以下两种协议的对比,包括对两种协议的优劣点评价,以及针对协议缺点的解决方案讨论,都基于我个人观点。受个人知识面和经验的限制,如果有评价不准确,没找对好的解决方案思路等问题,请网友们给予批评指正。 交流,就是想跟大家交流,分析问题,寻求答案,不在于争论对错,而是想找到对两种协议客观、正确的理解.
缺少P2P通讯机制 MQTT客户端并没有一个全局的、持久性的唯一Client ID,MQTT客户端的Client ID在每次连接到Broker时,由客户端指定或由Broker来自动生成。 那么,当我们想想做特定客户端的指令控制类型操作时,就会比较不方便了,因为:
解决方案讨论: 比较常见的解决方案是,为每个客户端,创建一个和客户端Client ID相关的,私有专用的消息接收Topic,用于接收发送给这个客户端的的消息。 例如,我们约定,当客户端程序连接Broker成功后,客户端程序会立即开始监听名为Clients/<CLIENT_ID>的Topic,通过往这个专用Topic里发送消息,我们就间接实现了P2P的消息通讯。 在这个约定下,一个客户端连接成功后,如果它的Client ID是"1234567890",那么客户端连接成功后,这个客户端就开始监听名为"Clients/1234567890"的Topic。那么往这个Topic里publish的消息,这个客户端就可以收到。 需要考虑的一个问题是安全性问题,因为我没有在MQTT的规范里,读到有关于主题订阅的权限限制的内容。那么,一个客户端在理论上,是可以监听到其它客户端的私有专用消息通道的。也许可以考虑给私有消息都用私钥加密,来提供更好的安全性.
没有应用层协议 MQTT提供了一条通讯层的通道,你可以用这个通道来传输任何格式的数据。 这个东西有利有弊吧,有利的地方在于灵活性,开发者可以自由的定义任何格式的应用层协议,不受任何规则限制。不利的地方在于,大部分应用开发者,其实并没有足够的知识和经验,可以设计出足够好的应用层协议.
实时性差 消息实时性和数据可靠性,这两个特性看上去是鱼与熊掌,往往需要我们做出选择与权衡。 在MQTT中,设置了QoS.AT_LEAST_ONCE和QoS.EXACTLY_ONCE的消息,实时性会比较差。 我们在智能锁的项目里,曾做过以下的测试。 我们保持移动端和服务器端之间的通讯畅通,断开服务器到锁终端设备之间的通讯通道。 然后我们从App端发送开锁指令给锁终端,由于通讯线路被断开,这时锁是不能被打开的。 2分钟之后,我们将和服务器端和锁终端设备之间的通讯线路恢复正常,这时候,锁被打开了。 解决方案讨论:
提供P2P通讯机制 在XMPP网络中,任何需要连接到XMPP服务器的节点(Node),无论它是人(User)或者是物(Thing),都需要有一个全局的XMPP账号。在XMPP概念里,这个账号叫做Jabber ID。 使用联系人/物的Jabber ID,就可以给它发送直接消息(前提为权限允许,例如:联系人在好友列表中)。 对于远程控制类型的IoT应用来说,这简直太方便了.
实时性强 XMPP就是一个实时通讯协议,实时性强是它的协议特征。 在一些IoT应用场合,我们就是需要更好的消息实时性。 我一条控制指令发过去,指令正确到达且正确执行了,你就返回正常执行确认;如果执行失败,你就返回对应错误码;如果不能确认执行结果,请告诉我超时了,让程序来处理超时逻辑。 无论啥情况,请立马告诉我,而不是2分钟后再突然执行指令。Ok,这就是我们需要的实时性。 以下的代码来自Lithosphere的sand-demo,它示范了这种实时性需求.
... ...
private static class RemotingActionCallback implements IRemoting.Callback {
... ...
@Override
public void executed(Object xep) {
// Code for action has executed correctly.
activity.runOnUiThread(() -> Toast.makeText(activity,
"Action has executed.",
Toast.LENGTH_LONG).show());
}
@Override
public void occurred(StanzaError error) {
// Code for error occurred.
String errorText = "Action execution error: " +
(error.getText() == null ? error.toString() : error.getText().getText());
remotingErrorOccurred(activity, error, errorText);
}
@Override
public void timeout() {
// Processing logic for timeout.
activity.runOnUiThread(() -> Toast.makeText(activity,
"Action execution timeout.",
Toast.LENGTH_LONG).show());
}
}
协议扩展性强,内置应用层通讯协议基础规则 XMPP和MQTT的设计思路有些区别。 MQTT协议的关注点,在于如何在网络层提供一条可信赖通道。然后吧,你愿意在这个通道上做啥就做啥,我协议是不管你任何应用层的事情的。 XMPP的协议特征之一,是具有很强的可扩展性。XMPP全称Extensible Message and Presence Protocol。XMPP里的X,是Extensiable(可扩展)的意思,表达了XMPP协议的这个协议特征。 XMPP协议被分成两部分,一部分是核心标准规范,包括 XMPP Core(RFC3920) 和 XMPP IM(RFC3921) 。 另一部分是XMPP的扩展协议, XEPs(XMPP Extension Protocols) 。XEPs协议族里,包含了大概300多个协议,这些协议覆盖的内容范围,简直包罗万象。这当然证明了XMPP协议的超强扩展性特征。 XMPP协议族覆盖的内容很多,既包含了网络层的协议,也包括应用层协议。 例如, User Avatar(XEP-0084) 。这个协议当然是一个应用层协议,这个规范定义了在实时通讯系统中,用户虚拟身份使用的解决方案。 在XMPP的标准规范 XMPP Core(RFC3920) 中,定义了XMPP协议的一堆基础规则,包括:
好吧,你当然可以认为,这么多规则,严重限制了开发者的想象力嘛! 我会这样认为,这是设计出色的应用层通讯协议的一个良好基础.
基于XML,通讯效率差 这应该是XMPP协议受到最多攻击的一个问题了。XMPP太重了,XMPP不适合移动互联网,更不适合物联网。 解决方案讨论:
缺少内置的QoS支持 MQTT是一个轻量级的MQ,QoS基本上是MQ软件的标配,MQTT也不例外。 XMPP由RFC标准协议加上XEPs组成,在RFC标准协议中,并没有要求提供QoS支持。 对于数据上报类型的IoT应用,QoS是非常必要的。 解决方案讨论:
实现QoS协议 XMPP的XEPs里,目前还缺少关于QoS的正式标准。 可以看到有一个草稿标准 Quality of Service(XEP-xxxx) 。需要注意的是,这个标准目前的状态,还是XEPs的草稿标准(ProtoXEP)状态,这表示这个规范还未能通过XSF(XMPP Standards Foundation/XMPP标准基金会)的标准审批过程。 我读了一下这个XMPP的QoS草稿标准,这个规范里的XMPP QoS实现,看上去和MQTT规范里要求的QoS实现,几乎没有什么区别。 区别只在于,两个协议的QoS控制指令的术语叫法不一样。比如:
虽然这只是一个草稿标准,但是由于这个XMPP标准对应的QoS处理逻辑,看上去和MQTT标准里的QoS实现逻辑,几乎没有什么区别。理论上,可以认为,实现这个XMPP草稿规范后,就可以为你的XMPP实现提供QoS支持了.
缺少IoT相关规范和开源产品实现 XMPP社区的伙计们,有在积极的探索XMPP在IoT领域的应用,我们可以看到社区在这个方向上的一些工作,比如:
但是目前的状况看上去,XMPP虽然在实时通讯领域取得了很大的成功,但是在IoT应用领域,XMPP还是小众技术。 IoT方向上相关的标准规范,都还是草稿状态,并没有进入正式的标准化过程。 在开源产品实现上,做了IoT支持的开源产品还比较少,而且实现都还比较不完善。我能看到的,以下XMPP开源产品有提供IoT相关的功能:
实现较为复杂,学习成本高 XMPP和MQTT,在协议的设计思路上,有着比较大的差异。 MQTT :Hi,朋友!我会给你一个速度快、简单好用、安全可靠的通讯通道。Ok,我的工作做完了!你愿意在上面干嘛就干嘛,我是不管的,请别再来找我了。 XMPP :我们会提供一个灵活、强大的网络通讯协议,它的灵活性来自高扩展性,它的强大来自我们提供了几百个实时通讯相关标准。我们希望这一把能彻底搞定实时通讯领域的各种问题! 什么,还缺少IoT相关标准?缺少IoT开源产品实现?目前就是这状况哦!请你深刻理解XMPP技术,自行定义私有IoT通讯协议来解决问题。可以做到的!你放心,XMPP技术相当灵活!可以做到的!我们对你有信心! 和MQTT的完全自由有所不同,如果你使用XMPP协议,你需要遵循协议标准中的一些规则和要求。由于XMPP协议较MQTT协议复杂,功能更多,正常来说,会需要更多的入门学习时间。 从另外一个角度来看,如果是已有的XMPP协议规范,如果是第三方产品中已经实现了的XMPP扩展协议功能呢?那可是现成的东西直接拿来用起,爽不爽? 解决方案讨论:
两个协议都可以用于IoT应用。这两个协议存在着明显的差异,不能说哪个是更好的,需要结合应用需求,团队技术能力和技术积累等各种因素,对技术选型进行综合考虑.
MQTT协议非常适合用在传感器网络为主,数据上报类型的应用中。MQTT的Public-Subscribe模式,以及QoS支持,似乎就是专门为这类型的应用来设计的。 所有的传感器设备,在上报数据中,只需要带上设备身份标识,带上数据采集时的时间戳,统一上报到数据处理的Topic通道去。 其它事,让服务器去干。 够用、简单好用,很爽! 。
XMPP的优势在于它的灵活性以及实时性。 如果你的IoT应用,会有复杂的通讯控制逻辑,以及有很高的实时性通讯需求,值得考虑XMPP.
MQTT最大优势,应该是它的简单易用性。能不能不要花那么多时间来学习通讯技术了,能不能尽快开始编码开搞应用需求? MQTT的短板,似乎是它的基础架构只提供了较单一的通讯机制,当我们碰到一些通讯上的复杂需求时,我们需要做更多工作来解决问题。当然,我们可以:
XMPP的优势在于它的灵活性。如果我有很复杂的通讯逻辑需要处理;如果我想在通讯层上面提供一个更易用的组件开发模型,XMPP可以帮你实现这些复杂需求。 但是需要考虑问题是,你真正理解和学会XMPP了吗,你能在自研的或者第三方XMPP基础件上,自由的开发XMPP扩展协议了吗?
两者都还不够好! 标准的MQTT,标准的XMPP,在IoT应用中都还不够好!不够用!不能够覆盖到IoT里各种复杂应用需求。我们往往需要在标准协议之上,再做很多的工作来解决问题。 连接万物,哪有这么简单! 。
都不够好,不够用 标准MQTT,标准XMPP,对于连接万物的IoT来说,都还不够好!不够用! MQTT对于传感器数据上报类型的应用,把数据安全传输到服务器端,然后服务器端一步去做数据分析,去做大数据,搞AI。对于这种类型的应用来说,MQTT够用的。 对于一些更复杂的IoT通讯需求,MQTT的通讯机制太单一了,不够用,举两例子吧:
标准XMPP,也不够好!也不够用!缺少IoT标准,市场上的开源产品普遍缺少IoT功能的支持.
XMPP扩展性更好,更容易在协议层去做扩展功能 XMPP的协议特征之一,就是高扩展性。如果要选其中一个协议来做协议层的扩展,XMPP看上去会方便很多.
基于我自己写的XMPP开源基础件,我可以用XMPP做到任何事 这个肯定是最重要的因素了,最终决定了Lithosphere的通讯协议技术选型。 如果我当年不是因为想做社交App创业,去写了XMPP库,XMPP服务器。如果当年因为机缘巧合,我写了MQTT的开源项目,那我现在会怎么选择? 人生没有如果! 假设一下嘛,哈哈。 我想,我应该会选择做基于MQTT的IoT解决方案。 人生没有如果!我现在就是写了XMPP开源基础件,我就用这些XMPP基础件,写了Lithosphere.
使用XMPP的效果如何? 哈哈,可以看看我写的Hello,Lithosphere系列教程,你来做评价。 如果是想要评估Lithosphere的功能和技术效果,建议看这两篇教程。 Hello, LoRa! 这个教程里覆盖了IoT协议的整个通讯流程,包括IoT终端设备集成(MCU板)、IoT LPWAN协议通讯(LoRa通讯协议)、IoT通讯网关、IoT通讯服务器端处理。 Hello, WebRTC! 使用封装好的WebRTC的Webcam插件,做一个实时监控摄像头,这事还挺简单的。 关于MQTT vs. XMPP的话题,就聊这么多了! 。
最后此篇关于MQTTvs.XMPP,哪一个才是IoT通讯协议的正解的文章就讲到这里了,如果你想了解更多关于MQTTvs.XMPP,哪一个才是IoT通讯协议的正解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我是一名优秀的程序员,十分优秀!