Android推送技术研究

前言

近期研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 须要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 仅仅能说说自己的理解.

为什么要研究Android推送技术?

主要还是毕业设计要做一个即时通信app, 我是不喜欢做什么社交app的, 也就象牙塔里的人想得出来, 说实话有这功夫还不如钻研一个小技术点, 把一个点研究透彻, 比搞个大而全, 还没用的东西好得多, 只是谁叫咱们是普通人, 没得选呢.

Android推送服务的几种实现方式

现实生活中, 推送服务就像订杂志一样, 仅仅要留下你的地址, 杂志就能如期送到你手里, 能够觉得每一个人都有唯一的一个地址, 但在眼下的网络上, 这是办不到的, 由于不是每一个人都有一个唯一的地址, server想要给我们推送一条消息, 必须知道我们的地址, 但server不知道我们在哪.

说到推送服务, 我所知道的实现方案有例如以下几种:

轮询

client定期询问server有没有新的消息, 这样server不用管client的地址是什么, client来问, 直接告诉它即可.

这样的方案最简单, 对于一些不追求实时性的client来说, 非常适合, 仅仅须要把时间间隔设定成几个小时取一次, 就能非常方便的解决这个问题.

但对于即时通讯产品来说, 这样的方案全然不能用. 假设即时通讯软件在网络畅通的情况下发送的消息要求对方10s内就能收到, 假设用轮询, 那么client要每隔5s连一次server, 假设在移动端, 手机的电量和流量非常快就会被消耗殆尽.

SMS通知

这样的方案在移动端是有可能的, 让client拦截手机短信, server在有新消息时给用户的手机号发一条特殊的短信, client拦截短信后发现是正常短信就放行, 假设是特殊短信就连接server取消息.

运营商不会配合, 用户也不会放心, 这方案普通公司玩不起.

长连接

这大概是眼下情况下最佳的方案了, client主动和server建立TCP长连接之后, client定期向server发送心跳包, 有消息的时候, server直接通过这个已经建立好的TCP连接通知client.

XMPP, MQTT等不算推送技术

在网上搜索资料的时候, 常常看见XMPP协议实现的Android推送和MQTT协议实现的Android推送, 我个人觉得这两种说法都怪怪的, XMPP和MQTT二者都是协议, 虽然我不清楚严格来讲这俩协议工作在哪一层, 可是绝对是在传输层之上的, 姑且觉得他俩在TCP/IP五层模型的应用层吧, 闭口不提传输层的实现, 而是扯应用层, 这样的说法真是令我费解, 所以我个人觉得XMPP, MQTT等等不算推送技术.

关于这个XMPP, 我想非常多人都是參考Openfire和Smack那套东西, 我一年前尝试用aSmack和Openfire做IM, 只是那个时候什么都不懂, 做的东西非常烂, 唯一懂的就是Openfire这东西相当老了, 我看有一些开源的推送解决方式都是在这套东西的基础上改的, 想想这工作量, 挺可怕的.

细说TCP长连接与心跳

长连接方案乍一听怪怪的, 什么是长连接? 定时发送心跳, 这和轮询有什么差别?

心跳是干什么的? 相同是定期和server沟通, 为什么长连接就比轮询更加优秀? 手机休眠了TCP连接不会断掉吗?

这是我在刚開始研究推送技术的时候的问题, 尽管有些还是没有非常准确的答案, 但了解的大概能够分享一下, 有什么错误欢迎指出.

什么是长连接

先说短连接, 短连接是通讯两方有数据交互时就建立一个连接, 数据发送完毕后。则断开此连接.

persistent connection

长连接就是大家建立连接之后, 不主动断开. 两方互相发送数据, 发完了也不主动断开连接, 之后有须要发送的数据就继续通过这个连接发送.

TCP连接在默认的情况下就是所谓的长连接, 也就是说连接两方都不主动关闭连接, 这个连接就应该一直存在.

可是网络中的情况是复杂的, 这个连接可能会被切断. 比方client到server的链路由于故障断了, 或者server宕机了, 或者是你家网线被人剪了, 这些都是一些莫名其妙的导致连接被切断的因素, 还有几种比較特殊的:

NAT超时

由于IPv4地址不足, 或者我们想通过无线路由器上网, 我们的设备可能会处在一个NAT设备的后面, 生活中最常见的NAT设备是家用路由器.

NAT设备会在IP封包通过设备时改动源/目的IP地址. 对于家用路由器来说, 使用的是网络地址port转换(NAPT), 它不仅改IP, 还改动TCP和UDP协议的port号, 这样就能让内网中的设备共用同一个外网IP. 举个样例, NAPT维护一个类似下表的NAT表

内网地址 外网地址
192.168.0.2:5566 120.132.92.21:9200
192.168.0.3:7788 120.132.92.21:9201
192.168.0.3:8888 120.132.92.21:9202

NAT设备会依据NAT表对出去和进来的数据做改动, 比方将192.168.0.3:8888发出去的封包改成120.132.92.21:9202, 外部就觉得他们是在和120.132.92.21:9202通信. 同一时候NAT设备会将120.132.92.21:9202收到的封包的IP和port改成192.168.0.3:8888, 再发给内网的主机, 这样内部和外部就能双向通信了, 但假设当中192.168.0.3:8888 == 120.132.92.21:9202这一映射由于某些原因被NAT设备淘汰了, 那么外部设备就无法直接与192.168.0.3:8888通信了.

我们的设备常常是处在NAT设备的后面, 比方在大学里的校园网, 查一下自己分配到的IP, 事实上是内网IP, 表明我们在NAT设备后面, 假设我们在寝室再接个路由器, 那么我们发出的数据包会多经过一次NAT.

国内移动无线网络运营商在链路上一段时间内没有数据通讯后, 会淘汰NAT表中的相应项, 造成链路中断.

网络状态切换

手机网络和WIFI网络切换, 网络断开和连上等情况, 也会使长连接断开. 这里原因可能比較多, 但结果无非就是IP变了, 或者被系统通知连接断了.

DHCP的租期

眼下測试发现安卓系统对DHCP的处理有Bug, DHCP租期到了不会主动续约而且会继续使用过期IP, 这个问题会造成TCP长连接偶然的断连.

引自Android微信智能心跳方案

心跳包的作用

网上非常多文章介绍长连接的时候都说:

由于是长连接, 所以须要定期发送心跳包.

心跳包是用来通知serverclient当前状态.

提出这些说法的人事实上自己也是一知半解. 这些说法事实上都对, 可是没有答到点上. 就好像别人问: "你为什么要去食堂"?

这人回答: "检查自己还能不能找到食堂". 这个答案说不上错了, 可是事实上这人是去食堂吃饭的, 证明自己认得路仅仅是个附赠品.

明白一点, TCP长连接本质上不须要心跳包来维持, 大家能够试一试, 让两台电脑连上同一个wifi, 然后让当中一台做server, 还有一台用一个普通的没有设置KeepAlive的Socket连上server, 仅仅要两台电脑别断网, 路由器也别断电, DHCP正常续租, 就这么放着, 过几个小时再用当中一台电脑通过之前建立的TCP连接给还有一台发消息, 还有一台肯定能收到.

那为什么要有心跳包呢?

事实上主要是为了防止上面提到的NAT超时, 既然一些NAT设备推断是否淘汰NAT映射的根据是一定时间没有数据, 那么client就主动发一个数据.

当然, 假设不过为了防止NAT超时, 能够让server来发送心跳包给client, 不过这样做有个弊病就是, 万一连接断了, server就再也联系不上client了. 所以心跳包必须由client发送, client发现连接断了, 还能够尝试重连server.

所以心跳包的主要作用是防止NAT超时, 其次是探測连接是否断开.

链路断开, 没有写操作的TCP连接是感知不到的, 除非这个时候发送数据给server, 造成写超时, 否则TCP连接不会知道断开了. 主动kill掉一方的进程, 还有一方会关闭TCP连接, 是系统代进程给server发的FIN. TCP连接就是这样, 仅仅有明白的收到对方发来的关闭连接的消息(收到RST也会关闭, 大家都懂), 或者自己意识到发生了写超时, 否则它觉得连接还存在.

心跳包的时间间隔

既然心跳包的主要作用是防止NAT超时, 那么这个间隔就大有文章了.

发送心跳包势必要先唤醒设备, 然后才干发送, 假设唤醒设备过于频繁, 或者直接导致设备无法休眠, 会大量消耗电量, 并且移动网络下进行网络通信, 比在wifi下耗电得多. 所以这个心跳包的时间间隔应该尽量的长, 最理想的情况就是根本没有NAT超时, 比方刚才我说的两台在同一个wifi下的电脑, 全然不须要心跳包. 这也就是网上常说的长连接, 慢心跳.

现实是残酷的, 依据网上的一些说法, 中移动2/3G下, NAT超时时间为5分钟, 中国电信3G则大于28分钟, 理想的情况下, client应当以略小于NAT超时时间的间隔来发送心跳包.

wifi下, NAT超时时间都会比較长, 据说宽带的网关一般没有空暇释放机制, GCM有些时候在wifi下的心跳比在移动网络下的心跳要快, 可能是由于wifi下联网通信耗费的电量比移动网络下小.

关于怎样让心跳间隔逼近NAT超时的间隔, 同一时候自己主动适应NAT超时间隔的变化, 能够參看

__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5ab58810ac8bc5994&scene=4#wechat_redirect">Android微信智能心跳方案.

心跳包和轮询的差别

心跳包和轮询看起来类似, 都是client主动联系server, 可是差别非常大.

  • 轮询是为了获取数据, 而心跳是为了保活TCP连接.
  • 轮询得越频繁, 获取数据就越及时, 心跳的频繁与否和数据是否及时没有直接关系
  • 轮询比心跳能耗更高, 由于一次轮询须要经过TCP三次握手, 四次挥手, 单次心跳不须要建立和拆除TCP连接.

TCP唤醒Android

这部分内容我仅仅知道结论, 不知道详细的知识

大家有没有想过, 手机的短信功能和微信的功能差点儿相同, 为什么微信会比短信耗电这么多? 当然不是由于短信一条0.1元. 手机短信是通过什么获取推送的呢?

以下这段出处不明的话或许能够给大家启发

首先Android手机有两个处理器, 一个叫Application Processor(AP), 一个叫Baseband Processor(BP). AP是ARM架构的处理器,用于执行Android系统; BP用于执行实时操作系统(RTOS), 通讯协议栈执行于BP的RTOS之上. 非通话时间, BP的能耗基本上在5mA左右,而AP仅仅要处于非休眠状态, 能耗至少在50mA以上, 执行图形运算时会更高. 另外LCD工作时功耗在100mA左右, WIFI也在100mA左右. 一般手机待机时, AP, LCD,
WIFI均进入休眠状态, 这时Android中应用程序的代码也会停止运行.

Android为了确保应用程序中关键代码的正确运行, 提供了Wake Lock的API, 使得应用程序有权限通过代码阻止AP进入休眠状态. 但假设不领会Android设计者的意图而滥用Wake Lock API, 为了自身程序在后台的正常工作而长时间阻止AP进入休眠状态, 就会成为待机电池杀手.

全然不是必需操心AP休眠会导致收不到消息推送. 通讯协议栈运行于BP,一旦收到数据包, BP会将AP唤醒, 唤醒的时间足够AP运行代码完毕对收到的数据包的处理过程. 其他的如Connectivity事件触发时AP相同会被唤醒. 那么唯一的问题就是程序怎样运行向server发送心跳包的逻辑. 你显然不能靠AP来做心跳计时. Android提供的Alarm Manager就是来解决问题的. Alarm应该是BP计时(或其他某个带石英钟的芯片。不太确定,但绝对不是AP), 触发时唤醒AP运行程序代码. 那么Wake
Lock API有啥用呢? 比方心跳包从请求到应答, 比方断线重连又一次登陆这些关键逻辑的运行过程, 就须要Wake Lock来保护. 而一旦一个关键逻辑运行成功, 就应该马上释放掉Wake Lock了. 两次心跳请求间隔5到10分钟, 基本不会怎么耗电. 除非网络不稳定. 频繁断线重连, 那种情况办法不多.

上面所说的通信协议, 我猜应该是无线资源控制协议(Radio Resource Control), RRC应该工作在OSI參考模型中的第三层网络层, 而TCP, UDP工作在第四层传输层, 上文说的BP, 应该就是手机中的基带, 也有叫Radio的, 我有点搞不清楚Radio怎么翻译. Google在Optimizing
Downloads for Efficient Network Access
中提到了一个叫Radio State Machine的东西, 我翻译成无线电波状态机, 也不知道正确的翻译是什么.

移动网络下, 每个TCP连接底层都应该是有RRC连接, 而RRC连接会唤醒基带, 基带会唤醒CPU处理TCP数据, 这是我个人的理解.

至于wifi下怎样工作, 我临时没有找到资料.

上面说了这么多, 事实上意思就是TCP数据包能唤醒手机. 至于UDP, 我不确定.

而推送中最重要的部分就是让手机尽量休眠, 仅仅有在server须要它处理数据时才唤醒它, 这正好符合我们的要求.

移动网络下的耗电

Google在Optimizing Downloads for Efficient Network Access中提到了一个叫Radio State Machine的东西.

mobile radio state machine

说的应该就是基带的工作状态, 在Radio Standby下差点儿不耗电, 可是一旦有须要处理的事情, 比方手机里某个app要訪问网络(从上一节能够猜測: 收到RRC指令也会导致唤醒), 就会进入到Radio Full Power中, 由Standby转为Full Power这一唤醒过程非常耗电, Full Power下基带空暇后5s进入Radio Low Power, 假设又空暇12s才进入Standby. 基本的意思就是不要频繁的唤醒基带去请求网络, 由于仅仅要一唤醒, 就至少会让基带在Full Power下工作5s,
在Low Power下工作12s, 并且唤醒过程非常耗电. 所以在移动网络下, 心跳须要尽量的慢才好, 只是以当前这样的情况, 想慢下来差点儿不可能.

只是这也带来另外一个问题, 假如手机里有10个应用, 每一个应用都发送心跳包, 每一个应用的server都可能唤醒手机, 那手机还休不休眠了?

实际实现遇到的问题

了解完了我就開始动手做demo, server使用Apache的Mina, client也用这个

Mina

这个框架挺好用, 就是遇到些非常奇怪的事情, 我两天前看的, 所以也可能是我自己的问题.

一个是Android端发一个汉字给server, serverfilter崩溃, 发超过一个汉字, clientfilter崩溃, 写个IoFilter做一下编解码就好了. 另外User Guide里面的代码也有错误. 第二个是IoSessionConfig的写超时设置了全然不起作用.

小米手机的奇妙Socket

后来又发现client仅仅要在后台超过一定时间, 对socket的写操作就会变得很诡异, 表现为socket把数据吞了, 告知应用数据已经被对方接收, 可是server什么都没收到, 并且server发送的消息client也收不到. 仅仅要让app进到前台, 之前消失的数据会一股脑发给server, client会收到server重传的消息.

我開始还以为是Android的休眠机制把wifi断了, 我把各种WifiLock, WakeLock都持有了, 还是出这样的情况. 后来无意间发现小米针对每一个app都有个后台执行时同意联网的开关, 我把它打开了, 果然好了一阵子, 后来又開始反复之前的情况, 我还以为是Mina的IO线程被kill了还是怎么, 用DDMS看了线程信息没问题. 不放心, 又用纯Socket实现了client, 还是有问题, 再在之前的基础上加上1分钟的心跳, 还是有问题.

小米手机的奇妙bug

这次真是我运气好, 我又看了一眼后台执行时同意联网的开关, 发现demo app的这个开关刚刚还被我打开了, 这下又关上了, 我怀疑是小米的这个功能有bug, 我是记得有小米员工提到这东西有server下发白名单的, 我觉得是server下发数据把我的修改给覆盖了, 我把几个app的后台联网关了, 重新启动手机之后, 他们又开了.

最后我改了个10s的心跳间隔, 在心跳的时候, 把后台同意联网关掉, 复现了那个奇妙的socket行为, 大概确定是MIUI的bug.

睡了一觉起来, MIUI的project师联系了我, 确认是bug. 顺便提醒一下用小米做測试机的开发人员和用户, 这个bug的暂时解决方式是: 用神隐模式里的自己定义配置, 把自己想改的设置好即可.

想起一年前什么都不懂就跑去小米面试就好笑, 我这水平全然就是坑人, 然而没想到这次被小米坑了.

我心中最佳的推送技术

RRC那套东西, 你懂的, 基带Standby模式下也保持着的连接.

參考网址

Understanding the Android “Radio State Machine” for better battery life

__biz=MzAwNDY1ODY2OQ==&mid=207243549&idx=1&sn=4ebe4beb8123f1b5ab58810ac8bc5994&scene=4#wechat_redirect">Android微信智能心跳方案

q=cache:m9nwCZ-0X1IJ:blog.oasisfeng.com/2013/04/14/dirty-secret-behind-weixin-charge-gate/+&cd=1&hl=zh-CN&ct=clnk&gl=cn">微信收费事件背后被广泛忽略的技术细节

android设备休眠

Optimizing Downloads for Efficient Network Access

关于socket长连接的心跳包

Network address translation

C/C++网络编程中的TCP保活

TCP/IP,http,socket,长连接,短连接――小结。

Android实现推送方式解决方式

转自【http://www.jianshu.com/p/584707554ed7】

时间: 2024-08-11 20:14:09

Android推送技术研究的相关文章

Android、iOS和Windows Phone中的推送技术

转自李宁的博客:http://blog.csdn.net/nokiaguy/article/details/11175359 推送并不是什么新技术,这种技术在互联网时代就已经很流行了.只是随着进入移动互联网时代,推送技术显得更加重要.因为在智能手机中,推送从某种程度上,可以取代使用多年的短信,而且与短信相比,还可以向用户展示更多的信息(如图像.表格.声音等). 推送技术的实现通常会使用服务端向客户端推送消息的方式.也就是说客户端通过用户名.Key等ID注册到服务端后,在服务端就可以将消息向所有活

安卓推送技术方案实现探讨

背景介绍 随着苹果产品的风靡,推送技术在国内也越来越热门.推送最开始用于邮件系统.随着iPhone 和 Android 手机的风靡,逐渐在手机上也越来越常见.不少手机客户端也时常推送一些消息. 推送技术的应用 推送技术在手机上的应用主要有两块:广告推送.SNS信息推送. l  广告推送:给目前有一定安装量但没有盈利模式的手机应用开发者带来了一定希望,但要注意推送的频度和内容选中,不然会因为推送的东西用户不感兴趣造成打扰. l  SNS信息推送:主要用于QQ空间.人人网.微博和天涯论坛等web2.

Android推送服务开发

由于公司之前使用的手机客户端推送服务是极光推送,给公司造成一年几十万的服务费,因此,公司决定开发自己的一套推送服务,初步的技术选型是: 服务端:netty4 关于netty框架在我的下面的博客里面我整理了相关资料,本来还有一些关于mina的由于时间原因暂时没整理出来. 为了便于自己测试,自己动手实现了如何使用netty完成服务端消息推送以及在Android客户端如何将接受到的信息显示在通知栏,整体思路大概是这样的: 服务端使用netty框架开启基于TCP监听服务. 客户端发起TCP连接(不关闭,

消息推送技术

消息推送 消息推送是针对 Web 应用开发领域的技术,指服务端以主动方式将信息送达客户端.主要用于提升用户体验,避免用户刷新页面从服务端拉取数据.例如 Web 邮件中自动出现刚收到的邮件项,Web 即时通讯自动提示新到消息等应用场景. 要实现消息推送机制,涉及两方面的内容: Web 层消息推送 服务层消息服务 Web 层消息推送 套接字 可以使用套接字接口进行全双工通讯.可以通过 Flash XMLSocket.Java Applet 技术实现.但由于实现方案与厂商技术绑定过紧,不属于 Web

服务器向Android推送的相关知识和解决方案

在Android中实现推送方式的基础知识及相关解决方案:推送功能在手机开发中应用的场景是越来起来了,不说别的,就我们手机上的新闻客户端就时不j时的推送过来新的消息,很方便的阅读最新的新闻信息.这种推送功能是好的一面,但是也会经常看到很多推送过来的垃圾信息,这就让我们感到厌烦了,关于这个我们就不能多说什么了,毕竟很多商家要做广告.本文就是来探讨下Android中实现推送功能的一些解决方案,也希望能够起到抛砖引玉的作用.^_^ 1.推送方式基础知识: 在移动互联网时代以前的手机,如果有事情发生需要通

网站推送技术总结

转自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/ 需求: 我想做个会员站内通知的功能.不想用以前的ajax查询,听说有个推技术.以下文章介绍的不错,来自转载, ================================================================================== PHP中Push(推送)技术的探讨  [http://vistaswx.com/bl

看了极光推送技术原理的几点思考

看了极光推送技术原理的几点思考 分类: android2012-11-26 20:50 16586人阅读 评论(18) 收藏 举报 目录(?)[+] 移动互联网应用现状 因为手机平台本身.电量.网络流量的限制,移动互联网应用在设计上跟传统 PC 上的应用很大不一样,需要根据手机本身的特点,尽量的节省电量和流量,同时又要尽可能的保证数据能及时到达客户端. 为了解决数据同步的问题,在手机平台上,常用的方法有2种.一种是定时去服务器上查询数据,也叫Polling,还有一种手机跟服务器之间维护一个 TC

魔推MPUSH开发者程凯征:好的消息推送技术是磨出来的

开发一款程序员喜欢用的SDK不容易.也许有些开发者还不知道能够使用方便易用的消息推送平台接口服务.但是像百度.网龙.去哪儿等APP应用都是在使用消息平台接口的服务.魔推MPUSH开发者程凯征以一位标准研发人员的视角,将研发和产品设计之间的关系用"与.或.非"来阐述他对消息推送技术是如何诞生的. 目前,魔推MPUSH已经向应用开发者开放,支持包括安卓.IOS.JAVA.PHP的主流系统.从原理上来说,为应用开发者提供的SDK包嵌入到应用程序当中,就可以实现信息的推送功能.目前,广泛的做法

PHP ServerPush (推送) 技术

用来代替ajax的请求 转自:http://blog.163.com/bailin_li/blog/static/17449017920124811524364/ 需求: 我想做个会员站内通知的功能.不想用以前的ajax查询,听说有个推技术.以下文章介绍的不错,来自转载, ================================================================================== PHP中Push(推送)技术的探讨  [http://vis