背景
移动互联网带来一个结果就是实时性,而消息推送就是实时性的一个重要原因。服务器经常会推送各种消息给终端,比如最新的新闻,微博,评论,等等。可以说,主动消息推送是一个越来越基本的功能了。那么怎么实现呢?
常见的实现方案有如下几种:
1. 轮询方式(PULL)
应用程序周期性的与服务器进行连接并查询是否有新的消息。你必须自己实现和服务器之前的通信,例如消息队列。 主要要考虑轮询的效率,如果太慢可能导致某些消息的延迟。如果太快,则会消耗流量和电池电量。
2. SMS
在Android平台通过拦截SMS消息。这个方案很难找到免费的短消息发送网关,因此成本相对比较高。
3. 持久连接(PUSH)
客户端通过发送心跳包,和服务器维持一个TCP连接。这个方案可以解决轮询的性能问题,但会消耗手机电池。
一般来说手机操作系统会提供相应的推送平台,比如苹果的ApnsPush,谷歌的GCM,微软的WPPush,黑莓的BBPush等)。并且为了节省电量,会有一个系统级别的长连接统一接入到系统推送平台。这样每个终端仅仅保持一个与推送服务器之间的连接。
但是因为一些问题,应用还是要自己维护应用级别的长连接和消息推送:
- 像苹果的ios系统,在app退出到后台10分钟后就会释放掉该app所持有的所有资源(如cpu,网络,内存等),导致之前建立的长连接通道也会一并断掉,此时通过业务长连接进行通知是不可达的,所以还需要依赖与苹果自身的apns通道来达到实时通知。
- Google的GCM由于Google服务器在国外,国内访问会不稳定。大家都懂的。另外,Android操作系统允许在低内存情况下,杀死系统服务,所以通知服务有可能被OS Kill掉。
实现
搭建推送平台有两种路径,
- 基于业界开源的解决方案基础上做二次改造
- androiddpn是韩国人写的一个开源的推送方案。它基于XMPP协议,搭建服务器端和客户端实现。
- 参考推送平台的客户端,服务端交互原理,参考相关资料,设计自己的通信协议和推送方案。
难点
- 性能
- 大量闲置的长连接:NIO
- 推送的成功率
- 消息的丢失: 消息存储和确认或者Seq