推送与IM即时聊天可行性分析报告与解决方案汇总
第一部分:理论分析
一、前言
目前市面上有很多第三方推送与IM即时聊天解决方案,如腾讯信鸽、极光推送、网易云信等第三方平台,但是这些平台有时并不能满足我们的需求,比如要求我们的系统必须部署到内网环境等情况,或者出于公司知识产权等考虑,这时我们就不得不自己想办法搭建推送服务器。
二、自建推送/IM服务器要考虑的问题
随着社交应用的普及,人们对即时聊天的要求也越来越高,截止2017年上半年为止,我大概总结了一下,一个基本的聊天应用起码要考虑到以下几点才算是一个可用的方案:
- QoS,对于传送质量的要求:未成功发送的消息如何保证送达?重试时如何保证不重复送达?
- 实时网络监测:如何在连接已断开时及时通知用户?
- 数据持久化:聊天记录如何保存?
- 消息队列:一次发送多条消息时如何保证有序到达?
- 发送回执与状态显示:只有在发送成功情况下消息才不显示任何额外标识,否则在发送过程中要显示Loading图标,发送失败后要显示感叹号图标,所有这些是否可通过监听发送回执来做到?推送服务器是否支持发送回执?
三、推送实现的可选方式
(1)自己写socket长连接:
其实很多人建议我们在手机端自己写一个socket长连接,然后采用轮循的方式不断从推送服务器去取数据,不可否认早些年在移动互联网刚开始发展的阶段这确实是一种解决方案,那时候没有成熟的协议,没有成熟的组件,也没有解决以上第二点中提出的那么多需要注意的点。而且随着时代的发展,这种方式的缺点也越来越明显,最要命的是它耗电、耗流量、耗系统资源,而且还不稳定,如果用户量达到一定数量服务端是绝对受不了了几万台终端同时用这种方式轮循的。
(2)使用官方推送渠道:
对于苹果手机来说,推送的实现方式比较简单,苹果公司统一提供了全局唯一的socket长连接,所有应用共享这一连接,所有推送也都经过这个连接来推送,开发人员只需要接入苹果的APNs即可。其实对Android手机来说,也有类似的实现方式,Google公司仿照苹果公司的模式也为Android操作系统提供了类似的“官方”推送服务器,叫做谷歌云消息系统(Google Cloud Messaging,简称GCM),但是由于要连接Google的服务器,众所周知的原因,这一服务无法在国内使用,如果我们想实现包括Android在内的全平台的统一推送服务,就要另想办法了。
(3)根据已有的成熟的推送协议自已搭建标准的推送服务器:
其实除了自己写socket长连接和使用官方渠道之外,目前已经有很多成熟的推送协议可供选择,比较流行的几种即时通信协议为ddpush、xmpp和mqtt,有关这几种推送协议的优缺点有一篇文章大家可以参考一下:
《总结ddpush、xmpp、mqtt在做推送的时候的选择》,链接:
http://blog.csdn.net/languobeibei/article/details/56288947
四、选择哪种协议
(1)功勋元老xmpp协议:
其实xmpp协议在手机早期发展阶段用的还是比较多的,在Android 2.X时代我们就曾经使用过这种协议,在实现xmpp协议的服务器框架中,最著名的当属Openfire,我们只需要下载Openfire的安装包并安装部署到我们的Linux主机,并做简单的配置就可以使用了,但是这种协议其实已经不在适合今天的互联网世界,其xml格式的报文相对冗余,且没有对消息传输质量等方面做详细的规定,现在已经很少使用。
(2)互联网与物联网行业的新星:mqtt协议
由于xmpp协议有各种不足,IBM公司推出的mqtt协议在近些年越来越受欢迎,这种协议使用二进制流进行传输,内容冗余非常少,而且mqtt协议不仅仅规定了报文格式,还对消息质量、消息持久化等方面做了详细规定,而且支持服务器的桥接,对于多台服务器联合部署也比较方便,特别适合今天做为IM即时聊天的解决方案,因此,我们推荐使用mqtt协议来实现我们的推送方案。
五、mqtt协议简介
其实不论是xmpp协议还是mqtt协议,都是基于tcp协议封装的应用层协议,在访问时都是能过tcp://的格式来连接服务器。
Mqtt协议基于发布/订阅模式来构建,实现了消息发送端和接收端的解耦,我们可以使用这种模式来构建点对点的聊天,也可以轻松构建一个群聊,发送端发布一个话题(topic),接收端订阅(subscribe)这个topic即可,并且mqtt协议提供了消息质量的支持,当QoS的等级为2时,发送端和接收端可以通过多次握手的方式实现消息有且仅一次送达,即使是接收端离线也可以实现离线消息的正确接收,我们可以配置服务器将离线消息缓存到内存或者数据库中,这些内容在mqtt协议中都做了明确规定。
在传输安全方式,mqtt协议也明确规定了SSL/TLS的传输方式,如果有安全传输的需求也可以满足。
在数据持久化方面,mqtt协议明确规定了消息可存放于内存或数据库中,并且开放给开发人员自由选择。
第二部分:实战
一、基于mqtt协议的Apollo服务器和mosquitto服务器的安装与配置
近年来关于mqtt的相关文档也越来越丰富,针对mqtt的服务器组件也越来越多,比较著名的有Apache基金组织的ActiveMQ Apollo和eclipse公司推出的mosquitto,拿mosquitto来说,我们只需要到http://mosquitto.org下载相应的安装包,并安装到我们的Linux主机就可以搭建一台基于mqtt协议的推送服务器,关于如何安装部署mosquitto服务器,网上有大量的文章可供参考,apollo服务器的下载安装也有很多文章介绍,大家可以自行百度,这里可以推荐两篇文章:
Mosquitto的下载及安装:
http://blog.csdn.net/xukai871105/article/details/39252653
Apollo的下载及安装:
http://blog.csdn.net/qq_29196551/article/details/51488340
二、开发API的选择
其实经过前边选择协议并安装服务器,我们的推送服务已经算是搭建好了,至于如何访问这个mqtt服务器是客户端要做的事情了,只要我们按照mqtt规定的方式连接推送服务器就可以了,但是由于mqtt协议规定的细节相对比较多,如果我们硬编码的话工作量还是比较大的,好在已经有人为我们封装过这些API了,这里推荐使用eclipse公司的paho,官网地址是http://www.eclipse.org/paho/,paho提供了多种语言的实现,包括Java、Android、Python、JavaScript、.Net(C#)、C/C++等实现,如果使用PHP语言也可以参考tokudu-PhpMQTTClient,如果考虑到兼容苹果手机,可以参考这篇文章:
《MQTT 协议(三):实战篇》
这篇文章介绍了用 Objective-C 封装的 MQTT 框架:MQTT-Client-Framework的使用,这样我们就可以使用一台推送服务器兼容Android和IOS两大平台了,我猜苹果的这套框架底层应该也是通过苹果的APNs来连接的。
Paho的官网也给出了各种实现方式的样例,比如Java的Demo在Github中的网址为:
https://github.com/eclipse/paho.mqtt.java
而Android的代码样例为:
https://github.com/eclipse/paho.mqtt.android
在Android的样例中,eclipse公司还给出了一个现成的mqtt服务器地址:
tcp://iot.eclipse.org:1883
如果想先看看效果,暂时没空搭建mqtt服务器的话,可以使用这个服务器来做一些演示。
三、容易混淆的概念:服务器、客户端
之前查询了很多有关搭建推送服务器的资料,发现很多朋友都忽略了几个最最基本的概念,什么叫服务器?什么叫客户端?所以我认为有必要在文章的最后对这个概念进行一些说明。
其实在传统的手机APP开发当中,我们一般把手机称作客户端,把给手机提供http接口的后端称作服务器,服务器可以由基于SpringMVC的Java来构建,也可以由PHP、Python等语言构建。
但是在推送服务器的领域,我认为有必要澄清一下“服务器”的概念,在这个领域里,只有一个东西可以被称为服务器,就是负责推送的那台“推送服务器”,除此之外其它所有的设备在它看来都是客户端,理论上讲,我们只需要搭建一个mosquitto或Apollo服务器,再用几台手机通过mqtt协议连接到这台服务器就可以实现即时聊天了,而我们所谓的Java服务器后台、PHP服务器后台则完全可以不要。
而如果我们需要通过我们自己的服务器管理后台给手机用户推送消息时,我们就可以在我们Java服务端代码中引入paho API(假设我们的服务端用Java EE来实现),这时我们的tomcat服务器也就可以连接mqtt服务器了,而对于mqtt服务器来说,这个tomcat服务器跟Android手机是一样的,它只是一个普通的客户端,mqtt服务器甚至不知道连接它的是一台手机还是一台部署了tomcat的Linux主机,mqtt服务器只知道有一台设备请求发布消息,那么就把这条消息推送给订阅了这一主题的设备,仅此而已,mqtt服务器、管理后台服务器和终端的关系如下图所示: