上網找了一下,一般對於ping的建議是直接利用java內建的InetAddress.isReachable()來做,實際上在ping內部網路的伺服器時,是沒問題的,但是如果要ping位於外部網路的伺服器時,就會失敗而回傳False。
Android內部的實作是在libcore/luni/src/main/java/java/net/InetAddress.java裡,這裡就很簡單的建立socket,然後試著連到指定位址的port 7,如果可以連,或者是伺服器明確地拒絕,就視為伺服器存在,可以連線。這就解釋了為什麼無法ping位於外部網路的伺服器,因為ISP為了安全或是其他考量,而不允許。我分別以python與java寫了與Android實作相似的程式去實驗,的確都不行。
[python]
import sys
import socket
if len(sys.argv)<2:
print( “Need at least 1 parameters.” )
print( “Usage: {0} host”.format( sys.argv[0] ) )
sys.exit(-1)
r = False
try:
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.settimeout(5)
s.connect( (sys.argv[1], 7) )
r = True
except socket.error, ex:
if ex.errno==111:
r = True
else:
print( ex )
if r:
print( “{0} is reachable.”.format( sys.argv[1] ) )
else:
print( “{0} is NOT reachable.”.format( sys.argv[1] ) )
[/python]
[java]
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.IOException;
class Ping {
public static void main(String[] args) {
InetAddress in;
try {
in = InetAddress.getByName(args[0]);
boolean result = in.isReachable(5000);
if (result) {
System.out.println(“Response OK”);
}
else {
System.out.println(“Response fail”);
}
} catch (UnknownHostException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
[/java]
Java裡只能建立 stream(TCP) 或 dgram(UDP) 的socket,那麼只能用JNI,用C寫ping了,但經過實驗結果,發現會因為權限的關係而無法建立socket,原來要建立raw與IPPROTO_ICMP的socket,需要root權限。一般linux裡,非root使用者可以使用ping,是因為ping加上了setuid權限,才能使用。在Android裡,要不就是建立service,要不就是設法為ping加上setuid,否則是都無法使用的。