iOS 自建通道原理总结

    xiaoxiao2023-12-17  171

    目录

    1、背景

    2、设计流程图

    1.长连通道的建立与初始化

    2.网络长连接通道的稳定性如何保证

    (1) NAT超时断开长连通道的规避策略

    (2) DHCP 续租断开长连通道的规避策略

    (3) 重试

    3、pushSDK与pushServer建立连接过程

     3.1协议设计

    4、通信格式

    4.1  监控体系


    1、背景

    目前iOS已经有原生APNs推送服务,完全有苹果公司维护。对于我们来说,里面任何的操作就像个黑盒看不见摸不着,很多条件是无法控制的,比如高峰期推送消息不及时,到达率不能给出相关数据等。

    2、设计流程图

     

     

    思考主要问题:

    1.长连通道的建立与初始化

    长连通道的建立见下面。

    长连建立成功后,第一次启动需要向服务端注册,获取服务端用于发push 推送的识别码,即push Token。

    2.网络长连接通道的稳定性如何保证

    (1) NAT超时断开长连通道的规避策略

    由于网络运营商都有相应的NAT超时策略,如果客户端和服务端建立的连接在一定时间内没有数据交换,则会被判定为已废弃的连接,并将其关闭。为了避免这种情况影响Push 长连的存活,注册成功后,为了让TCP长连保持连接,需要使用闹钟模块Alarm Service定期向后台发送心跳。但如果发送太频繁,将会导致高额耗电量,所以心跳间隔时间应该由后端控制。

    不同的网络运营商对于NAT超时的间隔有不同的设定,后端需要根据不同的网络类型,下发不同的心跳间隔,在最大程度上保证TCP长连存活的情况下,避免频繁心跳触发的高额耗电。

    以下是不同运营商对于NAT超时时间的策略。

    地区/网络

    NAT超时时间

    中国移动3G和2G

    5分钟

    中国联通2G

    5分钟

    中国电信3G

    大于28分钟

    美国3G

    大于28分钟

    台湾3G

    大于28分钟

    (2) DHCP 续租断开长连通道的规避策略

    由于安卓系统对DHCP的处理存在漏洞—— DHCP租期到了不会主动续约并且会继续使用过期IP。

    这个问题导致的问题表象是,在超过租期的某个时间点(没有规律)会导致IP过期,老的TCP连接不能正常收发数据。并且系统没有网络变化事件,只有等应用判断主动建立新的TCP连接才引起安卓设备重新向DHCP Server申请IP租用。

    为了避免这一问题,未到租期的一半时间,安卓设备需要重新向DHCP Server申请IP租用。

    (3) 重试

    网络环境不稳定,长连极易受到影响被断开,在断开后希望能及时建立连接保证通道的稳定性,因此设计一套重试机制是很重要的。有个问题要思考,我们SDK不可能无数次地请求建连,服务器会崩掉,我们会考虑时间次数和时间间隔-斐波拉契数列作为重试时间间隔,这样能有效规避无限建立连接的过程。最后如果还是不行就换个IP进行连接。

    参考:https://caofengbin.github.io/2018/03/16/dhcp-and-nat/

    3、pushSDK与pushServer建立连接过程

    连接管理是整个SDK的核心部分

    SDK与服务器之间保持长连接,针对于Push业务的特性,我们只需要以单线程,单tcp连接的形式即可满足我们的业务需求。

    同时这种设计有助于降低复杂度,提高app稳定性(避免资源竞争,降低服务器承载压力)。

    主要包含以下几个模块:

    1. TCP连接的选择,建立,维持

    2. 通讯协议的定义

    3. 通讯安全

    4. 消息去重等

    ① 连接的建立

        1、使用预埋或者上次下发的ip池中依次进行连接,直至连接成功

        2、连接成功后后服务器会下发新的ip

        3. SDK针对IP List中所有ip建立长连通道。每条通道进行  b 步骤(跑马)。

        4. 对比所有RTT,保留耗时最小的通道,断开其他通道。

        5. SDK发起注册或登录。(鉴权服务)

    这样做的意义是有利于服务器的扩容,不依赖于SDK发版     

    ② 重连机制(维持)

           受网络环境的不稳定,SDK建立的长连接极易断开,因此我们必须设计一套重连机制。在断开后及时重连,保证通道的可用性。同时,受限于接入点接入能力的限制,SDK不可能不断向接入点申请连接,这样有可能造成服务雪崩。针对这种情况,我们针对连接异常断开的场景,重连时使用斐波那契数列作为时间间隔,这样就有效避免了重连的无线重试。IPV4 因为Address数量有限,所以运营商分配给手机终端的ip一般是内网ip,手机要连接Internet,就需要通过运营商的网关做一个网络地址转换(Network Address Translation,NAT,GGSN 模块)。简单的说运营商的网关需要维护一个外网IP、端口到内网 IP、端口的对应关系,以确保内网的手机可以跟 Internet 的服务器通讯。心跳时间默认2分钟,sdk会随登录接口返回配置项,SDK根据配置调整心跳时长,直至最佳时长。

    ③ 使用AES对所有通讯内容进行加密处理,保障通讯安全

    ④ 使用二进制通讯协议

    长连下发模块(loadBalance):长连接IP下发模块用于将长连接服务器的外网ip(即负载均衡器的ip)下发给客户端,当有ip删减的时候,用户端需要实时感知到。

    连接管理:连接管理模块用于海量连接的管理,维持长连接的稳定性。

    保活的实现:1)客户端使用一个定时器,定时发送心跳ping,如果每次都能收到服务端的心跳响应pong,说明当前连接是健康的。2)服务端也使用一个定时器,定期检测是否有数据读写,如果持续有数据读写,说明连接是健康的,如果隔一段时间没有收到客户端的ping,那就说明这条连接已经假死,需要立即释放资源。3)客户端的心跳发送间隔如果是T秒,一般来说,长连服务端的定时器的间隔应该大于2T秒,保证客户端的连续两次心跳能收到一条。

    pushServer通信模块:主要就是管理开放给push server对应的tcp服务器端口,收发push server过来的数据,透传给sdk模块。

    通信协议的设计

    与客户端之间的协议:

    其中version:协议版本号

    contentLength:数据包总长度(不包括version字段)

    encrypt:标识该请求是否加密,1为加密,0为非加密

    command:具体命令字,有如下选项

    具体的command字段

    action

    request

    response

    request 发起端

    push

    0

     

    connection server

    transfer data

    1

     

    push sdk

    loadBalance

    2

    12

    push sdk

    注:LoadBalance请求不需要带任何数据,响应格式为:data字段域为connection-server ip列表, 十六进制表示

     Example:  若返回两个ip,26.27.28.29和42.43.44.45则data字段域的值为 1A1B1C1D2A2B2C2D

    unEncryptContentLength:非加密部分的长度

    unEncryptContent:主要存储加密过程中的密钥相关的信息,比如首次加密的时候客户端需要传public key,通信的时候需要对称密钥

    encryptContent:数据包的主体

     

    与pushServer之间的协议

    其中version:协议版本号

    connectionId:表示本机长的唯一一个用户

    length:数据包的长度(command和data字段)

    command:命令字

    具体的command 字段含义

    action

    request

    response

    request 发起端

    push

    0

     

    push server

    transfer data

    1

     

    connection server

    auth

    2

     

    push server

    disconnect

    9

    19

    push server

    data:与push server之间由于是内网通信,不需要加解密

     

     3.1协议设计

    长连通道通过Connection形式封装,每个Connection表示一个长连通道。每个Connection包含Read,Write流。PSTunnelProtocol类负责对读写流的数据解析。PSPushProtocol类(继承自)负责组装数据。写操作时直将封装好的数据调用父类写方法发送。读操作时将解析后数据抛给Connection。

    4、通信格式

    SDK与服务器之间通信格式为:   

    在发送push消息后,出现网络异常或者服务器异常等可重试的异常,为了保证push的容错性,可将这部分push提交到重试队列,在指定时间出队,重新发送。

    4.1  监控体系

    为了及时监控消息的到达率已经SDK的运行情况,我们将SDK的监控体系分为四个部分

    1、外部监控(主要由SDK提供接口,当Push触达App时,由App调用HTTP接口进行上报)

          主要有Push的展示、点击埋点。

    2、内部监控(针对所有长连接到达SDK的消息,SDK会立即以ACK的形式给Push Server一个回复,告知到达,以便Server执行策略)

    3、代码级监控 (在函数级埋点,并将日志存储在App本地,当需要时进行回捞)

     

    最新回复(0)