目录
引言
现在的移动端开发, 消息推送是一个标配的必备功能, 工作中要开发的产品当然也不能"幸免"
不过或许你会说, 接入第三方不就得了 -- 为开发加速(LeanCloud的广告语, 表示感谢)
...(在此略过100家)
但是有些情况下, 偏偏一不小心就选择了自己去实现这条"不归路", 所以就有了深入研究这件事
即使开发中选用了第三方方案, 但从知识结构和职业发展的角度来看, 研究这件事总是没有错的
消息推送
顾名思义, 消息推送就是上行发送消息到下行, 服务器发送消息给终端
如果是你, 会如何实现服务器发送消息给终端呢?
-
把终端变成服务器, 服务器变成终端, 这样来发送(其实是请求)消息 (脑洞大开的感觉有没有...)
-
终端不断滴去服务器请求, 有消息就取到, 结果和服务器推送消息看起来是一样一样的 (好像还蛮靠谱的...)
-
在终端和服务器之间保持一条一直连接不断开的双向通道 (看起来很完美啊, 就他了...)
第一种方法太"高端"了, 远超本人的能力范围, 所以暂不讨论
第二种方案有两种常见的实现方法
-
ajax轮询 - 终端隔个几秒就发送一次请求, 询问服务器是否有新信息
-
long poll - 又叫阻塞式轮询, 即终端发起连接后, 如果没消息, 服务器就一直不返回Response给终端
缺点也是很明显的
-
ajax轮询 - 消耗服务器的运算处理资源 (速度)
-
long poll - 消耗服务器的并发处理资源 (场地)
第三种方案看起来最完美的, 也是现在消息推送的标准实现, 它有以下几种实现方法
-
Socket
-
WebSocket
-
其他方案(这是什么鬼? 这里泛指除Socket和WebSocket的所有方案)
你确定上面"两个Socket"不是一个东西么?
这里确定, 一定以及肯定的告诉你, 这两者的关系比Java和Javascript的关系还要远(详见下文)
Socket
这里的Socket特指网络编程中的Socket
Socket中文名: 套接字, 它有两个特征
-
它不是协议而是一套APIs
-
它实现的是双向通信
Socket APIs是对TCP/IP协议的封装, 它可以分为面对连接的基于TCP的Socket和应用于无连接的基于UDP的Socket
Socket建立连接的流程大概是这样的
-
服务端利用Socket监听端口
-
客户端发起连接
-
服务端返回信息, 建立连接, 开始通信
-
客户端, 服务端断开连接
Socket与HTTP的区别
HTTP是基于TCP的应用层协议, 而Socket是对TCP/IP进行封装的一套APIs, 它可以基于TCP也可以基于UDP
HTTP是短连接(在先不要讨论Keep Alive什么的情况下), 每次请求返回结束后, 连接就会断开
Socket是双向长连接的, 连接通道会一直保持, 直到连接断开
Socket的实现
Socket最常用的iOS第三方库出自robbiehanson/CocoaAsyncSocket
WebSocket
什么是WebSocket? 我们先看下维基百科的权威解释
WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议
在WebSocket API中, 浏览器和服务器只需要做一个握手的动作, 然后, 浏览器和服务器之间就形成了一条快速通道, 两者之间就直接可以数据互相传送
PS: 看完Wiki我的第一感受是, 词条编辑这家伙是ABC吧, 抑或语文是体育老师教的
按照"国际惯例", 我们来从中提取出一些关键词(这个方法充分回避了我语文不好的缺点😄)
-
HTML5
-
基于TCP
-
全双工通信
-
协议
作为新技术新协议的WebSocket有如下一些优势
-
实时交互(所以在IM中广泛使用)
-
服务器能够主动推送内容
-
只需要建立一次连接、快速(延迟小, 每条消息可以小到两个字节)
-
开发者友好(接口简单)
WebSocket与Socket的区别
两者虽然都是应用于双工通信的长连接, 但是实现和概念是完全不同的
WebSocket是协议, 而Socket是一套APIs
WebSocket与HTTP的关系
两者都是应用层协议, 这个算不算关系?
其实两者还真有点关系, WebSocket用了HTTP的协议来完成一部分握手
WebSocket的实现
最火的当然是socket.io莫属了, github star 2w+
iOS最好用(本人自己测试的)的出自facebook/SocketRocket
详细Demo可以参考SocketRocketDemo, 服务器端测试环境基于websocket.org
其他方案
上述Socket和WebSocket其实说的都是长连接, 那有没有其他方案了呢?
答案是肯定的, 而且就在我们身边: HTTP
HTTP不是短连接的么?
是的, 在HTTP/1.0默认情况下确实是这样的
但是HTTP是一个发展中的功能庞大且复杂的协议
它实现长连接的魔法就是Header中的Connection: Keep-Alive
在HTTP/1.1中, Keep-Alive已经是默认打开的了, 并且HTTP/1.1是支持双工通信的
不过坏消息是, HTTP/1.1基本已经处于死亡状态(猜测这里也有WebSocket的功劳)
它的继承者HTTP/2作为新的标准继续前进(对HTTP/2并不是很熟悉, 所以就不误导人民群众了, 欢迎"砖家"指导和补充)
除了HTTP协议之外还有没有其他方案了呢?
答案当然还是肯定的: 自研
大厂如企鹅, 底层都是自家实现的
优点如汽车手动挡vs自动挡, 缺点就是烧钱(具体实现暂不清楚, 所以在此就不继续讨论了)
心跳
长连接都有这样的问题: 如何保证长连接通道的可靠性
讨论之前先要明确的是, TCP长连接本质上是不需要心跳来维持的
因为TCP是面对连接的协议, 可以通过Keep-Alive来保证连接
那么为什么还要心跳呢?
-
Socket是基于TCP或UDP的, 所以基于UDP的Socket是需要心跳的
-
心跳可以说明应用能否正常运行, 而TCP由操作系统负责, 所以在应用进程阻塞、死锁时TCP仍然可以发送Keep-Alive消息
-
防止NAT超时, 大部分移动无线网络运营商都在链路一段时间没有数据通讯时, 会淘汰NAT表中的对应项, 从而造成链路中断
以下是部分地区网络NAT超时统计(引自微信Android客户端后台保活经验分享)
地区/网络 | NAT超时时间 |
---|---|
中国移动3G/2G | 5分钟 |
中国联通2G | 5分钟 |
中国电信3G | 大于28分钟 |
美国3G | 大于28分钟 |
台湾3G | 大于28分钟 |
为了兼容国内网络要求, 我们至少需要5分钟心跳一次
老版本的微信是4.5分钟发送一次心跳, 运行良好(该结论引自微信Android客户端后台保活经验分享)
心跳的进一步优化可以移步参考微信Android客户端后台保活经验分享&[转]微信的智能心跳方案
附录
闲说HeartBeat心跳包和TCP协议的KeepAlive机制
更多文章, 请支持我的个人博客
网友评论