《移动IM开发指南》系列文章将会介绍一个IM APP的方方面面,包括技术选型、登陆优化等。此外,本文作者会结合他在网易云信多年iOS IMSDK开发的经验,深度分析实际开发中的各种常见问题。

推荐阅读

移动IM开发指南1:如何进行技术选型

移动IM开发指南3:如何优化登录模块

心跳指令是什么?

在使用 TCP 长连接的 IM 服务设计中,往往都会涉及到心跳。心跳一般是指某端(绝大多数情况下是客户端)每隔一定时间向对端发送自定义指令,以判断双方是否存活,因其按照一定间隔发送,类似于心跳,故被称为心跳指令。

为什么需要在应用层做心跳?

那么为什么需要在应用层做心跳,难道 TCP 不是个可靠连接吗?我们不能够依赖 TCP 做断线检测吗?比如使用 TCP 的 KeepAlive 机制来实现。应用层心跳是目前的最佳实践吗?怎么样的心跳才是最佳实践?

是不是以前从来没有仔细考虑过这些问题,仅仅只是个简单的心跳而已啊!

对于客户端而言,使用 TCP 长连接来实现业务的最大驱动力在于:在当前连接可用的情况下,每一次请求都只是简单的数据发送和接受,免去了 DNS 解析,连接建立等时间,大大加快了请求的速度,同时也有利于接受服务器的实时消息。

但前提是连接可用。如果连接无法很好地保持,每次请求就会变成撞大运:运气好,通过长连接发送请求并收到反馈。运气差,当前连接已失效,请求迟迟没有收到反馈直到超时,又需要一次连接建立的过程,其效率甚至还不如 HTTP。而连接保持的前提必然是检测连接的可用性,并在连接不可用时主动放弃当前连接并建立新的连接。

基于这个前提,必须要有一种机制用于检测连接可用性。同时移动网络的特殊性也要求客户端需要在空余时间发送一定的信令,避免连接被回收。详见《微信和运营商的撕B》。

而对于服务器而言,能够及时获悉连接可用性也非常重要:一方面服务器需要及时清理无效连接以减轻负载,另一方面也是业务的需求,如游戏副本中服务器需要及时处理玩家掉线带来的问题。

上面说了保持连接的重要性,那么现在回到具体实现上。为什么我们需要使用应用层心跳来做检测,而不是直接使用 TCP 的特性呢?

我们知道 TCP 是一个基于连接的协议,其连接状态是由一个状态机进行维护,连接完毕后,双方都会处于 established 状态,这之后的状态并不会主动进行变化。这意味着如果上层不进行任何调用,一直使 TCP 连接空闲,那么这个连接虽然没有任何数据,但仍是保持连接状态,一天,一星期,甚至一个月,即使在这期间中间路由崩溃重启无数次。举个现实中经常遇到的栗子:当我们 ssh 到自己的 VPS 上,然后不小心踢掉网线,此时的网络变化并不会被 TCP 检测出,当我们重新插回网线,仍旧可以正常使用 ssh,同时此时并没有发生任何 TCP 的重连。

有人会说 TCP 不是有 KeepAlive 机制么,通过这个机制来实现不就可以了吗?但是事实上,TCP KeepAlive 的机制其实并不适用于此。Keep Alive 机制开启后,TCP 层将在定时时间到后发送相应的 KeepAlive 探针以确定连接可用性。一般时间为 7200 s,失败后重试 10 次,每次超时时间 75 s。显然默认值无法满足我们的需求,而修改过设置后就可以满足了吗?答案仍旧是否定的。因为 TCP KeepAlive 是用于检测连接的死活,而心跳机制则附带一个额外的功能:检测通讯双方的存活状态。两者听起来似乎是一个意思,但实际上却大相径庭。考虑一种情况,某台服务器因为某些原因导致负载超高,CPU 100%,无法响应任何业务请求,但是使用 TCP 探针则仍旧能够确定连接状态,这就是典型的连接活着但业务提供方已死的状态,对客户端而言,这时的最好选择就是断线后重新连接其他服务器,而不是一直认为当前服务器是可用状态,一直向当前服务器发送些必然会失败的请求。

从上面我们可以知道,KeepAlive 并不适用于检测双方存活的场景,这种场景还得依赖于应用层的心跳。应用层心跳有着更大的灵活性,可以控制检测时机,间隔和处理流程,甚至可以在心跳包上附带额外信息。从这个角度而言,应用层的心跳的确是最佳实践。

如何实现心跳指令?

从上面我们可以得出结论,目前而言,应用层心跳的确是检测连接有效性,双方是否存活的最佳实践,那么剩下的问题就是怎么实现。

最简单粗暴做法当然是定时心跳,如每隔 30 秒心跳一次,15 秒内没有收到心跳回包则认为当前连接已失效,断开连接并进行重连。这种做法最直接,实现也简单。唯一的问题是比较耗电和耗流量。以一个协议包 5 个字节计算,一天收发 2880 个心跳包,一个月就是 5 * 2 * 2880 * 30 = 0.8 M 的流量,如果手机上多装几个 IM 软件,每个月光心跳就好几兆流量没了,更不用说频繁的心跳带来的电量损耗。

既然频繁心跳会带来耗电和耗流量的弊端,改进的方向自然是减少心跳频率,但也不能过于影响连接检测的实时性。基于这个需求,一般可以将心跳间隔根据程序状态进行调整,当程序在后台时(这里主要考虑安卓),尽量拉长心跳间隔,5分钟,甚至 10 分钟都可以。而当 App 在前台时则按照原来规则操作。连接可靠性的判断也可以放宽,避免一次心跳超时就认为连接无效的情况,使用错误积累,只在心跳超时 n 次后才判定当前连接不可用。当然还有一些小 trick 比如从收到的最后一个指令包进行心跳包周期计时而不是固定时间,这样也能够一定程度减少心跳次数。

以上就是 网易云信对于心跳指令的理解和实践,《移动IM开发指南》第三篇文章将为大家介绍如何优化登录模块,敬请期待。

移动IM开发指南2:心跳指令详解相关推荐

  1. 家电产品出口指南,RoHs法规详解

    [家电产品出口指南,RoHs法规详解] 受疫情影响,我国家电出口创新高,据海关总署发布的数据统计,2021年,中国家用电器出口额987.2亿美元,同比增长22.3%,出口规模远超历史同期水平,创近十年 ...

  2. arm-linux-ld中的参数,arm-linux-ld指令详解

    arm-linux-ld指令详解 我们对每个c或者汇编文件进行单独编译,但是不去连接,生成很多.o 的文件,这些.o文件首先是分散的,我们首先要考虑的如何组合起来:其次,这些.o文件存在相互调用的关系 ...

  3. 九爷带你了解 nginx 日志配置指令详解

    nginx日志配置指令详解 日志对于统计排错来说非常有利的. 本文总结了nginx日志相关的配置如 access_log.log_format.open_log_file_cache.log_not_ ...

  4. C#中的预处理指令详解

    这篇文章主要介绍了C#中的预处理指令详解,本文讲解了#define 和 #undef.#if.#elif.#else和#endif.#warning和#error.#region和#endregion ...

  5. pragma comment的使用 pragma预处理指令详解

    pragma comment的使用 pragma预处理指令详解 #pragma comment( comment-type [,"commentstring"] ) 该宏放置一个注 ...

  6. 大数据WEB阶段(十三)JSP(一)JSP基础、JSP指令详解、四大域九大隐式对象总结

    JSP基础.指令.四大作用域九大隐式对象总结 (一)JSP基础 一.JSP概述 jsp其实是java动态页面技术 HTML可以用来组织页面但是HTML是一种静态web资源技术无法嵌入动态数据. Ser ...

  7. #pragma comment和#pragma 预处理指令详解

    该宏放置一个注释到对象文件或者可执行文件. 例如,#pragma   comment(lib,"Ws2_32.lib")表示链接Ws2_32.lib这个库. 和在工程设置里写上链入 ...

  8. #pragma预处理指令详解

    #pragma预处理指令详解 在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保 ...

  9. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

最新文章

  1. BZOJ 2132 圈地计划(最小割)【BZOJ 修复工程】
  2. 获取预测模型在测试集中预测错误的数据样本
  3. 爬虫笔记10Scrapy-框架
  4. 牛客多校2 - Boundary(几何)
  5. 在线流程图绘制网站draw.io支持的三种存储介质
  6. 【差分隐私的指数机制该怎么理解?】差分隐私系统学习记录(三)
  7. 运算符--位移运算符和一些其他运算符
  8. [设计模式-创建型]单态(Singleton)
  9. 四边形可以分为几类_“平行四边形法则”:谁总结这么奇异的书法规律?
  10. 144显示器只有60_3199元34寸144Hz高刷新曲面带鱼屏显示器咋样?用过才知道
  11. 人生是什么?——感悟1:勇于承担自己的选择才是真正的勇气
  12. php逻辑分析,PHP – 字符串逻辑分析 – “X和Y或Z”
  13. 使用R语言进行时间序列分析
  14. 系统防御工程v0.2
  15. 华为Java社招面试经历详解【已拿到offer】
  16. 使用insightface进行人脸识别批量下载图片
  17. p3c插件 离线安装_阿里开发规范及P3C插件
  18. TCP端口作用,漏洞,操作详析--杨义贤
  19. 物理机通过Xshell连接不上虚拟机的解决方案
  20. ROS机器人学习历程三:Publisher 和Subscriber

热门文章

  1. php接收dup,TCP与DUP简单对比
  2. 5种较为简单的缺失值处理方法
  3. shell题库选择题_linux操作题及答案 shell练习题
  4. C语言 | 编写一个使用指针的c函数,交换数组a和数组b中的对应元素
  5. 光流 | HS光流算法与LK光流算法(基于OpenCV)
  6. nginx mysql设置远程连接超时_nginx中的超时设置
  7. java setter_java – 如何获得@getter和@setter?
  8. matlab显示像素分布,MATLAb-----7--------如何动态显示鼠标的坐标值和图像像素值
  9. LeetCode--Add Two Numbers
  10. INTERSPEECH 2020 AutoSpeech论文征集挑战赛正式启动