Android中长连接的解决方案

2019-07-24 15:53:25 浏览数 (1)

Http请求的过程

  1. 通过运营商的DNS服务器解析目标域名的ip地址,保存到localhost文件中缓存
  2. 通过TCP三次握手与服务端建立链接
  3. 写入Http的请求头、请求体以及数据后接收数据
  4. 接收完一个请求的数据后,通过TCP四次挥手释放链接

如果还需要担心DNS劫持的话,则还需要加一层HttpDNS的过程。也就是通过Http协议将域名解析成对应的可信任的IP列表,通过ip直接访问。

长连接的优势

长连接通过Socket与服务端建立持久的链接,即使单个请求发送与接收后也不会释放链接。这样的好处有:

  1. 通过指定IP建立连接,减少DNS的查询时间
  2. 只用经历最初的一次TCP的三次握手,在真正请求时,则免去了建立连接的过程
  3. 在大量请求并发的时候,不会出现大量的Http链接断开重连的过程
  4. 服务端可以通过长连接进行推送,达到更加实时的效果
  5. TCP接收数据的滑动窗口也会一直保持

长连接的问题

虽然长连接的好处很多,但是在保持长连接稳定的过程中也会存在很多的问题:

  1. 网络切换的过程会导致长连接断开
  2. 进程被杀掉时候,也会导致长连接断开
  3. NAT超时,会导致长连接断开
  4. DHCP租期到了,会导致ip地址变化,导致长连接断开

所以,在应用中,就需要保护长连接的稳定,否则会导致很多信息收不到。

NAT:因为 IP v4 的 IP 量有限,运营商分配给手机终端的 IP 是运营商内网的 IP,手机要连接 Internet,就需要通过运营商的网关做一个网络地址转换(Network Address Translation,NAT)。简单的说运营商的网关需要维护一个外网 IP、端口到内网 IP、端口的对应关系,以确保内网的手机可以跟 Internet 的服务器通讯。GGSN(Gateway GPRS Support Node 网关GPRS支持结点)模块就实现了NAT功能。 因为大部分移动无线网络运营商都是为了减少网关的NAT映射表的负荷,所以如果发现链路中有一段时间没有数据通讯时,会删除其对应表,造成链路中断。

长连接的稳定性方案

为了从客户端保持长连接的稳定,有这些方案:

  1. 提升长连接进程的优先级,避免被系统杀死
    • 因为Linux中的Low Memory Killer是通过每个进程的oomadj来判断是否清理该进程,所以可以通过提高进程优先级来降低被Kill的风险
  2. 进程保活,当进程被Kill时,可以重新启动:
    • 通过接收系统广播
    • 通过AlarmManager定时检测
    • 通过Linux的fork子进程,当子进程被回收时,检测ppid是否为init进程,如果是的话,则回调Java层启动Service
    • 通过Service的onStartCommand返回START_STICKY
  3. 网络切换时,自动重连
    • 监听系统网络切换广播
    • 监听屏幕亮灭的广播,主动批量拉取消息
  4. 定期发送心跳包,避免NAT超时
    • 移动网络的NAT超时一般都在5min左右
    • 心跳包需要在5min以内定时发送

运营商NAT超时时间

长连接与耗电

在保证长连接的过程中,太频繁发送网络请求,并且当前设备状态不佳时,都需要动态的调整长连接的策略。并且在收到消息后,本地存储的时机都需要进行考虑。

  • 前后台策略:区分进程前后台,调整心跳间隔时间
  • NAT超时策略:根据运营商以及网络类型,调整心跳间隔
  • 合并请求:将多个请求在同一时间/同一个包内进行合并,减少系统唤醒次数
  • 设备策略:根据设备是否在充电、设备电量来制定长连接请求策略
  • 消息策略:区分消息类型,制定优先级,确定哪些消息在特定情况下拉取
  • Android特性:尽量拟合Doze以及JobScheduler的特性,批量以及特定情况下进行消息处理

长连接的容灾

当用户的长连接断了之后,如果不能重启,则需要将长连接进行降级策略,例如使用Http轮询策略。

长连接消息的本地存储

在长连接消息的本地存储中,通常都使用SQLite数据库,当然也有新型的ORM数据库例如ObjectBox。而通常长连接都需要考虑数据库的点有:

  • 数据库的过期时间
  • 数据库消息的数量
  • 数据库消息的清理时机与策略
  • 数据库的批量插入与删除效率

离线推送

对于有产品矩阵的App而言,可以通过产品矩阵来发送Push的通知从而拉起相应的产品。比如百度、腾讯、阿里、头条等

0 人点赞