【问题标题】:How to ping an IP address如何ping一个IP地址
【发布时间】:2012-07-15 10:04:05
【问题描述】:

我正在使用这部分代码在 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");
}

输出是:

向 127.0.0.1 发送 Ping 请求
主机可达
向 173.194.32.38 发送 Ping 请求
主机无法访问

【问题讨论】:

  • 如果您直接使用 ping,是否可以 ping 该服务器?
  • 你在 jTextField1 中输入了什么?
  • 是的!但在我的程序中,我只能 ping localhost !!!
  • @user1529128 我已经用一个简单的示例编辑了您的问题,该示例重现了您描述的行为。如果您认为这不是您所要求的,请随时回滚编辑。
  • @assylias:感谢您的精彩编辑!我是 stackoverflow 的新手,这是我的第一个问题。谢谢你帮助我。

标签: java ping host


【解决方案1】:

InetAddress.isReachable()根据javadoc

".. 一个典型的实现将使用 ICMP ECHO REQUEST,如果 可以获取权限,否则会尝试建立TCP 目标主机的端口 7 (Echo) 上的连接..”。

选项 #1 (ICMP) 通常需要管理 (root) 权限。

【讨论】:

  • 那么为什么您通常可以在大多数计算机上以非管理员/非 root 身份执行此操作Java 之外
  • 澄清一下:命令行 ping 等命令不使用 ICMP 数据包吗?我相当肯定他们做到了。 ping 是否在管理环境中运行?
  • 你是说 isReachable 方法只使用 TCP 端口 7 而不会使用 ICMP ECHO 请求?或者如果我以某种方式向我的应用程序授予root权限,它会使用ICMP吗?如果是后者,那么如何让我的应用以 root 身份运行?
  • Linux 上的ping 命令是set-uid root;这就是为什么非 root 用户可以使用它,即使它使用 ICMP ECHO_REQUEST。
【解决方案2】:

我认为这段代码会对你有所帮助:

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();
        }
    }
}

【讨论】:

    【解决方案3】:

    检查您的连接。在我的电脑上,这两个 IP 都显示为 REACHABLE:

    向 127.0.0.1 发送 Ping 请求
    主机可达
    向 173.194.32.38 发送 Ping 请求
    主机可达

    编辑:

    您可以尝试修改代码以使用 getByAddress() 获取地址:

    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");
    }
    

    getByName() 方法可能会尝试某种在您的机器上可能无法实现的反向 DNS 查找,getByAddress() 可能会绕过它。

    【讨论】:

    • 我确定我已连接,我什至禁用了我的防火墙和防病毒软件,但它仍然无法正常工作......
    • 它可能仍然是你的机器。你在什么操作系统上?您是否尝试过使用 getByAddress() 而不是 getByName() 方法来确保不尝试反向 DNS 查找?
    • @Durandal 我正在使用win7,是的!我尝试了 getByAddress() 而不是 getByName() ,没有尝试 DNS 查找,请不要告诉我没有办法!
    • @Durandal:为什么我们需要在第二个示例中将 ipaddress 类型转换为字节,你已经给出了?
    • @vamsi 因为 IP 是作为文字给出的,并且编译器认为文字是 int 类型的。因为 byte 的值范围是 -128 到 127,超出该范围的值需要显式转换(例如文字 173)。 “为什么”源于 javas 字节被签名,而 IP 地址通常以无符号字节表示,以便于阅读。
    【解决方案4】:

    你不能简单地在 Java 中 ping,因为它依赖于 ICMP,遗憾的是 Java 不支持它

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

    改用套接字

    希望对你有帮助

    【讨论】:

    • 我现在可能断章取义,但这对我有用,事实上非常好:dnsjava.org 谢谢大家。
    • 下面有更好的答案
    • @AhmadArslan 无论您曾经在该链接上发布过什么答案,现在都没有了。所以这个链接不再有用了......你似乎已经杀死了你自己的链接......
    【解决方案5】:

    肯定会有用的

    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);
        }
      }
    
    }
    

    【讨论】:

    • 如果您将-c 更改为-n,很有可能。
    • @Supuhstar 它仅适用于具有 ping 命令的操作系统。基本上它上面所做的就是分叉一个新进程并使其从操作系统运行ping 命令。
    【解决方案6】:

    您可以使用此方法在 Windows 和其他平台上 ping 主机:

    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;
    }
    

    【讨论】:

    • 在 windows 上你总是得到 1 作为 returnVal。不管它是否可达。
    • 在 Windows 和 Android 上都取得了成功
    • 在没有 root 的情况下在 Windows 10 和 Android 7.1.1 上运行良好。
    【解决方案7】:

    简短推荐: 不要使用 isReachable(),调用系统 ping,如上面一些答案中所建议的那样。

    长解释:

    • ping 使用 ICMP 网络协议。要使用 ICMP,需要一个“原始套接字”
    • 操作系统不允许标准用户使用原始套接字
    • 以下适用于fedora 30 linux,windows系统应该类似
    • 如果 java 以 root 身份运行,isReachable() 实际上会发送 ICMP ping 请求
    • 如果 java 没有以 root 身份运行,isReachable() 会尝试连接到 TCP 端口 7,即回显端口。该服务一般不再使用,尝试使用可能会产生不正确的结果
    • 对连接请求的任何类型的回答,以及拒绝(TCP 标志 RST)都会从 isReachable() 中产生一个“真”
    • 某些防火墙会为任何未明确打开的端口发送 RST。如果发生这种情况,您将获得 isReachable() == true 对于甚至不存在的主机
    • 进一步尝试为 java 进程分配必要的功能:
    • setcap cap_net_raw+eip java 可执行文件(分配使用原始套接字的权利)
    • 测试:getcap java 可执行文件 -> 'cap_net_raw+eip'(已分配能力)
    • 正在运行的 java 仍然向端口 7 发送 TCP 请求
    • 使用 getpcaps pid 检查正在运行的 java 进程表明正在运行的 java 没有原始套接字功能。显然我的 setcap 已被某些安全机制覆盖
    • 随着安全要求的增加,这可能会变得更加受限,除非 s.b.实现了一个特别针对 ping 的异常(但目前在网上找不到任何东西)

    【讨论】:

    • 系统 ping 也不能保证正常工作;某些环境会在其防火墙处阻止所有 ICMP ECHO 请求。特别是,Azure(以及其他的 Github Actions)就是这样一种环境。
    【解决方案8】:


    只是对其他人提供的内容的补充,即使它们运行良好,但在某些情况下,如果互联网速度较慢或存在一些未知的网络问题,某些代码将无法运行 (isReachable())。但是下面提到的这段代码创建了一个进程,该进程充当 Windows 的命令行 ping (cmd ping)。它在所有情况下都适用于我,经过尝试和测试。

    代码:-

    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);
    }
    }
    

    希望对你有帮助,干杯!!!

    【讨论】:

    • 这可能容易受到命令注入的影响,请始终验证输入
    【解决方案9】:

    尽管这不依赖于 Windows 上的 ICMP,但此实现与新的 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);
    }
    

    【讨论】:

      【解决方案10】:

      在带有 oracle-jdk 的 linux 上,OP 提交的代码在非 root 时使用端口 7,在 root 时使用 ICMP。当按照文档说明以 root 身份运行时,它确实会执行真正的 ICMP 回显请求。

      如果您在 MS 机器上运行此应用程序,您可能必须以管理员身份运行应用程序才能获得 ICMP 行为。

      【讨论】:

        【解决方案11】:

        这是在Java 中ping IP 地址的方法,它应该适用于WindowsUnix 系统:

        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;
            }
        }
        

        确保将Apache Commons Lang 添加到您的依赖项中。

        【讨论】:

        • 此示例可能不适用于非英语操作系统。在windows上,还有“一般故障”错误信息,可能还有其他的
        【解决方案12】:

        我更喜欢这种方式:

           /**
             *
             * @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);
            }
        

        这种方式可以将阻塞时间限制在特定的时间,比如200毫秒。

        适用于MacOS、Android和Windows,应该在JDK 1.8中使用。

        这个想法来自Mohammad Banisaeid,但我无法评论。 (您必须有 50 声望才能发表评论)

        【讨论】:

          【解决方案13】:

          我知道以前的条目已经回答了这个问题,但是对于遇到这个问题的其他人,我确实找到了一种不需要在 Windows 中使用“ping”过程然后清理输出的方法。

          我所做的是使用 JNA 调用 Window 的 IP 帮助程序库来执行 ICMP 回显

          my own answer to my own similar issue

          【讨论】:

            【解决方案14】:

            InetAddress 并不总是返回正确的值。在本地主机的情况下成功,但对于其他主机,这表明主机无法访问。尝试使用下面给出的 ping 命令。

            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;
            }
            

            【讨论】:

              【解决方案15】:

              我尝试了几个选项:

              1. Java InetAddress

              InetAddress.getByName(ipAddress),Windows 上的网络在尝试了几次后开始出现异常

              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;
                        }.
                

              这很可靠,但有点慢

              1. Windows 批处理文件

              我终于决定在我的 Windows 机器上创建一个批处理文件,内容如下:ping.exe -n %echoCount% %pingIp% 然后我使用

              在我的 java 代码中调用了 .bat 文件
              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;
              }
              

              }

              事实证明这是最快最可靠的方法

              【讨论】:

              • 批处理示例不正确。输出很容易是“来自 x.y.z.a 的回复:无法访问目标主机”,这将返回一个肯定的答案。
              【解决方案16】:

              这应该可行:

              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";
              }
              

              }

              【讨论】:

              • 请添加您的代码如何工作的描述。这将有助于 OP 在应用代码时理解您的代码。
              • 有这个在“低质量队列”中进行审查......但是因为它的日期是一个小时......也许很快就会通过解释得到改进。急于发布 2012 年问题的答案?嗯...我现在就跳过它。
              • 感谢您的所有 cmets。首先,这是一个仅适用于 Windows 的类和方法。我需要作为一个项目的 ping 时间,所以我想出了这个,如果你在 Windows 上工作,这很脏但很快。从代码本身可以看出,这是一个超快的约 5 分钟开发的用于 ping IPv4 主机的代码。此类及其方法获取一个字符串作为 IP 地址,并返回在 windows CMD 中生成的 ping 的平均时间。 CMD 那些 ping 和此代码读取输出以到达给出一些数字统计信息的行。
              • 它在给出最小值、最大值和平均值时“标记”输出并返回平均时间。你可以只用一次 ping 来获得平均时间,这有点疯狂,但这是 Windows,无论如何它都会这样做。
              • 请在标记之前在 Windows 上自己尝试一下。这是一个大问题的简单/肮脏的解决方案。
              猜你喜欢
              • 1970-01-01
              • 2013-09-08
              • 1970-01-01
              • 1970-01-01
              • 2018-01-14
              • 2011-06-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多