Android Traceroute 功能实现
经常在windows下开发网络功能的人 经常会使用的命令就是tracert 。而实际上 在app开发中,我们也经常要碰到类似的情况。比如你的app
出现了问题,你总不能让用户想办法 去tracert吧。你肯定要知道你的app 是在网络中的哪一个部分出了问题。我举个最简单的例子。国内有很多做外包的
公司 在开发过程中 需要调用 facebook 等公司提供的sdk 或者接口。当然了 我们 在天朝吗 所以我们在做类似功能的时候 一般要使用vpn来访问。
但是很多vpn的情况 也是很不稳定的,在开发过程中 能否迅速的找到网络不通的原因 是很重要的。尤其是你给欠发达地区 的客户在开发app的时候
一旦网络连接不同,你怎么证明你的app 是运行正常的 ,是他们的网络基础不正常?
那我们今天就来看一下如果在android app下面实现这个tracert功能。
首先我们想到的肯定是 实现一下tracert这个命令的java版,但实际上 我们在网络上找不到类似的资源,自己去实现包括icmp 报文之类的又比较麻烦(日后我会自己实现一份)
所以我们想到 android 是基于linux的 为何不直接调用这个命令呢?我们取得tracert的结果不就行了吗,但实际上很多linux 版本是没有 tracert的这个命令的。
当然了 很多人会说 linux下是叫 Traceroute 这个命令的,但是很遗憾的是多数android 手机内置命令都不包含这个。。。。
经过一番思索 我决定 用ping 命令的参数 来实现 Traceroute 这个功能。 其实主要是 -t 和 -c 这2个参数了。另外就是对ttl 这个值有一定的理解 即可实现类似于
Traceroute 的功能。
代码如下:
package com.example.traceroute; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List; import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText; public class MainActivity extends Activity { // 输入网址框
private EditText et; // 开始traceroute的button
private Button searchButton; // 最大的ttl跳转 可以自己设定
private final int MAX_TTL = 30; // 都是一些字符串 用于parse 用的
private static final String PING = "PING";
private static final String FROM_PING = "From";
private static final String SMALL_FROM_PING = "from";
private static final String PARENTHESE_OPEN_PING = "(";
private static final String PARENTHESE_CLOSE_PING = ")";
private static final String TIME_PING = "time=";
private static final String EXCEED_PING = "exceed";
private static final String UNREACHABLE_PING = "100%"; // 初始化默认ttl 为1
private int ttl = 1;
private String ipToPing;
// ping耗时
private float elapsedTime; // 存放结果集的tarces
private List<TracerouteContainer> traces = new ArrayList<TracerouteContainer>();; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) this.findViewById(R.id.input);
searchButton = (Button) this.findViewById(R.id.search);
searchButton.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ExecuteTracerouteAsyncTask(MAX_TTL, et.getText().toString())
.execute();
}
});
} private void showResultInLog() {
for (TracerouteContainer container : traces) {
Log.v("ccc", container.toString());
}
} /**
* 这个任务就是来更新我们的后台log 日志 把所得到的traceroute信息打印出来。
*
*/
private class ExecuteTracerouteAsyncTask extends
AsyncTask<Void, Void, String> { private int maxTtl; private String url; public ExecuteTracerouteAsyncTask(int maxTtl, String url) {
this.maxTtl = maxTtl;
this.url = url;
} /**
* 后台所做的工作 本质就是调用 ping命令 来完成类似traceroute的功能
*/
@Override
protected String doInBackground(Void... params) {
String res = "";
try {
res = launchPing(url);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
TracerouteContainer trace; if (res.contains(UNREACHABLE_PING) && !res.contains(EXCEED_PING)) {
trace = new TracerouteContainer("", parseIpFromPing(res),
elapsedTime);
} else {
trace = new TracerouteContainer("", parseIpFromPing(res),
ttl == maxTtl ? Float
.parseFloat(parseTimeFromPing(res))
: elapsedTime);
} InetAddress inetAddr;
try {
inetAddr = InetAddress.getByName(trace.getIp());
String hostname = inetAddr.getHostName();
trace.setHostname(hostname);
} catch (UnknownHostException e) {
e.printStackTrace();
}
traces.add(trace);
return res;
} private String launchPing(String url) throws IOException {
Process p;
String command = ""; // 这个实际上就是我们的命令第一封装 注意ttl的值的变化 第一次调用的时候 ttl的值为1
String format = "ping -c 1 -t %d ";
command = String.format(format, ttl); long startTime = System.nanoTime();
// 实际调用命令时 后面要跟上url地址
p = Runtime.getRuntime().exec(command + url);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(
p.getInputStream())); String s;
String res = "";
while ((s = stdInput.readLine()) != null) {
res += s + "\n";
// 这个地方这么做的原因是 有的手机 返回的from 有的手机返回的是From所以要
// 这么去判定 请求结束的事件 算一下 延时
if (s.contains(FROM_PING) || s.contains(SMALL_FROM_PING)) {
elapsedTime = (System.nanoTime() - startTime) / 1000000.0f;
}
} // 调用结束的时候 销毁这个资源
p.destroy(); if (res.equals("")) {
throw new IllegalArgumentException();
}
// 第一次调用ping命令的时候 记得把取得的最终的ip地址 赋给外面的ipToPing
// 后面要依据这个ipToPing的值来判断是否到达ip数据报的 终点
if (ttl == 1) {
ipToPing = parseIpToPingFromPing(res);
}
return res;
} @Override
protected void onPostExecute(String result) {
// 如果为空的话就截止吧 过程完毕
if (TextUtils.isEmpty(result)) {
return;
} // 如果这一跳的ip地址与最终的地址 一致的话 就说明 ping到了终点
if (traces.get(traces.size() - 1).getIp().equals(ipToPing)) {
if (ttl < maxTtl) {
ttl = maxTtl;
traces.remove(traces.size() - 1);
new ExecuteTracerouteAsyncTask(maxTtl, url).execute();
} else {
// 如果ttl ==maxTtl的话 当然就结束了 我们就要打印出最终的结果
showResultInLog();
}
} else {
// 如果比较的ip 不相等 哪就说明还没有ping到最后一跳。我们就需要继续ping
// 继续ping的时候 记得ttl的值要加1
if (ttl < maxTtl) {
ttl++;
new ExecuteTracerouteAsyncTask(maxTtl, url).execute();
}
}
super.onPostExecute(result);
} } /**
* 从结果集中解析出ip
*
* @param ping
* @return
*/
private String parseIpFromPing(String ping) {
String ip = "";
if (ping.contains(FROM_PING)) {
int index = ping.indexOf(FROM_PING); ip = ping.substring(index + 5);
if (ip.contains(PARENTHESE_OPEN_PING)) {
int indexOpen = ip.indexOf(PARENTHESE_OPEN_PING);
int indexClose = ip.indexOf(PARENTHESE_CLOSE_PING); ip = ip.substring(indexOpen + 1, indexClose);
} else {
ip = ip.substring(0, ip.indexOf("\n"));
if (ip.contains(":")) {
index = ip.indexOf(":");
} else {
index = ip.indexOf(" ");
} ip = ip.substring(0, index);
}
} else {
int indexOpen = ping.indexOf(PARENTHESE_OPEN_PING);
int indexClose = ping.indexOf(PARENTHESE_CLOSE_PING); ip = ping.substring(indexOpen + 1, indexClose);
} return ip;
} /**
* 从结果集中解析出ip
*
* @param ping
* @return
*/
private String parseIpToPingFromPing(String ping) {
String ip = "";
if (ping.contains(PING)) {
int indexOpen = ping.indexOf(PARENTHESE_OPEN_PING);
int indexClose = ping.indexOf(PARENTHESE_CLOSE_PING); ip = ping.substring(indexOpen + 1, indexClose);
} return ip;
} /**
* 从结果集中解析出time
*
* @param ping
* @return
*/
private String parseTimeFromPing(String ping) {
String time = "";
if (ping.contains(TIME_PING)) {
int index = ping.indexOf(TIME_PING); time = ping.substring(index + 5);
index = time.indexOf(" ");
time = time.substring(0, index);
} return time;
} }
其实代码本身并没有多复杂 主要是要对linux有一定了解 另外要会在adb shell 下面调试你的命令结果。分析结果集。
Android Traceroute 功能实现的更多相关文章
- [译]:Xamarin.Android平台功能——位置服务
返回索引目录 原文链接:Location Services. 译文链接:Xamarin.Android平台功能--位置服务 本部分介绍位置服务以及与如何使用位置提供商服务 Location Servi ...
- Android表情功能
Android表情功能 标签(空格分隔): 未分类 转载自:android edittext插入表情(基于socket方式),并对文中不正确的内容进行整理和修正 [TOC] 涉及知识点: Androi ...
- Cocos2d-x使用android拍照功能加载照片内存过大,通过另存照片尺寸大小解决
使用2dx调用android拍照功能,拍照结束后在2dx界面显示拍照照片,如果不对照片做处理,会出现内存过大的问题,导致程序崩溃,如果仅仅另存拍照照片,则照片质量大小均下降,导致照片不够清晰,后来发现 ...
- Android定位功能
不说废话,直接说说实现android定位有关的API吧. 这些API都在android.location包下,一共有三个接口和八个类.它们配合使用即可实现定位功能. 三个接口: GpsStatus.L ...
- Android定位功能(二)
在前文Android定位功能(一)中,已经大致介绍了一下在Android平台中,和定位功能相关的类,并举例获取了位置信息.但是前文是基于Criteria定制了一个标准,通过getBestProvide ...
- Android P 功能和 API
Android P 功能和 API Android P 为用户和开发者引入众多新特性和新功能. 本文重点介绍面向开发者的新功能. 要了解新 API,请阅读 API 差异报告或访问 Android AP ...
- Delphi xe7 up1 调用android振动功能
Delphi xe7 up1 调用android振动功能 振动用到以下4个单元: Androidapi.JNI.App,Androidapi.JNIBridge,Androidapi.JNI.Os,A ...
- 我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(三)Android客户端功能实现
我的Android进阶之旅------>Android实现用Android手机控制PC端的关机和重启的功能(一)PC服务器端(地址:http://blog.csdn.net/ouyang_pen ...
- android nfc功能开发
链接:Android NFC开发详细总结 https://blog.csdn.net/zhwadezh/article/details/79111348 链接2:Android NFC功能 简单实 ...
随机推荐
- Linux网络编程6——使用TCP实现文件服务器
需求 当客户端连接上服务器后,服务器会将相应文件传输给客户端,实现文件下载. 思路 服务器端,主进程负责listen.循环内,主进程每从任务请求队列中accept出一个请求,就fork出孙子完成文件传 ...
- Linux:-bash: ***: command not found
Linux:-bash: ***: command not found,系统很多命令都用不了,均提示没有此命令. 突然之间linux很多命令都用不了,均提示没有此命令. 这应该是系统环境变量出现了问题 ...
- Java7编程高手进阶读书笔记—集合框架
定义:Java集合框架API是用来表示和操作集合的统一框架,它包含接口.实现类.以及帮助程序员完成一些编程的算法 作用: ●编程更加省力,提高城程序速度和代码质量 ● 非关联的API提高互操作性 ● ...
- Linux进程间通信(IPC)
序言 linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的. 而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心) ...
- java消息队列
来个个人通俗的解释吧.消息队列,顾名思义 首先是个队列.队列的操作有入队和出队 也就是你有一个程序在产生内容然后入队(生产者) 另一个程序读取内容,内容出队(消费者) 我想你应该是缺乏一个使用场景. ...
- Linux基础--文件压缩
1.compress [root@linux ~]# compress [-dcr] 档案或目录 参数: -d:用来解压缩的参数 -r:可以连同目录下的档案也同时给予压缩呢! -c:将压缩数据输出成为 ...
- sql server UI怎么设置自增加id?
设置表结构的时候,设置标识列就可以了啊 来自为知笔记(Wiz)
- ITEM 2 MAC OSX 功能略强大的终端
iTerm2 iTerm 2 is a terminal emulator for Mac OS X that does amazing things. iTerm2 是一个终端模拟器,官方网站:ht ...
- linux驱动分离分层的概念
这个分离分层的概念和输入子系统有点像,但不是完全一样的.为什么会再弄一个这个模型出来我也没有搞懂,现在我的学习还停留在把知识学懂的层面上.至于为什么会产生这种知识,现在我还无从解释,还需时日成长. 这 ...
- mars android视频学习笔记一:Activity生命周期
(1)创建:onCreate->onStart->onResume;(2)失去焦点:onPause->onStop:(3)重新获得焦点:onRestart->onStart-& ...