在我的认识里,打开网页或app去查询或者刷新时,客户端向服务器发出请求然后返回数据。 而服务端主动推送到客户端是怎么一个过程呢?
(特别不明白应用服务器如何确定每一个应用所在的设备,服务端把消息推到哪?客户端又不像服务器有一个固定的地址)
各位大神的意思是:现在的app,仍然是以客户端主动向服务端请求为主? 类似中国移动给全网信号内所有手机发消息这种不存在?
我这问题很多余么
19 个回答
这种机制非常浪费运营商的资源,也非常费电。
所以,建议把所有的应用设置都看清楚,尽量选择非推送。尤其是天气预报,手工查一下就行了,否则,那个所谓的墨迹天气,5分钟查一次,频率比得上微信了。完全没有必要,太费电了。要是赶上小区拥堵的情况,频繁的PDP激活,建立RRC连接,再释放,电池消耗特别大。而且还会发热,用户体验会很糟糕。
@Hugo 的答案更是只是传统的拉取消息模式(Pull),不能算是推送(Push)。
总结下题主的问题:
- 服务端主动推送到客户端是怎么一个过程呢
- 应用服务器如何确定每一个应用所在的设备
- 服务端把消息推到哪,客户端又不像服务器有一个固定的地址
- 现在的APP是如何使用消息推送的。
服务端主动推送到客户端是怎么一个过程
目前服务端给客户端推送,普遍做法是客户端与服务端维持一个长连接,客户端定时向服务端发送心跳以维持这个长连接。当有新消息过来的时候,服务端查出该消息对应的TCP Channel的ID并找到对应的通道进行消息下发。
这只是最基本的通讯模型,在此之上,有衍生出针对消息的发布/订阅模型,客户端可以订阅某一个Topic,服务端根据Topic找到对应的Channel进行批量的消息下发。所有的客户端隐式的订阅的all这个opic,所以『类似中国移动给全网信号内所有手机发消息的模式』亦可以理解『广播消息』,即给all这个Topic发消息。
在此基础上,又要几个开源的协议来帮你定义这个事情,比较有名的如MQTT协议(刚好这几天我看到MQTT协议的中文翻译,分享给大家),Github上搜索MQTT可以找到对应的开源的协议实现项目,有兴趣可以自行搜索。
现在的APP是如何使用消息推送的
实际上,主流的移动平台都已经有系统级的推送产品,Android上有GCM,iOS上有APNS,WinPhone有MPNS。但因为某些你懂的原因,GCM在国内处于不可用状态,所以国内的移动应用采用另外一种做法---在后台运行一个Service,维持应用于服务端的TCP长连接,以达到实时消息送达的效果。
但是在移动端如何稳定的维持长连接是一件非常复杂的事情,前面说了,客户端通过定时发送心跳信号(Heartbeat)以维持与服务端的长连接,但是,如果心跳的频率太频繁,移动设备耗电增加,心跳间隔太久又可能使得连接被断开。并且普遍认为移动设备处于一个多变的网络环境中,WIFI,2G,4G切换,基站切换都会引起网络变动,在不同网络环境下的心跳频率,与网络变动的重连动作,都需要大量的数据统计分析总结出来。
这仅仅是客户端的难题,在如今移动应用动辄成百上千的用户量的情况下,如何维护如此多的长连接,如果应对大规模的消息下发以及后续针对下发消息的各种统计动作都是技术难点。
再者,现在应用一般都是全平台的,发送一条消息,应该同时发送给Android,iOS, WinPhone,Android端走自建的TCP长连接通道,iOS与WinPhone走自家的系统推送通道。那么意味着你服务端要维护这三套推送系统。
显然对于小团队,要独自建立一套消息推送系统的难度非常大,所以市场上涌现出很多优秀的推送产品,帮开发者聚合这些推送方式,并提供统一的推送接口。国外如 Urban Airship, Parse等, 国内有JPush,百度云推送,信鸽,LeanCloud等。(比较遗憾的是,非常优秀的Parse已经被Facebook宣布停止开发,并将于1年后关闭)
现在除了体量非常大的公司自建推送系统外,一般普通公司都是使用第三方推送服务,以上所有的第三方推送服务,基础功能都是免费的,如果有条件的话,建议可以集成多家服务,A/B测试对比下推送效果,本人从事与以上某推送公司,在此就不评价各家产品好坏了,关于推送相关的问题可以私信问我 :)
Other
如果感(dian)兴(zan)趣的人多的话,我可以分享下推送方面的相关案例。
Android 上有 GCM (Google Cloud Messaging)
iOS 上有 APNs(Apple Push Notification service)
Windows Phone 上有 MPNs(Microsoft Push Notification service)。
但是由于Windows Phone的市场占比不高,所以一般也就没有人会专门做wp系统的推送。至于Android的GCM在国内基本上是不可用的。原因主要有以下两点:
一、国内大部分Android手机都不带Google服务,也就用不了GCM,这是主要的问题。
二、在国内Google的服务一般都不太稳定,原因你懂的。
所以现在在做消息推送的时候Android平台采用服务器与设备直接拉一条长连接的方式实现功能,而IOS平台则采用苹果自己的APNs服务。在分别说这两个平台推送原理的时候,先回答一下题主关于服务器如何先找到设备、再找到app的问题。每一个设备都有一个自己的设备号,而设备中的app又都有一个唯一的包名。所以服务器只需要找到设备号与包名就可以定位到某个设备的某个应用,而这设备号与包名会一起构成一个标识符,叫做device_token,因此问题就简化为把device_token与消息内容等信息交给服务器,服务器把内容发到唯一的device_token上。这就好像你在上海要通过顺丰寄送一个快件儿给某某小区的某某房间,那么快件儿首先会邮递到顺丰公司在北京的总站点,之后再根据小区的地址投递/路由到某某房间,这样一个寄件过程就算完成了。在这里,你要寄送的快件儿就是你要发的“消息”,送达房间相当于最终“接收消息的App”,顺丰公司在北京的总站点相当于这里提到的“设备”,送达房间的房间号就相当于这个环节里面提到的“包名”。
接下来分别简单说一下这两个平台的推送实现原理。
首先是IOS平台,IOS的推送是通过苹果自己的APNs服务进行的,用户需要将device_token以及消息内容等推送信息交给APNs服务器,剩下的均由苹果自己来完成。详细方法可以看我在知乎的另一个回答 iOS 的 push 推送是如何实现的? - 李琰的回答,但是如果提供的device_token是失效的(app被卸载、系统版本升级导致device_token变化等情况)那么推送过程就会被中断,频繁的断线重连甚至会被APNs认为是一直DoS攻击。详情可以参考 为什么苹果的推送,两次推送之间间隔比较久的话,第二次推送会很慢? - 沙漠的回答
接下来是Android平台,Android平台在不使用GCM的情况下就需要将自己的服务器或是第三方推送服务提供商的服务器与设备建立一条长连接,通过长连接进行推送。但是不建议自己设置服务器实现推送功能,一是因为成本太高(开发成本、维护成本),自己搭建的服务器无论是稳定性还是速度上都比不了第三方推送服务提供商的效果。另一个是因为自己的数据量较小,使用第三方推送服务提供商可以用他们的维度进行推送,实现精准推送。友盟推送就是做的比较好的,可以根据用户分群、地区、语言等多维度进行推送,最大程度减少对于用户的干扰,仅把消息推送给相关用户。 友盟推送的优势是什么? - 李琰的回答
下图是Android平台消息推送的简单示意图。

开发者通过第三方推送服务提供商将信息直接下发给需要的设备,第三方推送服务提供商与设备建立一条长连接通道,并且将消息路由到APP中(图中的设备1与设备2),对于像设备3这种无网络连接或是没有成功建立长连接通道的设备,会在设备3连网且推送消息没有过期的情况下自动收到由第三方推送服务提供商推送过来的消息,保证消息不会丢失。
客户端隔几分钟请求,服务器下发消息。
问题一:没运行怎么请求?
答:服务(非前台)在请求。你可以理解成偷偷在请求。
问题二:怎么知道是哪个客户端?
答:请求时候带上身份…
微信是前台的时候频率高一点,后台的时候频率低一点。
前台后台你可以理解成看得见的时候和看不见的时候。
——————
手机:你有新消息吗?
服务器:没有
3分钟后~
手机:你有新消息吗?
服务器:没有!
3分钟后~
手机:你有新消息吗?
服务器:没有!!
3分钟后~
手机:你有新消息吗?
服务器:有!KK吸毒了!
手机:哦~
3分钟后~
手机:你有新消息吗?
服务器:有!FF吸毒了!
手机:哦~
3分钟后~
手机:你有新消息吗?
服务器:没有
不过在web2。0炒得火热的时期,流行了一段时间的 真正意义上的服务器短连接 推技术
说来简单,在服务器response 流关闭的时候,这个http连接就算over了
服务器干啥呢,就是写个死循环,让这个流一直不结束,也就是说永远不告诉客户端,大爷我给你发完了。
然后服务器就可以有事没事调戏客户端了。当然浏览器上还是需要加些代码设置
以前的网络聊天室据说就是这么干的
从成本来说,客户端轮询请求 服务器压力最小,但是不太敏感
tcp长连接呢,服务器压力大些,但是消息及时
这种老式的方案,属于折中方案,但是挺扯淡的,需求不是特别符合还是别用了。
- 基于 AJAX 的长轮询(long-polling)方式,服务器Hold一段时间后再返回信息;
- HTTP Streaming,通过iframe和<script>标签完成数据的传输;
- TCP 长连接
- HTML5新引入的WebSocket,可以实现服务器主动发送数据至网页端,它和HTTP一样,是一个基于HTTP的应用层协议,跑的是TCP,所以本质上还是个长连接,双向通信,意味着服务器端和客户端可以同时发送并响应请求,而不再像HTTP的请求和响应
上述的1和2统称为comet技术,这里有个简单的介绍: Comet:基于 HTTP 长连接的“服务器推”技术
前些日子给项目网站加了后台通知的实时推送到前端显示,用的是nodejs的 http://socket.io,它是websocket的一个开源实现,对不支持websocket的浏览器降级成comet / ajax 轮询, http://socket.io的良好封装使代码编写非常容易。
或者直接用第三方的push notification服务。原理类似,只不过平台统一keep alive省电。需要注册在服务提供方注册。
Push 的工作机制可以简单的概括为下图

图中,Provider是指某个iPhone软件的Push服务器,这篇文章我将使用.net作为Provider。
APNS 是Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。
上图可以分为三个阶段。
第一阶段:.net应用程序把要发送的消息、目的iPhone的标识打包,发给APNS。
第二阶段:APNS在自身的已注册Push服务的iPhone列表中,查找有相应标识的iPhone,并把消息发到iPhone。
第三阶段:iPhone把发来的消息传递给相应的应用程序, 并且按照设定弹出Push通知。
原文: http://blog.youkuaiyun.com/zhuqilin0/article/details/6527113
现在http2也开始有server pushing了,不过还是需要客户端先request。
1. 顾客到窗口问:菜好了没?
2. 窗口小二叫道:25桌,你要的包子的炒肝!
3. 服务员轻轻地站在你的身边:先生,你要的法式面包卷牛肉丸。
4. DU~,DIDAR,喂,请问XXX在吗?好的,你的快递!
嗯。暂时这么多。
而在Android上,跟APNS对应的服务GCM,在国内无法使用。而各个手机厂商(如小米)自己的推送服务又无法覆盖所有手机终端。所以,在Android上实现推送只能自己启动Service维持一个长连接。正是因为安卓上很多应用都有后台长连接挂着,所以安卓手机更费流量,也更费电。
==================================
用手机打了上面两段,实在太累了。找到台电脑,更新一下。
题主真正想问的可能是原理性的东西,而非工程性的。下面先正面回答一下题主的两个问题:
应用服务器如何确定每一个应用所在的设备,服务端把消息推到哪?客户端又不像服务器有一个固定的地址
--客户端确实不一定有固定IP地址,但如果客户端有长连接(TCP)连接到服务器,那么服务器就知道当前处于连接状态的所有TCP连接的客户端地址。从编程的角度来讲,服务器维护了所有连接着的客户端socket,只要往客户端socket里写数据,就能到达客户端;从TCP原理来讲,服务器维护了每个TCP连接的发送窗口,这里的关键是,服务器知道发给每个客户端的TCP包应该是什么序号(seq),而处于连接状态的客户端也时刻准备着在自己的接收窗口里面接收正确序号的TCP包。
现在的app,仍然是以客户端主动向服务端请求为主?
--是的,主要以客户端主动向服务端请求为主。但涉及到IM、实时对战游戏之类的应用场景,就一定需要长连接推送。像天气类,新闻类 app,对推送实时性要求并不太高,采取定期拉取策略也是可以的(实际上实现难度要降低几个数量级)。
另外,关于实现长连接推送需要考虑的一些工程性的问题,把想到的列出如下,有机会再深入探讨。
(1)采用什么协议?XMPP还是MQTT还是自定义二进制协议?是否像微信一样,需要推送二进制数据(比如短语音和缩略图数据)?
(2)如何保证后台长连接不死?像大公司的各个App,普通会采用互拉的手段保持后台运行。而最牛的还是微信,在各个手机系统上基本都算是“开挂”了。
(3)如何做才能真正不丢数据?涉及到系统的方方面面,比如消息的确认,客户端和服务器的数据同步,客户端的数据存储的事务保证,后台消息队列如何设计保证不丢数据。如果是IM,离线数据如何处理?
(4)长连接的Keep Alive和连接状态的检测。比如XMPP相当于一个永远解析不完的XML流,使用一个空格作为Keep Alive消息。
(5)在iOS上进行伪推送。前面已经提到过。还有如何利用iOS特性,用特殊APNS推送唤起App预先下载消息。
(6)长连接的安全性。验证以及加密。
(7)是用各种云推送还是自己实现?用哪家云推送更好?
ps:今天下班买的肉夹馍是猪脚馅儿的,原来这世上还有那么难吃的肉夹馍