在Android开发中,检测设备和服务器之间的网络连通性是一项常见且重要的任务。利用Ping命令,可以快速诊断网络问题并确保应用的网络请求流畅。

简介

ping(Packet Internet Grouper)是一种因特网包探测器,用于测试网络连接量的程序,Ping是工作在TCP/IP网络体系结构中应用层的服务命令,主要是向特定的目的服务器发送ICMP(Internet Control Message Protocol 因特网报文控制协议)Echo 请求报文,测试目的站是否可达及了解其有关状态。

检测网络必要性

最常见的现象是,假如我们用手机连接一个路由器,路由器没有插网线,这时如果我们使用Android常用的api,检测网络是否连接,判断是否可用,毫无疑问,最后返回的都是true,当我们请求接口的时候可能就是无法访问。在日常工作中,这种问题也会经常碰到,当我们一切准备就绪,提交给测试,结果他说没法加载数据,其实就是网络不好,数据没请求成功而已,所以检测网络状态,ui层给出提示是很有必要的。

Android执行Ping命令

在Android常用的有两种方式执行ping命令使用Runtime.getRunTime().exec(),或者使用ProcessBuilder,这里以第一种方式为例:
假如我们现在ping谷歌服务器的连通性:

Runtime.getRuntime().exec("www.google.com")

我们也可以加入参数比如发送的数据,超时时间等

ping -c 3 -i 2 -s 100 -t 64 -w 10 -q www.google.com

上面这行命令的参数含义:
ping: 是一个常用的网络工具,它用来测试另一台计算机是否可通过IP网络到达。
-c 3: 指定发送的回显请求数量为3次。
-i 2: 设置每次ping请求之间的间隔时间为2秒。
-s 100: 设置每次ping发送的数据包大小为100字节。
-t 64: 设置Time-to-Live(TTL)为64。TTL是数据包在网络中可以经过的最大路由器数目;每当数据包经过一个路由器,其值就减1,当值降至0时,该数据包将被丢弃。
-w 10: 设置总的超时时间为10秒。这指的是ping命令执行的总时长,而不是单次ping请求的超时时间。
-q: 安静输出。不显示每次回显请求的详细信息,只在摘要中打印最小、最大以及 平均延迟。
www.google.com: 这是要测试连接的目标主机名称或IP地址。
将上述选项结合在一起,这条命令的意思是通过向www.google.com发送3个数据包,每个数据包的大小为100字节,那每隔2秒发送一个,TTL值设置为64,并且将整个命令的执行时间限制在10秒内,执行过程中不显示详细的ping请求回应的数据,只在最后提供汇总信息。

完整示例

public class NetWorkCheck implements Runnable {
    private static final String TAG = "NetWorkCheck";
    private final String mIpAddress;
    private final Consumer<NetworkSingle> mCallback;

    public NetWorkCheck(String ipAddress, Consumer<NetworkSingle> callback) {
        this.mIpAddress = ipAddress;
        this.mCallback = callback;
    }


    @Override
    public void run() {
        try {
            ping();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void ping() {
        String cmd = "";
        NetworkSingle single = NetworkSingle.NONE;
        BufferedReader in = null;
        //ping -c 3 -i 2 -s 100 -t 64 -w 10 -q www.google.com
        try {
            cmd = "ping -c 3 -i 2 -s 100 -t 64 -w 10 -q " + mIpAddress;
            Log.d(TAG, cmd);
            Process myProcess = Runtime.getRuntime().exec(cmd);
            in = new BufferedReader(new InputStreamReader(myProcess.getInputStream()));
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("result=  " + inputLine);
                // 3 packets transmitted, 3 received, 0% packet loss, time 4006ms
                // rtt min/avg/max/mdev = 51.957/62.180/74.437/9.289 ms
                if (inputLine.contains("packet loss")) {
                    int start = inputLine.indexOf("received,") + 10;
                    int end = inputLine.indexOf("%");
                    String packetLoss = inputLine.substring(start, end).trim();
                    int packetLossValue = Integer.parseInt(packetLoss);
                    if (packetLossValue == 0) {
                        single = NetworkSingle.GREAT;
                    } else if (packetLossValue < 30) {
                        single = NetworkSingle.GOOD;
                    } else if (packetLossValue < 50) {
                        single = NetworkSingle.BAD;
                    }
                }
            }
            System.out.println("Cannot reach " + mIpAddress);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        mCallback.accept(single);
    }


}

定时检测

通过上面示例,知道了如何使用ping检测连通性,接下来就需要开启定时任务轮询检测,我通过android提供的ScheduledExecutorService,执行定时任务,示例如下:

public class GoogleNetTaskManager {
    private final ScheduledExecutorService executorService;

    public GoogleNetTaskManager(int numThreads) {
        executorService = Executors.newScheduledThreadPool(numThreads);
    }

    public void scheduleAtFixedRate(Runnable runnable, long initialDelay, long period,
                                    TimeUnit unit) {
        try {
            executorService.scheduleAtFixedRate(runnable, initialDelay, period, unit);
        }catch (Exception e){
            AtotoLogger.e("Ping server error = "+e.getMessage());
        }

    }

    public void shutdown() {
        executorService.shutdown();
    }
}

开启定时任务:

private final GoogleNetTaskManager mGoogleNetTaskManager;
mGoogleNetTaskManager = new GoogleNetTaskManager(5);mGoogleNetTaskManager = new GoogleNetTaskManager(5);
mGoogleNetTaskManager.scheduleAtFixedRate(new NetWorkCheck(ApiConfig.URL_PING_ADDRESS,
                        StatusHolder.networkSingle::postValue), 0, 10,
                TimeUnit.SECONDS);

总结

以上就是在Android中检测网络连通性的主要流程,需要特别注意的就是需要加入网络权限,在不需要的时候记得关闭定时任务,如果您觉得对您有帮助,记得点赞加关注。