A02_启动测速和切换站点

一 业务功能

请添加图片描述

二 问题

请添加图片描述

三 业务流程

1 初始化网络

请添加图片描述

2 测速选站点

请添加图片描述

3 拉取站点

请添加图片描述

4 手动切换站点

请添加图片描述

四 重点代码

public class StationMeasure {


    private static final String TEST_STATION_URL = "/test/ips";
    private static final String STATION_URL = "/product/ips";
    private static final String URL = "url";

    private static final String BASE_URL = "base_url";

    /**
     * 测速定时6s返回
     */
    private static final int TASK_TIME = 6;

    /**
     * 是否正在测速,默认必须为false,保证初始化时执行
     */
    private boolean isMeasuring = false;


    /**
     * 拉取站点3s定时器
     */
    private Disposable mGetServerTimer;

    /**
     * 随机从开放站点获取站点列表的开始索引
     */
    private int mGetServerStationStart;

    /**
     * 随机从开放站点获取站点列表的当前索引
     */
    private AtomicInteger mGetServerStationIndex;

    /**
     * 是否最快的站点返回了
     */
    private boolean isMeasureFirstBack = false;

    private GetStationCallBack mStationCallBack;

    protected CompositeDisposable disposables;


    public void init() {
        if (disposables != null) {
            disposables.dispose();
        }
        disposables = new CompositeDisposable();
        setStationByRandom();
        //延迟1s执行测速
        disposables.add(Observable.timer(1, TimeUnit.SECONDS)
                .subscribeWith(new SimpleDisposableObserver<Long>() {
                    @Override
                    public void onNext(Long aLong) {
                        startMeasureAutoChange();
                    }
                }));
    }

    /**
     * 站点测速(更新站点)并自动切换站点
     */
    public void startMeasureAutoChange() {
        synchronized (this) {
            //1、若测速进行中标记为真,不执行
            if (isMeasuring) {
                return;
            }

            //2、设置测速实例的测速进行中,标记为真
            isMeasuring = true;
        }

        //Logger.d("StationMeasure> 流程开始");

        //3、重置定时任务
        if (disposables != null) {
            disposables.dispose();
        }
        disposables = new CompositeDisposable();

        disposables.add(Observable.timer(TASK_TIME, TimeUnit.SECONDS)
                .subscribeWith(new SimpleDisposableObserver<Long>() {
                    @Override
                    public void onNext(Long o) {
                        //4、定时6s执行随机选择函数
                        //Logger.d("StationMeasure> 执行定时6s随机选择函数");
                        disposables.clear();
                        isMeasuring = false;
                        setStationByRandom();
                    }
                }));
        getStation(this::measure);
    }

    /**
     * 随机选站点方法
     */
    private void setStationByRandom() {
//        Logger.d("StationMeasure> setStationByRandom");
        int len = Station.newInstance().getTcStations().length;
        Station.newInstance().switchIp(new Random().nextInt(len));
    }

    /**
     * 执行测速
     *
     * @param IPS 测速IP组
     */
    private void measure(String[][] IPS) {
        // 循环并发向可用的TC站点建立HTTP连接
        isMeasureFirstBack = false;
//        Logger.d("StationMeasure> measure 开始并发测速");
        StringBuilder url;
        for (int i = 0; i < IPS.length; i++) {
            final int index = i;
            url = new StringBuilder("http://").append(IPS[i][1]).append(":").append(IPS[i][2]);
//            Logger.d("StationMeasure> measure index=" + index + " url =" + url);
            Disposable disposable = getHttApi(url.toString())
                    .get(url.toString())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeOn(Schedulers.io())
                    .subscribeWith(new SimpleDisposableObserver<ResponseBody>() {
                        @Override
                        public void onNext(ResponseBody responseBody) {
                            if (!isMeasureFirstBack) {
                                measureEnd(index);
                            }
                        }

                    });
            disposables.add(disposable);
        }
    }

    private void measureEnd(int index) {
//        Logger.d("StationMeasure> 流程结束  index=" + index);

        isMeasureFirstBack = true;
        isMeasuring = false;
        disposables.clear();
        Station.newInstance().switchIp(index);
    }

    /**
     * 获取站点
     *
     * @param callBack 获取站点回调
     */
    private void getStation(GetStationCallBack callBack) {
        //1、随机(分摊服务器压力)开始遍历
        mStationCallBack = callBack;
        final int start = new Random().nextInt(Station.newInstance().getTcStations().length);
        mGetServerStationIndex = new AtomicInteger();
        mGetServerStationIndex.getAndSet(start);
        mGetServerStationStart = start;
//        Logger.d("StationMeasure> getStation 随机拉取开放 mGetServerStationIndex=" + mGetServerStationIndex);

        //2、设置3s超时
        if (mGetServerTimer != null) {
            mGetServerTimer.dispose();
        }
        mGetServerTimer = Observable.timer(3, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeWith(new SimpleDisposableObserver<Long>() {

                    @Override
                    public void onNext(Long aLong) {
//                        Logger.d("StationMeasure> getStation 3s定时执行");

                        if (mGetServerTimer != null) {
                            mGetServerTimer.dispose();
                        }
                        if (mStationCallBack != null) {
                            mStationCallBack.getStationCallBack(Station.newInstance().getTcStations());
                            mStationCallBack = null;
                        }
                    }
                });

        //3、 拉取站点请求
        getIpFromServer();
    }

    /**
     * 1、设置IP:先读取缓存,缓存没有设置写死
     * 2、随机索引,循环请求开放接口获取站点,直到一个请求成功
     * 3、将请求成功的IP组缓存本地并设置APP站点
     * {
     * "eno": [
     * ["电信", "1.1.1.1", "83", "1", "DX"],
     * ["联通", "1.1.1.1", "83", "1", "LT"],
     * ["移动",  "1.1.1.1", "83", "1", "YD"]
     * ],
     * "open": [
   	 *	["电信", "1.1.1.1", "83", "1", "DX"],
     * 	["联通", "1.1.1.1", "83", "1", "LT"],
     * 	["移动",  "1.1.1.1", "83", "1", "YD"]
     * }
     */
    private void getIpFromServer() {
        String[][] openStation = Station.newInstance().getOpenStations();
        Map<String, String> map = getUrlFormIp(openStation[mGetServerStationIndex.get() % openStation.length]);
      //  Logger.e("StationMeasure> getIpFromServer URL=" + map.get(URL));
        //要设置3s
        getHttApi(map.get(BASE_URL)).get(map.get(URL))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new SimpleDisposableObserver<ResponseBody>() {
                    @Override
                    public void onNext(ResponseBody responseBody) {
                        try {
                            String data = responseBody.string();
                            if (Station.newInstance().setStationFromData(data)) {
//                                Logger.d("StationMeasure> getIpFromServer 拉取站点成功 data=" + data);
                                Station.newInstance().updateStationCache(data);
                                if (mStationCallBack != null) {
                                    if (mGetServerTimer != null) {
                                        mGetServerTimer.dispose();
                                    }
                                    mStationCallBack.getStationCallBack(Station.newInstance().getTcStations());
                                }
                            } else {
                                goOn();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            goOn();
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        super.onError(e);
                        goOn();
                    }


                });
    }

    private Map<String, String> getUrlFormIp(String[] ips) {
        Map<String, String> map = new HashMap<>();
        try {
            StringBuilder url = new StringBuilder("https://");

            url.append(ips[1]);
            url.append(":");
            url.append(ips[2]);
            map.put(BASE_URL, url.toString());
            url.append(BuildConfig.DEBUG ? TEST_STATION_URL : STATION_URL);
            map.put(URL, url.toString());

        } catch (Exception e) {
            e.printStackTrace();
            goOn();
        }

        return map;
    }

    private void goOn() {
        mGetServerStationIndex.getAndIncrement();
        if (mGetServerStationIndex.get() >= Station.newInstance().getTcStations().length + mGetServerStationStart) {
            //遍历所有站点,没有成功
            if (mStationCallBack != null) {
                mStationCallBack.getStationCallBack(Station.newInstance().getTcStations());
                mStationCallBack = null;
                if (mGetServerTimer != null) {
                    mGetServerTimer.dispose();
                }
            }

            return;
        }
        getIpFromServer();
    }


    public static HttpApi getHttApi(String url) {
        OkHttpClient.Builder builder = OKHttp.getOkHttpClient(3).newBuilder();
        builder.addInterceptor(new CommonParamsInterceptor());
        return new Retrofit.Builder()
                .client(builder.build())
                .baseUrl(url)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build().create(HttpApi.class);
    }

    public static StationMeasure newInstance() {
        return StationMeasureHolder.instance;
    }

    private StationMeasure() {
    }

    private static class StationMeasureHolder {
        static StationMeasure instance = new StationMeasure();
    }

    /**
     * 拉取站点后回调
     */
    private interface GetStationCallBack {
        void getStationCallBack(String[][] IPS);
    }
}

五 测速相关场景

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值