当网络通信采用tcp协议时,在真正的读写操作之前,sever与client之间必须建立一个连接,当读写操作完成之后,对方不再需要这个连接时他们可以释放这个链接,连接的连接需要三次握手,释放需要四次握手,也就是说每个连接的建立都是需要消耗资源和时间的。
tcp连接
短连接
模拟一种TCP短连接的情况:
- client 向 server 发起连接请求
- server 接到请求,双方建立连接
- client 向 server 发送消息
- server 回应 client
- 一次读写完成,此时双方任何一个都可以发起 close 操作
一般都是 client 先发起 close 操作。当然也不排除有特殊的情况。
从上面的描述看,短连接一般只服务器托管网会在 client/server 间传递一次读写操作!
短连接的操作步骤是:
- 建立连接——数据传输——关闭连接…建立连接——数据传输——关闭连接
优缺点:
- 短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费时间和带宽。
应用场景:
- 而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。
TCP长连接
模拟一种长连接的情况:
- client 向 server 发起连接
- server 接到请求,双方建立连接
- client 向 server 发送消息
- server 回应 client
- 一次读写完成,连接不关闭
- 后续读写操作…
- 长时间操作之后client发起关闭请求
长连接的操作步骤是:
- 建立连接——数据传输…(保持连接)…数据传输——关闭连接
保持连接用到了TCP保活功能
优缺点:
- 长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,适合长连接
- client与server之间的连接如果一直不关闭的话,会存在一个问题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件再允许就可以以客户端机器为颗粒度,限制每个客户端的最大长连接数,这样可以完全避免某个蛋疼的客户端连累后端服务。
应用场景:
- 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。每个TCP连接都需要三次握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,再次处理时直接发送数据包就OK了,不用建立TCP连接。
- 例如:数据库的连接用长连接,如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
对比
短连接环境下,数据交互完毕后,会主动释放连接;如果使用的是长连接的情况下,如果双方已经建立起了连接,但是很长一段时间内没有数据交换,而客户端可能意外断电、死机、崩溃、重启,还是中间路由网络无故断开,这些TCP连接没来得及正常释放,那么,因为服务端不知道客户端的情况,他就会一直维护这个连接,长时间的积累会导致非常多的半打开连接,造成服务端系统资源的消耗和浪费。所以服务端要做到快速感知失败,减少无效连接操作,这就有了TCP的Keepalive(保活探测)机制。
长连接断开的原因
- 在长连接的情况下,双方的所有通信 都建立在1条长连接上(1次TCP连接);所以,长连接 需要 持续保持双方连接 才可使得双方持续通信
- 可是,长连接会存在断开的情况,而 断开原因 主要是
- 长连接所在进程被杀死
- NAT超时
- 网络状态发生变化
- 其他不可抗因素(网络状态差、DHCP的租期等等 )
原因1:进程被杀死
当进程被杀死后,长连接也会随之断开
原因2:NAT 超时(重点关注)
- NAT超时现象如下
- 各运营商 & 地区的 NAT超时时间如下
- 特别注意:排除其他外因(网络切换、NAT超时、人为原因),TCP长连接在双方都不断开连接的情况上,本质上是不会自动中断的
- 即,不需要心跳包来维持
- 验证:让2台电脑连上同1个Wifi(其中1台做服务器, 另1台做客户端连接服务器(无设置KeepAlive);只要电脑、路由器不断网断电,那么,2台电脑的长连接是不会自动中断的。
原因3:网络状态发生变化
当移动客户端网络状态发生变化时(如移动网络 & Wifi切换、断开、重连),也会使长连接断开
原因4:其他不可抗因素
如网络状态差、DHCP的租期到期等等,都会使得长连接发生 偶然的断开
DHCP
的租期到期:对于Android
系统,DHCP
到了租期后不会主动续约 & 继续使用过期IP,
,从而导致长连接 断开
高效维持长连接的解决方案
在了解长连接断开原因后,针对对应原因,此处给出 高效维持长连接的解决方案
为此,若需有效维持长连接,则需要做到
其实,说得简单点:高效维持长连接的关键在于
- 保活:处于连接状态时尽量不要断
- 断线重连:断了之后继续重连回来
解决方案1:进程保活
解决方案2:心跳保活机制
这是本文的重点,下节开始会详细解析
解决方案3:断线重连机制
- 原理
检测网络状态变化 & 判断连接的有效性 - 具体实现
前者请参考文章:Android:检测网络状态&监听网络变化;后者主要存在于心跳保活机制,所以下面会在心跳保活机制中一起讲解。
心跳保活机制简介
- 心跳保活机制的整体介绍如下
- 注:很多人容易混淆 心跳机制 & 轮询机制,此处给出二者区别
主流心跳机制分析 & 对比
对国、内外主流的移动IM产品(WhatsApp、Line、微信)进行了心跳机制的简单分析 & 对比,具体请看下图
心跳机制方案 总体设计
下面,将根据市面服务器托管网上主流的心跳机制,设计 一套心跳机制方案
基本流程
设计要点
- 对于心跳机制方案设计的主要考虑因素 = 保证消息的实时性 & 耗费设备的资源(网络流量、电量、CPU等等)
- 从上图可以看出,对于心跳机制方案设计的要点在于
- 心跳包的规格(内容 & 大小)
- 心跳发送的间隔时间
- 断线重连机制 (核心 = 如何 判断长连接的有效性)
在下面的方案设计中,将针对这3个问题给出详细的解决方案。
心跳机制方案 详细设计
心跳包的规格
为了减少流量 & 提高发送效率,需要精简心跳包的设计
设计原则
主要从心跳包的内容 & 大小入手,设计原则具体如下
设计方案
心跳包 = 1个携带少量信息 & 大小在10字节内的信息包
心跳发送的间隔时间
为了 防止NAT
超时 & 减少设备资源的消耗(网络流量、电量、CPU
等等),心跳发送的间隔时间 是 整个 心跳机制方案设计的重点。
设计原则
设计方案
最直接 & 常用方案
一般,最直接 & 常用的心跳发送间隔时间设置方案 :每隔估计 x 分钟发送心跳包1次
其中,x <5分钟即可。(综合主流移动IM产品,此处建议 x= 4分钟)
但是,这种方案存在一些问题:
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net