作者:你问什么只为她停留_538 | 来源:互联网 | 2023-08-20 16:37
我们的手机app经常主动给我们推送消息,比如更新通知,热点事件,微信的来信提醒。在日常应用司空见惯的功能是如何实现的呢? 上图中浏览器和服务器建立的是TCP请求,TCP
我们的手机app经常主动给我们推送消息,比如更新通知,热点事件,微信的来信提醒。在日常应用司空见惯的功能是如何实现的呢?
上图中浏览器和服务器建立的是TCP请求,TCP是全双工协议,所以建立请求之后双方可以任意交换数据,但是我们的消息推送是由服务器主动推送消息到客户端,看起来好像也是建立了tcp连接,实际上这里需要注意一个方向的问题,http请求的发起方一定是浏览器,而不是我们的web服务器,可能很多人会思考,那如果浏览器建立连接后不断开那不是可以实现服务器推送消息吗?这样肯定是不可行的,如果每个连接都保持不断,那么很快web服务的线程就会耗尽。
那么我们继续思考,有这样一种方案:假如让客户端每隔一段时间就向服务器询问—有新的消息吗?轮询制可以实现,但是耗费客户端的线程,这种方式仅仅试用于消息是定时更新:比如炒股软件,每15分钟更新一次;比如心跳机制,每隔5秒检测服务端是否还存活;
第二种方案:建立Http长轮询,比如基于Ajax请求(Http)就有区分短连接和长连接,由浏览器建立连接后,采用轮询机制加上间隔时间(setInterval)就可以实现定时向浏览器发送请求,如果有新的消息,就会立即发给客户端,这样似乎也是可以解决浏览器给服务器发送消息的(假推送);而事实上很多网页版的即时通讯也确实采用的是这种方式:如网页版微信、QQ,网页版的FaceBook IM;但这个还是开头提到的问题,对服务器的要求很高,后台需要对服务器的运行进行维护。
介绍下Http协议的细节:
1、Http的长链接实质是建立在TCP协议上的长连接与短连接;
2、每个http连接建立后,通信结束并不会立马断开,从http 1.1开始,默认使用长连接,在请求头中会有这样的参数Connection:keep-alive 表示就是长连接
3、keep-alive不会永久保持,在不同的服务器软件中时间不一样,如apcahe的tomcat,Nginx;Nginx的默认连接保持时间是75s,实现长连接要客户端和服务端都支持长连接
4、http连接在传输层使用的Tcp协议,在网络层使用ip协议,可以保证顺序和可靠的连接特性(假如连接过程中发生丢包,服务器会重发)
第三种方案:现在Html5推出了websocket,websocket建立的不是Http的TCP/IP连接(IP+port形式),而是类似 http连接形式以ws://
或wss://
开头的有状态协议(刚好跟http的无状态相反),意思建立连接的客户端和服务器之间保持活跃状态,并可以相互通信,直到有一方主动停止;
插播一段websocket的使用场景:
1、即时web应用程序:比如交易网站中实时更新的价格信息,就可以使用websocket连续推送到客户端;
2、游戏应用中需要实时刷新客户的游戏状态和数据;
3、聊天应用中建立一对一的实时消息传输;
websocket虽然是有状态的协议连接,但是依然需要客户端先主动向服务端建立连接,一旦客户端发生了关机重启,比如微博,如果你没有打开微博,服务端也就没法推送新的消息;回想下12年智能手机刚刚兴起时,如果你同时打开多个移动app在后台运行,此时手机会变得奇卡无比;原因就在于很多应用app都在后台保持着一个用于消息推送的websoket连接,这种应用数量少时看起来没啥影响,但是数量一多,对手机的耗电和流量影响非常大;
现如今移动应用发展迅速,基本很少采用上述需要长连接的技术来实现服务端向客户端推送消息了,而是采用一种 “邮箱模式”;好比在移动app的门口安装一个邮箱,服务器通过“”“邮局”将信件塞到邮箱中;比如google就为Android应用提供一种google订阅服务,移动app只要通过api订阅google的邮箱服务,而服务器只需要将消息推送到google的云端,由google将消息通过订阅服务传递给app,google就充当了邮局和邮递员的角色,这种技术确实解决了app端耗电耗流量的问题,但是我们设想下,移动设备不只有Android系统呀,还有IOS设备,所以需要为两个操作系统开发两套订阅服务的代码,这也是此前很多公司app的通行做法;
以上的情况还仅试用于国外可以访问google和apple服务的情况,国内由于防火墙的原因,app厂商们是没法接入这两家公司的订阅服务的;于是国内的各大手机厂商,如小米,华为等手机厂商需要针对自己的手机应用开发订阅服务,而app厂商就需要为每个手机厂商定制一个订阅的系统,这很显然是不现实的;
如今国内比较流行的做法是在更高层面上做消息推送,你只需要订阅他们提供的接口,他们就能为你实现向Android ios不同的应用设备,或者是浏览器网页应用进行消息推送,比如极光推送,Baidu推送;
说到这里,我想回归到我们最初提出的问题,仅仅是因为服务器无法连接客户端而产生的推送问题,就需要各种客户端订阅服务以及各种编码实现,这似乎给我们开发系统变得异常复杂,唯一的原因就是服务端无法定位到一个唯一的客户端ip,意味着每台移动或者计算设备是没法在网络上仅仅通过一个ip就能够定位出来,这实际跟目前ip协议有关,IPV4协议由于容量的限制2^48个,所以现有的ipv4网络需要划分为公网和局域网,在公网(互联网)通过路由器ip地址来进行每个局域网位置的定位,具有唯一性,而对于每一个不同的局域网而言,内部ip可以相同,通过APR协议随机发送给其中一个,局域网之间的内部计算机ip也是可以相同的,所以没法实现单个计算机的定位,来进行服务端消息的推送,如果到时ipv6得到普及,到时每一个地球上的计算设备都能分配到唯一一个ip地址,到时上面的这种邮局模式就可以退出历史舞台,真正实现服务端和客户端随意通信的效果了。
写这篇博客参考了微软大佬Anduin Xue在youtube上的视频,有兴趣可以关注他
IT的开放给了每一位从业者一个充分获取的学习环境,希望各位看到这篇博客的小伙伴,一起加油!