背景

移动互联网带来一个结果就是实时性,而消息推送就是实时性的一个重要原因。服务器经常会推送各种消息给终端,比如最新的新闻,微博,评论,等等。可以说,主动消息推送是一个越来越基本的功能了。那么怎么实现呢?

常见的实现方案有如下几种:

1. 轮询方式(PULL)

应用程序周期性的与服务器进行连接并查询是否有新的消息。你必须自己实现和服务器之前的通信,例如消息队列。 主要要考虑轮询的效率,如果太慢可能导致某些消息的延迟。如果太快,则会消耗流量和电池电量。

2. SMS

在Android平台通过拦截SMS消息。这个方案很难找到免费的短消息发送网关,因此成本相对比较高。

3. 持久连接(PUSH)

客户端通过发送心跳包,和服务器维持一个TCP连接。这个方案可以解决轮询的性能问题,但会消耗手机电池。

一般来说手机操作系统会提供相应的推送平台,比如苹果的ApnsPush,谷歌的GCM,微软的WPPush,黑莓的BBPush等)。并且为了节省电量,会有一个系统级别的长连接统一接入到系统推送平台。这样每个终端仅仅保持一个与推送服务器之间的连接。

但是因为一些问题,应用还是要自己维护应用级别的长连接和消息推送:

  1. 像苹果的ios系统,在app退出到后台10分钟后就会释放掉该app所持有的所有资源(如cpu,网络,内存等),导致之前建立的长连接通道也会一并断掉,此时通过业务长连接进行通知是不可达的,所以还需要依赖与苹果自身的apns通道来达到实时通知。
  2. Google的GCM由于Google服务器在国外,国内访问会不稳定。大家都懂的。另外,Android操作系统允许在低内存情况下,杀死系统服务,所以通知服务有可能被OS Kill掉。

实现

搭建推送平台有两种路径,

  1. 基于业界开源的解决方案基础上做二次改造
    • androiddpn是韩国人写的一个开源的推送方案。它基于XMPP协议,搭建服务器端和客户端实现。
  2. 参考推送平台的客户端,服务端交互原理,参考相关资料,设计自己的通信协议和推送方案。

难点

  1. 性能
    • 大量闲置的长连接:NIO
  2. 推送的成功率
    • 消息的丢失: 消息存储和确认或者Seq