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