写点什么

百度 iOS 端长连接组件建设及应用实践

作者:百度Geek说
  • 2023-07-13
    上海
  • 本文字数:6522 字

    阅读完需:约 21 分钟

百度iOS端长连接组件建设及应用实践

作者 | 百度消息中台团队


导读

在过去的十年里,移动端技术飞速发展,移动应用逐渐成为主要的便捷访问和使用互联网的方式,承接了越来越多的业务和功能,这也意味着对移动端和服务器之间的通信效率和稳定性提出了更高的要求。为了实现更高效的实时通信和数据同步,长连接逐渐成为一种关键技术,通过维持客户端和服务器之间的持久连接,实现了双方实时数据交换,避免了频繁的建连和断连开销,从而提高用户体验、服务稳定性、可靠性等方面的表现。

本文旨在探讨长连接技术在移动端的实践,针对百度 iOS 端在建设长连接过程中的技术选型和整体架构逻辑将做重点展开。同时结合 IM 即时通讯案例的介绍和分析,展示长连接是如何在移动应用领域为类似业务场景提供解决方案的。

本文将分为五个主要部分。首先,对长连接技术进行概述,包括定义、与短连接的对比以及在移动互联网领域的常见应用。接下来,会简单介绍百度长连接服务,包括搭建的背景以及建成后提供的服务核心主流程。然后,将重点讨论百度 iOS 端长连接 SDK 搭建过程中的挑战和解决方案,包含协议的选择、DNS 解析优化、长连接保活机制的设计等。紧接着,以 IM 即时通讯场景中的长连接实践为例,展示了长连接 SDK 是如何为业务实现请求数据转发、接收服务器主动推送等功能的。最后,对本文的主要内容做了总结,以及对长连接在移动端应用中未来的发展趋势和前景进行了展望。


全文 7193 字,预计阅读时间 18 分钟。

01 长连接简介

1.1 认识长连接

长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。



1.2 长连接与短连接对比


1.3 长连接在移动互联网领域的应用

长连接在移动互联网领域有广泛的应用,特别是在实现实时通信和消息推送等功能方面发挥了关键作用。例如,常见的微信、QQ 这样的即时通信软件,就是通过维持客户端和服务器的长连接,实现即时传输信息的需求。又如一些网络游戏、定位服务、新闻推送等,也会使用长连接,实时推送新的动态或者消息给用户。这样,无论用户在何时何地,只要连接到互联网,就能够接收到最新的信息,极大地提升了使用者的体验度并且使得移动互联网更加便捷。


总的来说,对实时性、数据传输效率、频繁通信等有强需求的应用,长连接都是一个好的选择。

02 百度长连接服务简介

2.1 搭建统一长连接的背景

此前,百度移动端都是由各业务自运维的长连接,往往搭建和维护成本都偏高,且可复用性不大,因此计划实现一套高并发、低时延、高触达的统一长连接组件,能够更灵活高效地支持各业务接入,能够对百度系的各 APP 独立输出长连接服务满足各业务的诉求,从而提升服务质量,降低资源成本。

2.2 长连接服务主流程图

百度长连接服务包含客户端的长连接 SDK 和服务端的长连接接入层两个部分,长连接接入层又包含访问控制模块和接入模块,负责维护长连接管理及业务数据转发。下图描述了长连接建连及心跳保活过程,业务登录和登录后推送过程,以及最终长连接 SDK 触发断连的过程。后文将针对 iOS 端长连接 SDK 的具体实现解决方案,和长连接 SDK 在百度 APP 中的业务应用落地进行更为详细的探讨。


03 百度 iOS 端搭建长连接 SDK 的解决方案

3.1 客户端搭建长连接的挑战点概述

客户端从 0 到 1 搭建一套完整的长连接 SDK,这个过程涉及到多个技术点的考虑,包括但不限于:连接的创建和维护,网络协议的选择,使用加密传输、验证数据来源等方式保证长连接的安全性,通过数据传输格式选择、数据压缩等方式减少数据量提高传输效率,错误异常处理机制等,需要开发者根据实际情况进行最优实现方案的选择。在这之中,最核心的可以拆解为以下两个部分:


1、连接的创建:完整建连流程的设计,网络协议的选择,设计时需要考虑长连接建连的成功率、时延等核心指标;


2、连接的维护:保证建连成功是第一步,长连接还需要保持维护双方连接才可达成持续通信的目的,这包括:在长时间无数据交互的情况下,需要定期发送心跳包进行连接的保活,以及长连接连接断开后需要及时进行断线重连恢复连接在线状态。

3.2 核心逻辑一:连接的创建

长连接建连即客户端与服务器建立连接,是长连接 SDK 要做的第一件事,所有业务方数据的传输(上下行)都要基于长连接建连成功的这个前提。长连接建连并不是一个单一简单的操作,而是一个分阶段进行的过程。本小节将主要讨论在设计开发长连接建连模块之前,需要重点考虑确认的几个技术点和实现方案,以及百度 iOS 端长连接 SDK 最终实现的长连接建连完整过程的架构。


3.2.1 挑战①:协议的选择

问题点:UDP 还是 TCP

对于网络编程这个话题,使用哪种数据传输层协议来实现通信是一个非常基础但一直争论不休的问题。UDP 和 TCP 各有各的应用场景,TCP 能提供可靠的数据传输,UDP 则有更高的传输效率,此处不再赘述 TCP 与 UDP 的区别,最终选择哪种协议实现,是一个见仁见智的问题,需结合整体应用场景、开发代价、部署和运营成本等方面综合考虑。


解决方案:TCP 为主,同时小流量探索 QUIC 的潜力

百度 iOS 端长连接 SDK 中现有两套数据传输方案:

方案一:在长连接 SDK 建设初期,根据业内成熟技术方案选型的调研结果,及开发成本、维护便捷性的考虑,第一个方案是参考 CocoaAsyncSocket 框架改写的,基于 Socket 原生开发,使用 TCP 协议,支持 TLS/SSL 安全传输,并且是线程安全的,该方案较为成熟,使用便捷,建连成功率较高。目前百度 APP iOS 端中 90%的用户流量都是走的该方案实现的长连接逻辑。


方案二:一般稳定网络传输都是通过 TCP,但在网络基建本身已经越来越完善的情况下,TCP 一些设计本身的问题便暴露了出来,加之 TCP 是在操作内核和中间固件中实现的,因此对 TCP 进行重大更改几乎是很难的事情,类似建连过程握手耗时长、队头阻塞等问题没有得到很好地解决,让我们开始考虑一些新的可能性。长连接 SDK 后续引入了基于 QUIC 协议实现的第二套方案。QUIC 协议是建立在 UDP 之上,并且实现了可靠传输,相比 HTTP2+TCP+TLS 协议,QUIC 具有不少优点:减少了 TCP 三次握手及 TLS 握手时间,改进了拥塞控制,并且没有队头阻塞的多路复用,支持连接迁移等。百度 iOS 长连接 SDK 目前通过 NWConnection 引入了 QUIC 协议的实现。QUIC 的协议虽然比较先进,但这也意味着在工程实现方面有更多可优化的空间,目前方案二还处于小流量实验阶段,仍有很多优化工作有待后续进一步去落地。就当前放量所得到的数据来看,在长连接建连成功率及时延指标上,QUIC 实现方案都有较好的表现。


3.2.2 挑战②:DNS 解析优化

问题点:国内移动端网络所面临的 DNS 疑难杂症

国内各 ISP 运营商的 LocalDNS 由于域名缓存、解析转发、LocalDNS 递归出口 NAT 的原因,容易引起 DNS 被劫持造成服务不可用、DNS 调度不准确导致性能退化等问题。DNS 解析的效率和准确性,直接影响长连接建连的质量,进而影响公司的业务。


解决方案:HTTPDNS

因此在百度 iOS 端长连接 SDK 中,采用当前业界比较主流的解决方案:HTTPDNS,来替代 LocalDNS 解析。HTTPDNS 是利用 HTTP 协议与 DNS 服务器进行交互,绕开了运营商的 LocalDNS 服务,有效防止了域名劫持,提高域名解析效率。


3.2.3 完整解决方案:百度 iOS 端长连接建连整体流程

建连时机

在百度 APP 中,统一维护了一系列系统事件和生命周期供各个组件监听。iOS 长连接 SDK 根据百度 APP 的业务特性,选择在环境搭建完成事件后触发长连接建连,即等待 APP 启动必要数据比如首页资源等加载完成后,开始触发长连接建连。


建连完整过程

下图展示了长连接 SDK 建连的四个过程:

获取 Token

  • 获取 Token 的意义:狭义上 Token 指的是长连接访问控制模块返回的 access-token,后续随长连接登录请求上行到长连接接入层,由接入层向长连接访问控制模块进行鉴权用。广义上随此次 Token 请求下发的,还有传输协议及访问点等数据,包括但不限于:长连接协议使用 QUIC 还是 TCP,是否优先 ipv6,连接域名和端口,日志打点小流量开关等。

  • 获取 Token 的机制:获取 Token 优先走本地缓存,当本地缓存无有效数据时,才发出网络请求,该请求是基于 NSURLSession 实现的短连接请求;Token 在服务端和客户端均有缓存,存在过期时间,若 Token 过期,会在下图中阶段四通过长连接登录请求失败体现,这时会清空本地 Token 缓存并触发重新建连。

DNS 域名解析:如前所述,长连接 SDK 中使用 HTTPDNS 替代 LocalDNS 来防止 DNS 劫持、提高解析效率。同时在 iOS Release 环境下,为提高 DNS 解析效率,本地建立了缓存机制,HTTPDNS 解析结果返回后会更新本地缓存,下次建连过程优先取缓存,缓存不合法才走网络请求。

建立 Socket 连接:Socket 建连过程涉及到传输协议的选择,根据前面介绍,iOS 长连接 SDK 目前是通过小流量实验的方式,10%的用户走 QUIC 建连,90%的用户走 TCP 建连。

长连接登录请求:携带 Token 中获取的 access-token 上行请求完成鉴权,长连接登录请求返回成功意味着整个建连过程完成,业务层可开始正常使用长连接进行通讯,若登录返回报错,则会触发重连。

顺利完成这四个阶段后,长连接会在该链路上持续发送心跳包进行连接保活,在异常断连或压后台等触发的主动断连之前,一直保持连接在线状态,为各个业务的数据传输提供通路。


3.3 核心逻辑二:连接的维护

3.3.1 维护连接的意义

上个小节介绍了长连接连接建立的全过程,长连接建连成功后,实际已处于可用状态,即各业务基于长连接的通信已经可以正常进行。但在此之后,保持长连接的可用性也是非常重要的。如果长连接无法很好地保持,在连接已经失效的情况下服务端继续推送下行通知而端却收不到,造成资源的浪费,同时无法及时重新建连,对业务造成损失。


3.3.2 维护长连接的解决方案

针对可能导致长连接断开的几种主要原因,长连接 SDK 建立了对应的机制来保证连接的稳定性,可总结为两点:心跳保活和断线重连。



解决方案①:心跳保活

心跳保活的定义:实现长连接保活的方式通常是采用应用层心跳,通过心跳包的超时或报错等来执行重连操作。心跳一般是指某端(通常是客户端)每隔一定时间向另一端(通常是服务端)发送自定义指令,以判断双方是否存活,因其按照一定间隔发送,类似于心跳,故被称为心跳保活。

百度 iOS 端长连接 SDK 心跳保活机制:长连接登陆请求成功后,解析返回数据,若服务端下发了心跳包的间隔时间,则以服务端下发的时间间隔持续发送心跳包进行连接保活,若没有下发心跳包间隔时间,客户端会默认 60s 间隔时间来触发心跳包的发送。具体心跳保活过程见下图。



解决方案②:断线重连

断线重连原理:在长连接可能被断开的场景(压后台重进 APP、网络状态变更等),检测长连接的可用状态,监测到连接不可用时,及时触发重连机制。

百度 iOS 端长连接 SDK 断线重连机制:具体触发断线重连的时机见下图,iOS 长连接 SDK 内部维护有串行队列和统一的长连接状态监测记录,不会导致重复建连的发生。


04 长连接在百度 APP 中的应用与实践

4.1 长连接在百度 APP 中的业务落地

长连接是客户端到服务端的一种全双工连接,建连完成后,可以为业务方提供请求转发、服务端主动推送等服务。在百度 APP 中,包括在线健康诊疗、高考志愿填报咨询、情感心理辅导等一系列实时咨询服务,发送直播弹幕、加入某大 V 粉丝群聊天、私信好友等多种用户实时沟通场景的落地,以及实现用户在线情况下云端可及时主动下发配置控制端的基础能力建设,都离不开长连接的支持。长连接为各个业务与自己服务端的数据交互提供了稳定便捷的方式和渠道。


下图为百度 APP 中长连接与落地业务的结构示意图。完整的长连接模块包括了客户端的长连接 SDK 和服务端的长连接接入层两个部分,作为各个业务与自己服务端数据交流的中间渠道,处理了包括连接建立与保活、实现各业务客户端与自己服务端的数据双向互发等逻辑。下面将重点关注长连接在 IMSDK 实时聊天通讯场景中的实践。


4.2 长连接在 IM 即时通讯场景中的实践


4.2.1 背景介绍

IMSDK,即百度消息中台为百度 APP 及百度系其他产品打造的具备应用内即时通讯能力的客户端 SDK,包括多种用户沟通场景:私聊、群聊、聊天室、直播弹幕等,并帮助业务推送消息通知触达用户,建立 B 端和 C 端的沟通渠道。目前主功能诸如拉取会话列表、拉取消息、发送消息、消息已读等均为长连接实现。本小节将通过介绍用户发送消息、用户收到新消息通知这两个 IM 及时通讯中的常见场景,展示长连接提供的数据转发和服务器主动推送能力是如何在业务场景落地的。


4.2.2 实践 1:实时聊天场景下用户发送消息

实践场景

实时聊天场景下,用户在聊天框向自己好友发送一条消息,消息如果发送失败了,应用通常会在本条消息气泡旁展示一个红叹号,这个应用场景对于互联网用户应该都非常熟悉。从技术角度看,本质上是业务客户端向自己的服务器上行一个请求,服务器再将请求结果返回给客户端。这是一个典型的需要频繁点到点通信的场景,非常适合基于长连接来实现。长连接 SDK 对外提供了封装好的长连接请求类,外部业务方诸如 IMSDK 在上行长连接请求时通过创建该类的实例,将上行所需参数和数据赋值给请求实例,并设置回调闭包用于接收和处理请求回执数据和结果,最后将请求发出。业务不需要考虑数据传输及转发等逻辑,长连接会充当业务客户端和服务器之间的通路,黑盒处理这个过程。

技术难点

对于长连接 SDK 而言,在这条通路上最重要也是比较复杂的逻辑点在于,各个业务方的上行请求和下行通知都是并发进行的,长连接 SDK 如何有序地管理数据流向。上行请求即写流,接收下行数据即读流,下面就读写流的管理,与请求同回执数据的匹配问题的解决方案作简要的介绍。

技术实现

长连接 SDK 内就读写数据维护有两个队列:读队列和写队列,以及维护了一个缓存池用作请求实例和请求回执数据的匹配。业务方上行一个长连接请求,实际上是将请求任务添加到写队列中,如果此时处于可写流状态,还会触发写流。当 socket 建连成功以后,会取出写队列队头的任务,开始写流,写流完毕会检查写队列是否为空,不为空继续取队头任务执行,直至写队列为空为止。同时 socket 建连成功还会添加一次读任务到读队列中,并检查如果此时处于可读状态,便取出队头第一个读任务,开始读流,读流成功后会继续添加一个读任务到读队列,循环读流操作。

读流得到的服务端下行返回数据,通过 serviceId(业务编号)+ methodId(长连接请求方法编号)+ 请求发起的时间戳组成唯一键值,去缓存区匹配到下行返回数据对应的请求体,通过回调的方式,将请求结果返回到调用方。该请求一旦被回调过一次,其实例将从缓存区被删除,及时释放缓存区内存,并且保证一次请求不会发生多次回调的情况。



4.2.3 实践 2:实时聊天场景下用户收到新消息通知

实践场景

实时聊天场景下,用户是如何收到别的用户发送给他的新消息通知的呢?其实是依靠服务器的下行通知到客户端。长连接不仅提供为业务客户端转发上行请求的能力,还提供了服务端主动推送的服务。比如在 IM 业务中,依靠 IM 服务器下行新消息通知,来完成消息的实时接收和拉取。这些通知又是如何到达 IMSDK 的呢?其实它与上一小节 IMSDK 上行长连接请求的过程类似。


技术实现

在 IMSDK 的长连接管理类初始化阶段,会对需要接收的下行通知方法进行注册,这里的注册实际上指的就是上行多个长连接请求,每个请求有对应的 serviceID(业务编号)和 methodID(需要注册的通知方法号码)。跟上一小节长连接请求不同的点在于,这些请求在收到回执数据后不会从长连接 SDK 请求缓存区里移除,而是会长期存在,只要读流时读到了对应 methodID 的数据,就能在请求缓存区找到对应请求,将下行数据传到 IMSDK 了。这样一来,只要长连接在线,业务方就能实时接收到其服务器下行的通知消息了。

05 结语

长连接服务的核心大致可分为:建连过程、连接维持过程以及数据传输过程。本文给出了搭建长连接服务过程中面临的一些挑战和解决方案,并结合长连接功能在百度 APP 即时通讯场景下的实践,简要介绍了百度 iOS 端长连接 SDK 的整体架构。


在移动端,长连接技术的应用前景非常广阔。随着 5G 和 6G 等高速移动网络的发展,将使得移动应用程序能够更加高效地使用长连接技术,从而实现更加实时和高效的数据交换。这也为对实时数据交换有强需求的应用场景提供了更广阔的想象空间,诸如物联网、智能家居、虚拟现实和增强现实等技术,长连接都将在其中发挥更加重要的作用。


——END——


推荐阅读:


百度App启动性能优化实践篇


扫光动效在移动端应用实践


Android SDK安全加固问题与分析


搜索语义模型的大规模量化实践


如何设计一个高效的分布式日志服务平台


视频与图片检索中的多模态语义匹配模型:原理、启示、应用与展望

发布于: 刚刚阅读数: 5
用户头像

百度Geek说

关注

百度官方技术账号 2021-01-22 加入

关注我们,带你了解更多百度技术干货。

评论

发布
暂无评论
百度iOS端长连接组件建设及应用实践_网络编程_百度Geek说_InfoQ写作社区