目录
引言
消息推送
Socket
WebSocket
其他方案
心跳
附录
引言
现在的移动端开发, 消息推送是一个标配的必备功能, 工作中要开发的产品当然也不能"幸免"
不过或许你会说, 接入第三方不就得了 -- 为开发加速(LeanCloud的广告语, 表示感谢)
极光
腾讯信鸽
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客户端后台保活经验分享&[转]微信的智能心跳方案
附录
socket.io
websocket.org
趣解WebSocket
闲说HeartBeat心跳包和TCP协议的KeepAlive机制
微信Android客户端后台保活经验分享
[转]微信的智能心跳方案
Android推送技术研究
更多文章, 请支持我的个人博客