android 丢包率测试工具,android的ping的实现丢包率的获取

最近做的ANdroid项目是有关于利用ping的方法去获取丢包率。

方案一(失败):

1、ping.c文件在JNI的实现。ping.c文件与其相关文件从Busybox源码(busybox-1.19.2)里拿,或是Android源码的\external\ping\目录下拿。

在jni下编译自己的.so文件。但是实验不成功。

追踪方法:用log在.c打印信息

需要声明

#include

#define  LOG_TAG    "zyp"

#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

且要在Android.mk文件添加LOCAL_LDLIBS :=-llog(需要放在include $(CLEAR_VARS)后面的任意位置)

就可以使用:

LOGI("ping= %f",a);打印自己要的信息

追踪发现在创建ICMP协议的socket会失败出错。查找资源原因是必须程序是Root权限才可以。

采用办法是且要在

Java:Process process = Runtime.getRuntime().exec(“su”);

也是失败。原因是因为Runtime.getRuntime().exec(“su”);只是开启一个“Root”的进程,程序还是没有获得Root权限去创建Socket。

方案二(需要Root):

把jni的ping.c与相关文件编译成可执行的二进制文件,Android.mk文件采用Busybox源码(busybox-1.19.2)里拿,或是Android源码的\external\ping\目录下的Android.mk文件,用cygwin编译,编译成可执行文件ping。拷贝发到工程的assets目录下。

复制assets目录下的ping到私有文件目录下/data/data/pakeage_/files/ping

/**

* 复制assets目录下的ping到私有文件目录下ping下。

*/

private boolean cpPingLib(){

String path = TestPing.this.getApplicationContext().getFilesDir()

.getAbsolutePath()+ "/ping"; //data/data/包名/files/

File file = new File(path);

if(file.exists()){

return true;

}

FileOutputStream out = null;

InputStream in = null ;

try {

in = TestPing.this.getAssets().open("ping"); //从assets目录下复制

out = new FileOutputStream(file);

int length = -1;

byte[] buf = new byte[1024];

while ((length = in.read(buf)) != -1){

out.write(buf, 0, length);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

return false;

} catch (IOException e) {

e.printStackTrace();

return false;

}finally{

try {

out.flush();

in.close();

out.close();

} catch (IOException e) {

e.printStackTrace();

}

}

return true;

}

/**

* 执行chmod 777 ping

*/

private boolean chmodExec() {

Process process = null;

try {

String cmd="chmod 777 "+TestPing.this.getApplicationContext()

.getFilesDir().getAbsolutePath()+ "/ping";

process = Runtime.getRuntime().exec(cmd); //切换到root帐号

process.waitFor();

} catch (Exception e) {

return false;

} finally {

try {

process.destroy();

} catch (Exception e) {

}

}

return true;

}

然后就可以ping了(需要Root):

/**

* 运行命令:"/data/data/ping -c [发包次数] -s [包大小] [ip地址]";

* @return 丢包率

*/

private int beginPing(String address, int countPage, int countDatePake) {

String returnMsg = "";

Process process = null;

DataOutputStream os = null;

try {

String cmd=getApplicationContext().getFilesDir()

.getAbsolutePath()+"/ping -c "+countPage+" -s "+

countDatePake +" "+address+ "\n";

process = Runtime.getRuntime().exec("su"); //切换到root帐号

os = new DataOutputStream(process.getOutputStream());

InputStreamReader r = new InputStreamReader(

process.getInputStream());

LineNumberReader returnData = new LineNumberReader(r);

os.writeBytes(cmd + "\n");

os.writeBytes("exit\n");

os.flush();

process.waitFor();

String line = "";

while ((line = returnData.readLine()) != null) {

if(line.contains("packet loss is "))

returnMsg += (line);

}

} catch (Exception e) {

return -1;

} finally {

try {

process.destroy();

} catch (Exception e) {

}

}

//returnMsg = "100 packets transmitted, 0 received, packet loss is 100% ..."

int s = returnMsg.indexOf("packet loss is");

s += 14;

while((++s)

if((returnMsg.charAt(s)<48) || (returnMsg.charAt(s)>57))

continue;

int n = s;

while( ++n

if(returnMsg.charAt(n)!='%') continue;

return Integer.valueOf(returnMsg.substring(s, n));

}

}

return -1;

}

方案三(不确定):

之所以不直接用系统的ping,是因为系统ping打印的信息是不确定的:

ping -c4 192.168.1.118

PING 192.168.1.118 (192.168.1.118) 56(84) bytes of data.

64 bytes from 192.168.1.118: icmp_seq=1 ttl=64 time=31.4 ms

64 bytes from 192.168.1.118: icmp_seq=2 ttl=64 time=2.05 ms

64 bytes from 192.168.1.118: icmp_seq=3 ttl=64 time=1.45 ms

64 bytes from 192.168.1.118: icmp_seq=4 ttl=64 time=9.78 ms

--- 192.168.1.118 ping statistics ---

4 packets transmitted, 4 received,0% packet loss, time 3002ms

rtt min/avg/max/mdev = 1.452/11.178/31.422/12.140 ms

其中0% packet loss在不同的系统是不同格式的,所以才有方案一与方案二,方案一、二是创建自己的ping,自己的ping打印的信息结果有确定性。

方案三还是有成功的概率,去把ping打印的结果进行分析,用”,“进行分离,把含有loss与%在就把间的数字读取即可(如果ping打印的信息没有loss与%就会失败了):

/**

* 运行命令:"ping -c [发包次数] -s [包大小] [ip地址]";

* @return 丢包率

*/

private int pingExec(String address, int countPage, int countDatePake) {

Process process = null;

String returnMsg = "";

try {

String cmd="ping -c "+countPage+" -s "+countDatePake +" "+address;

process = Runtime.getRuntime().exec(cmd);

InputStreamReader r = new InputStreamReader(

process.getInputStream());

LineNumberReader returnData = new LineNumberReader(r);

String line = "";

while ((line = returnData.readLine()) != null) {

// returnMsg += line;

if(line.contains("loss") && line.contains("%") ){

returnMsg += line;

}

}

// returnMsg = "100 packets transmitted, 0 received,

// packet loss is 100% , time 99007ms";

} catch (IOException e) {

e.printStackTrace();

return -1;

}finally {

try {

process.destroy();

} catch (Exception e) {

}

}

int index = -1;

String splitStr[]= returnMsg.split(",");

for(int i=0;i

if(splitStr[i].contains("loss") && splitStr[i].contains("%")){

returnMsg = splitStr[i];

index = returnMsg.indexOf('%');

break;

}

}

int m = index;

while( m-->0 ){

if((returnMsg.charAt(m)<48) || (returnMsg.charAt(m)>57)){

break;

}

}

if(((m+1)==index) ||((m+1)<0) || (index>(returnMsg.length()-1))){

return -1;

}

return Integer.valueOf(returnMsg.substring(m+1,index));

}

方案四,发送UDP的包,需要开启服务器的Echo(是端口7)

private int pingUDP(String ipaddress, int countPage, int countDatePake){

int countErr=0;

int count=0;

DatagramSocket socket = null;

StringBuffer strSend = new StringBuffer();

DatagramPacket packetSend = null;

try {

String sensStr = "boys or girls,you can receive me";//32 bit

if(strSend.length()>0)

strSend.delete(0,strSend.length());

int n = countDatePake/32;

for(int i=0;i

strSend.append(sensStr);

}

int surplus = countDatePake - 32*n;

if( surplus>0 )strSend.append(sensStr.substring(0, surplus));

socket = new DatagramSocket(5000);

socket.setSoTimeout(5000);

InetAddress serverAddress = InetAddress.getByName(ipaddress);

byte data [] = strSend.toString().getBytes();

packetSend = new DatagramPacket(data,data.length,serverAddress,7);

//调用socket对象的send方法,发送数据

} catch (Exception e) {

e.printStackTrace();

}

DatagramPacket packetRe = null;

try {

while((!stop) && (count

if(socket==null)break;

socket.send(packetSend);

count++;

byte data [] = new byte[strSend.length()];

packetRe = new DatagramPacket(data,data.length);

socket.receive(packetRe);//如果客户端没有发送数据,该进程就停滞在这里

if(!Arrays.equals(packetRe.getData(),strSend.toString().getBytes())){

countErr++;

}

}

} catch (SocketException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally{

if(socket != null){

socket.close();

}

}

if((count == countPage) && ( count>0)){

return ((countErr*100)/count);

}

return -1;

}

pingUDP()函数是将接受到的数据与发送的数据进行对比,数据一样的话就成功咯【Arrays.equals(packetRe.getData(),strSend.toString().getBytes())进行比较】。

方案二最好。我是先实行方案二,若是失败就采用方案三,否则就方案四了。