A02_启动测速和切换站点

news2024/11/25 11:37:13

一 业务功能请添加图片描述

二 问题

请添加图片描述

三 业务流程

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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/835169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鸟哥马哥共叙Linux发展

导读北京时间3月28日&#xff0c;由51CTO学院和人民邮电出版社信息技术分社联合举办的[开放见远]“鸟哥”大陆行Linux技术沙龙在位于北京市西三环久凌大厦的51CTO学院举行。 台湾著名Linux网站——“鸟哥的Linux私房菜”站长蔡德明&#xff0c;51CTO学院讲师马哥教育创始人马永…

EasyRecovery15简体中文个人版专业手机数据恢复软件

EasyRecovery15数据恢复软件是一款文件恢复软件&#xff0c;能够恢复内容类型非常多&#xff0c;包括办公文档、文件夹、电子邮件、照片、音频等一些常用文件类型都是可以进行恢复&#xff0c;操作非常简单&#xff0c;只需要将存储设备连接到电脑上&#xff0c;运行EasyRecove…

异常(上)概述,捕捉异常,try-catch语句的详细使用

文章目录 前言一、异常是什么&#xff1f;二、捕捉异常 1.自动捕捉异常2.try-catch语句捕捉异常 a.多重try-catch代码块b.异常的中断机制c.finally代码块恢复机制总结 前言 该文介绍了Java异常的概述&#xff0c;运行代码时&#xff0c;异常的捕捉&#xff0c;及其使用 try-cat…

QT图形视图系统 - 使用一个项目来学习QT的图形视图框架 - 始篇

文章目录 QT图形视图系统介绍开始搭建MainWindow框架设置scene的属性缩放功能的添加加上标尺 QT图形视图系统 介绍 详细的介绍可以看QT的官方助手&#xff0c;那里面介绍的详细且明白&#xff0c;需要一定的英语基础&#xff0c;我这里直接使用一个开源项目来介绍QGraphicsVi…

leetcode 738. 单调递增的数字

2023.8.4 这题用暴力法会超时&#xff0c;我就没试了&#xff0c;采用了个挺巧的方法&#xff0c;为了方便需要先将整数n转换为字符串的形式&#xff0c;然后从后向前遍历&#xff0c;当两个数字非递增时&#xff0c;将前一个数字--&#xff0c;后一个数字的位置记录在index中&…

路由的hash和history模式的区别

目录 ✅ 路由模式概述 一. 路由的hash和history模式的区别 1. hash模式 2. history模式 3. 两种模式对比 二. 如何获取页面的hash变化 ✅ 路由模式概述 单页应用是在移动互联时代诞生的&#xff0c;它的目标是不刷新整体页面&#xff0c;通过地址栏中的变化来决定内容区…

Three.js 创建网格辅助线,坐标轴辅助线,模型骨骼辅助线

three.js中的辅助线使用 1.网格辅助线&#xff08;GridHelper&#xff09; 2.坐标轴辅助线&#xff08;AxesHelper&#xff09; 3.模型骨骼辅助线(SkeletonHelper) 在上一篇 Three.js加载外部glb,fbx,gltf,obj 模型文件 的文章基础上新加入一个创建 辅助线的函数 createHel…

原型链污染例题复现

一、什么是原型链 下面我们通过这个小例子来看看。 可以看到b在实例化为test对象以后&#xff0c;就可以输出test类中的属性a了。这是因为在于js中的一个重要的概念&#xff1a;继承。而继承的整个过程就称为该类的原型链。 在javascript中,每个对象的都有一个指向他的原型(p…

CRM系统哪些功能可以个性化定制?

不同的企业有着不同的业务流程和需求&#xff0c;因此在选型时就需要一款可以个性化定制的CRM系统。下面说说可以个性化定制的CRM系统的功能和优势。 如何实现个性化定制&#xff1f; Zoho CRM支持个性化定制&#xff0c;您可以创建自定义功能模块、字段以及业务流程&#xf…

还在人工管理?太傻了!建筑行业高手给你支一招!

在现代科技日益发展的时代&#xff0c;智慧工地成为建筑行业的新兴趋势。借助先进的技术和数字化解决方案&#xff0c;智慧工地为建筑项目带来了前所未有的效率、安全性和可持续性。 智慧工地不仅提高了建筑施工的效率&#xff0c;也为管理人员提供了更好的决策依据和风险预测能…

MQTT(EMQX) - SpringBoot 整合MQTT 连接池 Demo - 附源代码 + 在线客服聊天架构图

MQTT 概述 MQTT (Message Queue Telemetry Transport) 是一个轻量级传输协议&#xff0c;它被设计用于轻量级的发布/订阅式消息传输&#xff0c;MQTT协议针对低带宽网络&#xff0c;低计算能力的设备&#xff0c;做了特殊的优化。是一种简单、稳定、开放、轻量级易于实现的消息…

DLL的引入方式(DllImport的特殊引入方式)

Dll引入方式有四种&#xff1a; 1.就是普通的比如一个解决方案中有多个项目&#xff0c;将其他项目的引入到该项目中 2.就是软件自带的程序集的引入 3.就是使用dll的引入&#xff08;普通的本身就是VS的dll文件&#xff09; 4.就是使用dll的引入&#xff08;不是属于该语言的…

网络音频终端音频编码解码终端

网络对讲终端SV-7011V 网络对讲终端SV-7011V&#xff0c;采用了ARM音频DSP架构&#xff0c;集网络对讲、网络广播、监听等功能于一身&#xff0c;内置麦克风、配置line out、line in、Mic in功能输出接口&#xff0c;适用于学校&#xff0c;机场&#xff0c;广场等场所。 产品…

解决 MySQL 删除数据后,ID 自增不连续问题

修复前 除了部分数据&#xff0c;导致后续新增的数据&#xff0c;ID 自增不连续 解决方案 执行下方 SQL 语句即可修复此问题&#xff0c;mbs_order为需要修复的表名 SET i0; UPDATE mbs_order SET id(i:i1); ALTER TABLE mbs_order AUTO_INCREMENT0;

NetApp 入门级全闪存系统 AFF A250:小巧而强大

NetApp 入门级全闪存系统 AFF A250&#xff1a;小巧而强大 作为 AFF A 系列中的入门级全闪存系统&#xff0c;AFF A250 不但可以简化数据管理&#xff0c;还能为您的所有工作负载提供令人惊叹的强劲动力&#xff0c;价格也平易近人。 AFF A250&#xff1a;您的新 IT 专家 AFF…

指向字符串常量(字符串右值)的char指针,free的时候为什么会报错?

起因是如下代码 char *p "abc"; free(p);先说结果&#xff0c;这里会报错&#xff0c;会报一个错误如下 一开始还没反应过来&#xff0c;只知道 “test_content” 是一个右值&#xff0c;这是一个指向右值的指针。 但是free的时候为什么会报错呢&#xff1f; 首…

HarmonyOS元服务开发实践:桌面卡片字典

一、项目说明 1.DEMO创意为卡片字典。 2.不同卡片显示不同内容&#xff1a;微卡、小卡、中卡、大卡&#xff0c;根据不同卡片特征显示同一个字的不同内容&#xff0c;基于用户习惯可选择喜欢的卡片。 3.万能卡片刷新&#xff1a;用户点击卡片刷新按钮查看新内容&#xff0c;同时…

NVM保姆级安装配置

nvm安装配置 1、NVM简介2、NVM安装三、NVM使用四、NVM常用命令 1、NVM简介 在项目开发过程中&#xff0c;使用到vue框架技术&#xff0c;需要安装node下载项目依赖&#xff0c;但经常会遇到node版本不匹配而导致无法正常下载&#xff0c;重新安装node却又很麻烦。为解决以上问…

浏览器调式的时候刷新页面network的日志和请求不会消失的解决办法

把“Preserve log”勾选去掉&#xff0c;F5刷新页面时&#xff0c;就是最新的日志&#xff0c;新的请求 把“Preserve log”勾上&#xff0c;F5刷新浏览器页面时&#xff0c;就会有历史日志&#xff0c;而不会消失

基于VR技术的新型实验室教学模式——VR线上生物实验室

随着科技的发展&#xff0c;虚拟现实技术已经逐渐走进了我们的生活。在教育领域中&#xff0c;虚拟现实技术也被广泛应用于各种学科的教学中。其中&#xff0c;VR线上生物实验室是广州华锐互动开发的&#xff0c;一种基于VR技术的新型教学模式&#xff0c;它能够为学生提供更加…