信道重连设计

需求概述


在现今的客户端和服务端端的网络交互流程中,已经实现了信道重连的功能。但目前各客户端针对重连的实现细节并不完全统一,而在某些使用场景下,也没有达到当初设计信道重连机制的需求。因此需要重新设计整理实现方案,保证各平台的统一和功能的完备。

功能需求


我们需要实现以下需求:

  • 信道重连的请求由客户端发起,客户端需要定义规则来判断何时发起重连请求;
  • 服务器需要在信道重连的请求响应中返回密钥有效期,以此来作为信道重连的最小时间间隔;
  • 所有通过信道传输的网络请求,在请求过程中都需要判断信道是否重连;
  • 客户端需要增加配置是否禁用信道重连功能。

设计


以下说明的网络请求,未经特殊说明的,都指经过信道传输的网络请求,包括但不限于:

  • luahttp接口发出的请求;
  • js http接口发出的请求;
  • 离线更新及通过信道下载发出的请求;
  • 开发模式请求ewp服务器资源的请求;
  • 控件属性或样式中需要去ewp服务器请求资源的请求。

信道重连逻辑


  • 在信道握手请求中,若EWP端有配置信道重连时间,则将其值(单位秒)作为信道重连的时间间隔,以X-Emp-CipherExpiry header的形式,返回给客户端;
  • 客户端在接收到EWP端的网络响应时,解析header,如遇X-Emp-CipherExpiry字段,将其值保存,后续以此计算信道重连的时间戳;
  • 客户端在所有通过信道传输的网络请求发起前,先判断当前系统时间是否大于信道重连的时间戳。如需要信道重连,则重新走握手流程,并在请求中加上X-Emp-Rehandshake header,值为1;
  • EWP端在握手流程中需获取X-Emp-Rehandshake header,若值为1,则在握手成功后返回ok,否则与正常流程一致,返回app初始化页面;
  • 为保证安全,客户端在信道重连的请求响应中判断是否重连成功,若重连失败,则取消后续请求,并提示网络错误。其中网络错误信息可配置。
  • 客户端增加配置项是否禁用信道重连功能,该配置关闭时,不走信道重连流程。

信道重连时间戳的计算方法


  • 客户端拿到服务器返回的X-Emp-CipherExpiry字段值后,先将其与当前系统时间相加,计算得出一个信道超时时间戳。
  • 在后续的网络请求响应成功后,取当前系统时间与本地存储的X-Emp-CipherExpiry字段值相加,得出新的信道超时时间戳;若请求响应失败,无须更新时间戳。

关于并发请求的说明


由于产品的网络请求大多为异步请求,存在并发访问ewp的情况。那么很可能出现这种场景:

  1. 请求A发现信道超时,请求ewp服务器重连信道;
  2. 在A重连信道请求尚未返回时,出现并发请求B;
  3. 请求B发现信道超时,也请求ewp服务器重连信道。

这样就造成冗余重连信道的现象发生。

为此规定,当某个网络请求开启信道重连请求时,后续触发的网络请求必须等待此信道重连结束后,方可继续执行后续操作。若信道重连成功,等待的网络请求继续发出;若信道重连失败,取消所有等待的网络请求。

简单的实现


/** 信道超时时间,非0情况下,当前时间大于此时间时,信道超时重连 */
    private static long mRehandshakeTime = 0L;
    /** 服务器返回超时时间 */
    private static long mInterval = 0L;
    /** 信道是否重连的标记 */
    private static String mRehandshake = "false";
    /** 信道重连是否成功的的标记 */
    private static String mRehandshakeSuccess = "true";
    /** 1.4 信道是否为密文传输   默认true */
    private boolean mIsEncryptedTrans = true;
    /** 存放CryptoHttpManager的队列 */
    private static ArrayList<CryptoHttpManager> mList = new ArrayList<CryptoHttpManager>();
    /** 标记是否取消后续请求。 */
    public  boolean mCancel = false;
    /** 是否重连的标记 */
    private  boolean mIsRehandshake = false;

if(!mIsRehandshake){
                    synchronized(mList){
                        if( EMPConfig.newInstance().isTlsReconnectAble() && "true".equals(mRehandshake)){
                            mList.add(this);
                            mList.wait();
                        }
                    }
                //取消后续请求返回null
                if(mCancel){
                    return resultObj;
                }
                synchronized (mRehandshake) {
                    // 请求之前首先判断信道是否需要重建
                    if (EMPConfig.newInstance().isTlsReconnectAble() && "false".equals(mRehandshake)
                                && mRehandshakeTime != 0L && System.currentTimeMillis() > mRehandshakeTime) {
                                    mRehandshake = "true";
                                    try{
                                            //信道重连
                                            new ClientHello();
                                            // 信道重连结束后更新成功标记
                                            mRehandshakeSuccess = "true";
                                    }catch (HttpResponseException ex) {
                                        //信道重连失败后更新标记
                                        mRehandshakeSuccess = "false";
                                        //信道重连失败,则依次取消请求
                                        Iterator<CryptoHttpManager> iterator = mList.iterator();
                                        while(iterator.hasNext()){
                                            iterator.next().setCancel(true);
                                        }
                                        throw ex;
                                    }finally{
                                        //信道重连失败后更新标记
                                        mRehandshake = "false";
                                        synchronized(mList){
                                            mList.notifyAll();
                                            mList.clear();
                                        }
                                    }
                        }
                }
            }
            if("false".equals(mRehandshakeSuccess)){
                return resultObj;
            }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章