检查当前手机的网络延迟

原理:周期性的ping一个网络地址,计算出连接时间,估算出当前的网络延迟状况。

工具类代码:

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by tonglin on 2018/3/27.
 */

public class NetPingManager {
    private String mDomain; // 接口域名
    private InetAddress[] mAddress;
    private List mAddressIpList;
    private IOnNetPingListener mIOnNetPingListener; // 将监控日志上报到前段页面
    private HandlerThread mHandlerThread;

    private static int DELAY_TIME = 3000;
    private ConnectivityManager manager;
    private final Handler mHandleMessage;
    private static final String url = "www.baidu.com";

    /**
     * 延迟
     */
    public void setDuration(int delay) {
        DELAY_TIME = delay;
    }

    /**
     * 初始化网络诊断服务
     */
    public NetPingManager(Context context, String domain, IOnNetPingListener theListener) {
        if (TextUtils.isEmpty(domain)) {
            this.mDomain = url;
        } else {
            this.mDomain = domain;
        }
        this.mIOnNetPingListener = theListener;
        this.mAddressIpList = new ArrayList<>();
        if (null != context)
            this.manager = (ConnectivityManager) context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        this.mHandlerThread = new HandlerThread("ping");
        this.mHandlerThread.start();
        this.mHandleMessage = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 0:
                        //每次请求清空上传集合
                        if (null != mAddressIpList) {
                            if (null != mAddressIpList) {
                                mAddressIpList.clear();
                                startNetDiagnosis();
                            }
                        }
                        if (null != mHandlerThread)
                            mHandleMessage.sendEmptyMessageDelayed(0, DELAY_TIME);
                        break;
                }
            }
        };
    }


    public void getDelay() {
        if (null != this.mHandleMessage) {
            this.mHandleMessage.sendEmptyMessage(0);
        }
    }


    public void release() {
        synchronized (NetPingManager.class) {
            if (null != this.manager)
                this.manager = null;
            if (null != this.mHandleMessage) {
                this.mHandleMessage.removeMessages(0);
            }
            if (null != mHandlerThread) {
                Looper looper = this.mHandlerThread.getLooper();
                if (looper != null) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        looper.quitSafely();
                    } else {
                        looper.quit();
                    }
                }
            }
            this.mHandlerThread = null;
            this.mIOnNetPingListener = null;
            if (null != mAddressIpList)
                mAddressIpList.clear();
            this.mAddressIpList = null;
            this.manager = null;
        }
    }

    /**
     * 监控网络诊断的跟踪信息
     */
    public interface IOnNetPingListener {
        void onDelay(long log, int type);

        void onError();
    }


    /**
     * 开始诊断网络
     */
    private void startNetDiagnosis() {
        if (!TextUtils.isEmpty(this.mDomain)) {
            // 网络状态
            if (isNetworkConnected()) {
                parseDomain(this.mDomain);// 域名解析
                // TCP三次握手时间测试
                execUseJava();

            } else {
                if (null != mIOnNetPingListener)
                    mIOnNetPingListener.onError();
                LogUtil.e("netping", "当前主机未联网,请检查网络!");
            }
        }
    }

    /**
     * 使用java执行connected
     */
    private boolean execUseJava() {
        if (mAddress != null && mAddressIpList != null && !mAddressIpList.isEmpty()) {
            int len = mAddress.length;
            if (len > 0) {
                execIP(mAddress[0], mAddressIpList.get(0));
            }
        }
        return false;
    }

    private static final int PORT = 80;
    private static final int CONN_TIMES = 4;
    // 设置每次连接的timeout时间
    private int TIME_OUT = 6000;
    private final long[] RttTimes = new long[CONN_TIMES];// 用于存储三次测试中每次的RTT值

    /**
     * 返回某个IP进行5次connect的最终结果
     */
    private boolean execIP(InetAddress inetAddress, String ip) {
        boolean isConnected = true;
        InetSocketAddress socketAddress;
        if (inetAddress != null && ip != null) {
            socketAddress = new InetSocketAddress(inetAddress, PORT);
            int flag = 0;
            for (int i = 0; i < CONN_TIMES; i++) {
                execSocket(socketAddress, i);
                if (RttTimes[i] == -1) {// 一旦发生timeOut,则尝试加长连接时间
                    TIME_OUT += 4000;
                    if (i > 0 && RttTimes[i - 1] == -1) {// 连续两次连接超时,停止后续测试
                        flag = -1;
                        break;
                    }
                } else if (RttTimes[i] == -2) {
                    if (i > 0 && RttTimes[i - 1] == -2) {// 连续两次出现IO异常,停止后续测试
                        flag = -2;
                        break;
                    }
                }
            }
            long time = 0;
            int count = 0;
            if (flag == -1) {
                isConnected = false;
            } else if (flag == -2) {
                isConnected = false;
            } else {
                for (int i = 0; i < CONN_TIMES; i++) {
                    if (RttTimes[i] > 0) {
                        time += RttTimes[i];
                        count++;
                    }
                }
                if (count > 0) {
                    if (mIOnNetPingListener != null) {
                        int delay = (int) (time / count);
                        int type;
                        if (delay <= 100) {
                            type = 1;
                        } else if (delay <= 200) {
                            type = 2;
                        } else {
                            type = 3;
                        }
                        mIOnNetPingListener.onDelay(delay, type);
                    }
                }
            }
        } else {
            isConnected = false;
        }
        return isConnected;
    }


    /**
     * 针对某个IP第index次connect
     */
    private void execSocket(InetSocketAddress socketAddress, int index) {

        long start;
        long end;
        Socket mSocket = new Socket();
        try {
            start = System.currentTimeMillis();
            mSocket.connect(socketAddress, TIME_OUT);
            end = System.currentTimeMillis();
            RttTimes[index] = end - start;
        } catch (SocketTimeoutException e) {
            RttTimes[index] = -1;// 作为TIMEOUT标识
            e.printStackTrace();
        } catch (IOException e) {
            RttTimes[index] = -2;// 作为IO异常标识
            e.printStackTrace();
        } finally {
            if (mSocket != null) {
                try {
                    mSocket.close();
                } catch (IOException io) {
                    io.printStackTrace();
                }
            }
        }
    }

    /**
     * 判断网络是否连接
     */
    private Boolean isNetworkConnected() {
        if (manager == null)
            return false;
        NetworkInfo networkinfo = manager.getActiveNetworkInfo();
        return !(networkinfo == null || !networkinfo.isAvailable());
    }


    /**
     * 域名解析
     */
    private boolean parseDomain(String domain) {
        boolean flag = false;
        Map, Object> map = getDomainIp(domain);
        String useTime = (String) map.get("useTime");
        mAddress = (InetAddress[]) map.get("remoteInet");
        if (mAddress != null && mAddressIpList != null && mAddress.length > 0) {// 解析正确
            if (!TextUtils.isEmpty(mAddress[0].getHostAddress())) {
                mAddressIpList.add(mAddress[0].getHostAddress());
                flag = true;
            }

        } else {// 解析不到,判断第一次解析耗时,如果大于10s进行第二次解析
            if (Integer.parseInt(useTime) > 10000) {
                map = getDomainIp(domain);
                mAddress = (InetAddress[]) map.get("remoteInet");
                if (mAddress != null && mAddressIpList != null && mAddress.length > 0) {
                    if (!TextUtils.isEmpty(mAddress[0].getHostAddress())) {
                        mAddressIpList.add(mAddress[0].getHostAddress());
                        flag = true;
                    }
                }
            }
        }
        return flag;
    }

    /**
     * 解析IP
     */
    private Map, Object> getDomainIp(String domain) {
        Map, Object> map = new HashMap<>();
        long start = 0;
        long end;
        String time = null;
        InetAddress[] remoteInet = null;
        try {
            start = System.currentTimeMillis();
            remoteInet = InetAddress.getAllByName(domain);
            if (remoteInet != null) {
                end = System.currentTimeMillis();
                time = (end - start) + "";
            }
        } catch (UnknownHostException e) {
            end = System.currentTimeMillis();
            time = (end - start) + "";
            remoteInet = null;
            e.printStackTrace();
        } finally {
            map.put("remoteInet", remoteInet);
            map.put("useTime", time);
        }
        return map;
    }
}

使用方法:实例化NetPingManager,然后调用getDelay()方法

NetPingManager net = new NetPingManager(getApplicationContext(), "www.baidu.com",
 new NetPingManager.IOnNetPingListener() {
            @Override
            public void onDelay(long delay, int type) {
                if (!isDestroyed() && !isFinishing() && tvdelay != null) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            switch (type) {
                                case 1:
                                    tvdelay.setTextColor(Color.parseColor("#A7FC3F"));
                                    ABViewUtil.setTextViewLeftDrawable(R.drawable.nvb_icon_speed1, tvdelay);
                                    break;
                                case 2:
                                    tvdelay.setTextColor(Color.parseColor("#FFF34A"));
                                    ABViewUtil.setTextViewLeftDrawable(R.drawable.nvb_icon_speed2, tvdelay);
                                    break;
                                case 3:
                                    tvdelay.setTextColor(Color.parseColor("#FF0000"));
                                    ABViewUtil.setTextViewLeftDrawable(R.drawable.nvb_icon_speed3, tvdelay);
                                    break;
                                default:
                                    ABViewUtil.setTextViewLeftDrawable(R.drawable.nvb_icon_speed1, tvdelay);
                                    break;
                            }
                            tvdelay.setText(String.valueOf(delay) + " ms");
                        }
                    });
                }
            }

            @Override
            public void onError() {
                LogUtil.i("tag", "无网络");
            }
        });
        if (netPingManager != null) {
            netPingManager.getDelay();
        }

你可能感兴趣的:(android)