IM推送Android客户端之重连策略

话不多直接进入主题

所谓重连就是Android客户端额度TCP连接断开之后自动进行连接,但是有时候会遇到一直重连不上的情况,那么就不能一直频繁的进行重连操作,毕竟在手机休眠的时候重连操作可能会有网络数据通信,手机会被唤醒,等重连操作完成后手机才会再进入休眠,所以频繁的重连会导致手机频繁的唤醒,耗电量妥妥的就上来了。

重连策略

  • 重连分两种,一种是连接断开重连,另一种是连接成功后秒断重连,连接成功秒断重连的意思是,重连成功,但是连接维持很小一段时间就又断开了,这时候也要有递增的时间间隔策略
  • 重连之前先判断手机是否有网络连接,如果没有则不继续进行重连操作
  • 如果一直重连失败,那么下一次的重连时间和之前的重连时间之间的间隔要不断的递增,最终稳定在一个较大的区间之内,如果仍然连接不上,那么就一直以这个较大的重连间隔时间去进行重连
  • 考虑到秒断情况,如果重连操作能成功连接上,但是连接不久之后又再次断开,之后要再次进行重连,断开和再次重连之间的时间间隔也要做限制,否则会导致重连成功,之前累计的时间间隔清零,连接又断开,然后连接间隔又从0开始计时

连接断开的重连时间间隔的随机算法

private AtomicInteger connectPeriodTag = new AtomicInteger(0);

private float connectTaskPeriod;

private void randomConnectPeriod() {
        int start = (int) (Math.pow(2, connectPeriodTag.get()) * 1000);
        int end = (int) (Math.pow(2, connectPeriodTag.get() + 1) * 1000);
        connectTaskPeriod = RandomUtil.getRandom(start, end);
        if (connectTaskPeriod >= 20 * 60 * 1000) {
            connectTaskPeriod = 20 * 60 * 1000;
        } else {
            connectPeriodTag.incrementAndGet();
            SyncLogUtil.i("to increment the connectPeriodTag:" + connectPeriodTag.get() + ",connectTaskPeriod:" + connectTaskPeriod);
        }
        SyncLogUtil.i("connect task period is [" + TimeFormatUtil.format((long) connectTaskPeriod) + "]");
    }

在连接成功后就把connectPeriodTag 重新设置成0,这样假如将来连接又断开了,连接间隔的计算又从0开始,保证在正常情况下连接断开后能及时重连,如果这次没有重连成功,那么connectPeriodTag 递增1,然后再计算下次重连间隔,最大的稳定时间间隔为20分钟,也就是说如果一直重连失败,那程序最后就会每隔20分钟再进行一次重连

连接秒断的重连时间间隔随机算法

随机算法和上面的是一样的,具体做法是连接成功后记录下连接成功的时间点,然后下次再进行重连的时候首先判断一下此时的时间和上一次连接成功的时间间隔是否在一个较小的时间段内,如果是则计算秒断时间间隔算法,如果不是就把秒断时间间隔算法里面的tag设置成0,演示代码如下:

private void reconnect() {
        SyncLogUtil.d("reconnect...");
        long lastConnectPeriod = System.currentTimeMillis() - lastConnectTime;
        SyncLogUtil.i("lastConnectPeriod:" + lastConnectPeriod);
        // 避免连接连接成功后又断开,然后又进行重连导致短时间内重连频率太高而给服务器带来的并发压力
        if (lastConnectPeriod < reconnectPeriodLimit) {
            // 用闹钟来唤醒重连
            startReconnectAlarm(hostInfo);
        } else {
            reconnectPeriodTag.set(0);
            connect(hostname(), port(), true, null);
        }
    }

之所以选择随机算法的原因是尽量避开多台设备在同一时间点触发重连,因为每次运行随机算法所产生的时间间隔都不同,所以在多台设备上也都会产生不同的重连时间间隔,降低了同一时刻因为多台设备触发重连给服务器造成的并发压力,上述的随机算法运行的效果如下:
第一次运行:
1451.5292毫秒,00:00:01
2339.7693毫秒,00:00:02
6769.3306毫秒,00:00:06
15956.557毫秒,00:00:15
17409.965毫秒,00:00:17
47527.496毫秒,00:00:47
96241.05毫秒,00:01:36
195035.5毫秒,00:03:15
270967.44毫秒,00:04:30
685830.0毫秒,00:11:25
1200000.0毫秒,00:20:00
1179013.6毫秒,00:19:39
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00

第二次运行:
1578.5051毫秒,00:00:01
3575.9648毫秒,00:00:03
4001.7532毫秒,00:00:04
10672.303毫秒,00:00:10
21160.8毫秒,00:00:21
43281.56毫秒,00:00:43
98480.76毫秒,00:01:38
163748.23毫秒,00:02:43
279018.8毫秒,00:04:39
835901.8毫秒,00:13:55
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1180800.1毫秒,00:19:40

第三次运行:
1965.0104毫秒,00:00:01
3987.2378毫秒,00:00:03
6056.092毫秒,00:00:06
15700.957毫秒,00:00:15
27048.209毫秒,00:00:27
40336.637毫秒,00:00:40
106045.37毫秒,00:01:46
249301.33毫秒,00:04:09
458808.22毫秒,00:07:38
992412.1毫秒,00:16:32
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1140937.8毫秒,00:19:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
1200000.0毫秒,00:20:00
从上面的运行效果来看是随着重连次数的增加,时间间隔会不断的变大,而且变大的幅度也增加了,最终会稳定在20分钟

测试运行的代码:

public class ReconnectPeriodTest {

    private static AtomicInteger connectPeriodTag = new AtomicInteger(0);

    private static float connectTaskPeriod;

    public static void main(String[] args) {
        while(true) {
            randomConnectPeriod();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private static void randomConnectPeriod() {
        int start = (int) (Math.pow(2, connectPeriodTag.get()) * 1000);
        int end = (int) (Math.pow(2, connectPeriodTag.get() + 1) * 1000);
        connectTaskPeriod = getRandom(start, end);
        if (connectTaskPeriod >= 20 * 60 * 1000) {
            connectTaskPeriod = 20 * 60 * 1000;
        } else {
            connectPeriodTag.incrementAndGet();
        }
        System.out.println(connectTaskPeriod + "毫秒," + format((long) connectTaskPeriod));
    }

    public static float getRandom(int min, int max) {
        Random random = new Random();
        return (float) (random.nextDouble() * (max - min) + min);
    }

    public static String format(long milliseconds) {
        if (milliseconds < 1000) {
            milliseconds = 1000;
        }
        Date date = new Date(milliseconds - 8 * 3600 * 1000);
        return new SimpleDateFormat("HH:mm:ss").format(date);
    }
}

猜你喜欢

转载自blog.csdn.net/lhd201006/article/details/52816532