如何定位 IP 地址

我正在使用这部分代码在 java 中 ping 一个 ip 地址,但是只有 ping localhost 成功,对于其他主机,程序说主机是无法访问的。 我关闭了我的防火墙,但仍然有这个问题

public static void main(String[] args) throws UnknownHostException, IOException {
String ipAddress = "127.0.0.1";
InetAddress inet = InetAddress.getByName(ipAddress);


System.out.println("Sending Ping Request to " + ipAddress);
System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");


ipAddress = "173.194.32.38";
inet = InetAddress.getByName(ipAddress);


System.out.println("Sending Ping Request to " + ipAddress);
System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");
}

输出结果是:

将 Ping 请求发送到127.0.0.1
可以联系到主机
发送 Ping 请求到173.194.32.38
无法联系到主机

285435 次浏览

Check your connectivity. On my Computer this prints REACHABLE for both IP's:

Sending Ping Request to 127.0.0.1
Host is reachable
Sending Ping Request to 173.194.32.38
Host is reachable

EDIT:

You could try modifying the code to use getByAddress() to obtain the address:

public static void main(String[] args) throws UnknownHostException, IOException {
InetAddress inet;


inet = InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 });
System.out.println("Sending Ping Request to " + inet);
System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");


inet = InetAddress.getByAddress(new byte[] { (byte) 173, (byte) 194, 32, 38 });
System.out.println("Sending Ping Request to " + inet);
System.out.println(inet.isReachable(5000) ? "Host is reachable" : "Host is NOT reachable");
}

The getByName() methods may attempt some kind of reverse DNS lookup which may not be possible on your machine, getByAddress() might bypass that.

You can not simply ping in Java as it relies on ICMP, which is sadly not supported in Java

http://mindprod.com/jgloss/ping.html

Use sockets instead

Hope it helps

InetAddress.isReachable() according to javadoc:

".. A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host..".

Option #1 (ICMP) usually requires administrative (root) rights.

It will work for sure

import java.io.*;
import java.util.*;


public class JavaPingExampleProgram
{


public static void main(String args[])
throws IOException
{
// create the ping command as a list of strings
JavaPingExampleProgram ping = new JavaPingExampleProgram();
List<String> commands = new ArrayList<String>();
commands.add("ping");
commands.add("-c");
commands.add("5");
commands.add("74.125.236.73");
ping.doCommand(commands);
}


public void doCommand(List<String> command)
throws IOException
{
String s = null;


ProcessBuilder pb = new ProcessBuilder(command);
Process process = pb.start();


BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));


// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null)
{
System.out.println(s);
}


// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null)
{
System.out.println(s);
}
}


}

You can use this method to ping hosts on Windows and other platforms:

private static boolean ping(String host) throws IOException, InterruptedException {
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");


ProcessBuilder processBuilder = new ProcessBuilder("ping", isWindows? "-n" : "-c", "1", host);
Process proc = processBuilder.start();


int returnVal = proc.waitFor();
return returnVal == 0;
}

On linux with oracle-jdk the code the OP submitted uses port 7 when not root and ICMP when root. It does do a real ICMP echo request when run as root as the documentation specifies.

If you running this on a MS machine you may have to run the app as administrator to get the ICMP behaviour.

I know this has been answered with previous entries, but for anyone else that comes to this question, I did find a way that did not require having use the "ping" process in windows and then scrubbing the output.

What I did was use JNA to invoke Window's IP helper library to do an ICMP echo

See my own answer to my own similar issue

I think this code will help you:

public class PingExample {
public static void main(String[] args){
try{
InetAddress address = InetAddress.getByName("192.168.1.103");
boolean reachable = address.isReachable(10000);


System.out.println("Is host reachable? " + reachable);
} catch (Exception e){
e.printStackTrace();
}
}
}


Just an addition to what others have given, even though they work well but in some cases if internet is slow or some unknown network problem exists, some of the codes won't work (isReachable()). But this code mentioned below creates a process which acts as a command line ping (cmd ping) to windows. It works for me in all cases, tried and tested.

Code :-

public class JavaPingApp {


public static void runSystemCommand(String command) {


try {
Process p = Runtime.getRuntime().exec(command);
BufferedReader inputStream = new BufferedReader(
new InputStreamReader(p.getInputStream()));


String s = "";
// reading output stream of the command
while ((s = inputStream.readLine()) != null) {
System.out.println(s);
}


} catch (Exception e) {
e.printStackTrace();
}
}


public static void main(String[] args) {


String ip = "stackoverflow.com"; //Any IP Address on your network / Web
runSystemCommand("ping " + ip);
}
}

Hope it helps, Cheers!!!

Here is a method for pinging an IP address in Java that should work on Windows and Unix systems:

import org.apache.commons.lang3.SystemUtils;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


public class CommandLine
{
/**
* @param ipAddress The internet protocol address to ping
* @return True if the address is responsive, false otherwise
*/
public static boolean isReachable(String ipAddress) throws IOException
{
List<String> command = buildCommand(ipAddress);
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();


try (BufferedReader standardOutput = new BufferedReader(new InputStreamReader(process.getInputStream())))
{
String outputLine;


while ((outputLine = standardOutput.readLine()) != null)
{
// Picks up Windows and Unix unreachable hosts
if (outputLine.toLowerCase().contains("destination host unreachable"))
{
return false;
}
}
}


return true;
}


private static List<String> buildCommand(String ipAddress)
{
List<String> command = new ArrayList<>();
command.add("ping");


if (SystemUtils.IS_OS_WINDOWS)
{
command.add("-n");
} else if (SystemUtils.IS_OS_UNIX)
{
command.add("-c");
} else
{
throw new UnsupportedOperationException("Unsupported operating system");
}


command.add("1");
command.add(ipAddress);


return command;
}
}

Make sure to add Apache Commons Lang to your dependencies.

This should work:

import java.io.BufferedReader;
import java.io.InputStreamReader;


public class Pinger {


private static String keyWordTolookFor = "average";


public Pinger() {
// TODO Auto-generated constructor stub
}




public static void main(String[] args) {
//Test the ping method on Windows.
System.out.println(ping("192.168.0.1")); }




public String ping(String IP) {
try {
String line;
Process p = Runtime.getRuntime().exec("ping -n 1 " + IP);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (((line = input.readLine()) != null)) {


if (line.toLowerCase().indexOf(keyWordTolookFor.toLowerCase()) != -1) {


String delims = "[ ]+";
String[] tokens = line.split(delims);
return tokens[tokens.length - 1];
}
}


input.close();
} catch (Exception err) {
err.printStackTrace();
}
return "Offline";
}

}

InetAddress is not always return correct value. It is successful in case of Local Host but for other hosts this shows that the host is unreachable. Try using ping command as given below.

try {
String cmd = "cmd /C ping -n 1 " + ip + " | find \"TTL\"";
Process myProcess = Runtime.getRuntime().exec(cmd);
myProcess.waitFor();


if(myProcess.exitValue() == 0) {


return true;
}
else {
return false;
}
}
catch (Exception e) {
e.printStackTrace();
return false;
}

Even though this does not rely on ICMP on Windows, this implementation works pretty well with the new Duration API

public static Duration ping(String host) {
Instant startTime = Instant.now();
try {
InetAddress address = InetAddress.getByName(host);
if (address.isReachable(1000)) {
return Duration.between(startTime, Instant.now());
}
} catch (IOException e) {
// Host not available, nothing to do here
}
return Duration.ofDays(1);
}

I tried a couple of options:

  1. Java InetAddress

InetAddress.getByName(ipAddress), the network on windows started misbehaving after trying a couple of times

  1. Java HttpURLConnection

            URL siteURL = new URL(url);
    connection = (HttpURLConnection) siteURL.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(pingTime);
    connection.connect();
    
    
    code = connection.getResponseCode();
    if (code == 200) {
    code = 200;
    }.
    

This was reliable but a bit slow

  1. Windows Batch File

I finally settled to creating a batch file on my windows machine with the following contents: ping.exe -n %echoCount% %pingIp% Then I called the .bat file in my java code using

public int pingBat(Network network) {
ProcessBuilder pb = new ProcessBuilder(pingBatLocation);
Map<String, String> env = pb.environment();


env.put(
"echoCount", noOfPings + "");
env.put(
"pingIp", pingIp);
File outputFile = new File(outputFileLocation);
File errorFile = new File(errorFileLocation);


pb.redirectOutput(outputFile);


pb.redirectError(errorFile);


Process process;


try {
process = pb.start();
process.waitFor();
String finalOutput = printFile(outputFile);
if (finalOutput != null && finalOutput.toLowerCase().contains("reply from")) {
return 200;
} else {
return 202;
}
} catch (IOException e) {
log.debug(e.getMessage());
return 203;
} catch (InterruptedException e) {
log.debug(e.getMessage());
return 204;
}

}

This proved to be the fastest and most reliable way

short recommendation: don't use isReachable(), call the system ping, as proposed in some of the answers above.

long explanation:

  • ping uses the ICMP network protcol. To use ICMP, a 'raw socket' is needed
  • standard users are not allowed by the operating system to use raw sockets
  • the following applies to a fedora 30 linux, windows systems should be similar
  • if java runs as root, isReachable() actually sends ICMP ping requests
  • if java does not run as root, isReachable() tries to connect to TCP port 7, known as the echo port. This service is commonly not used any more, trying to use it might yield improper results
  • any kind of answer to the connection request, also a reject (TCP flag RST) yields a 'true' from isReachable()
  • some firewalls send RST for any port that is not explicitly open. If this happens, you will get isReachable() == true for a host that does not even exist
  • further tries to assign the necessary capabilities to a java process:
  • setcap cap_net_raw+eip java executable (assign the right to use raw sockets)
  • test: getcap java executable -> 'cap_net_raw+eip' (capability is assigned)
  • the running java still sends a TCP request to port 7
  • check of the running java process with getpcaps pid shows that the running java does not have the raw socket capablity. Obviously my setcap has been overridden by some security mechanism
  • as security requirements are increasing, this is likely to become even more restricted, unless s.b. implements an exception especially for ping (but nothing found on the net so far)

I prefer to this way:

   /**
*
* @param host
* @return true means ping success,false means ping fail.
* @throws IOException
* @throws InterruptedException
*/
private static boolean ping(String host) throws IOException, InterruptedException {
boolean isWindows = System.getProperty("os.name").toLowerCase().contains("win");


ProcessBuilder processBuilder = new ProcessBuilder("ping", isWindows? "-n" : "-c", "1", host);
Process proc = processBuilder.start();
return proc.waitFor(200, TimeUnit.MILLISECONDS);
}

This way can limit the blocking time to the specific time,such as 200 ms.

It works well in MacOS、Android and Windows, and should used in JDK 1.8.

This idea comes from Mohammad Banisaeid,but I can't comment. (You must have 50 reputation to comment)