如何ping IP地址


77

我正在使用这部分代码来ping通Java中的ip地址,但只有ping通本地主机才能成功,而对于其他主机,该程序表示主机无法访问。我禁用了防火墙,但仍然有此问题

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
主机


4
如果您直接使用ping,是否可以ping该服务器?
珍妮D

您要向jTextField1输入什么输入?
chrisbunney 2012年

是的!但是在我的程序中,我只能ping localhost !!!
Mehdi

2
@ user1529128我用一个简单的示例编辑了您的问题,该示例再现了您描述的行为。如果您认为不是您要的内容,请随时回滚编辑。
assylias 2012年

3
// @ assylias:谢谢你的编辑!我是stackoverflow的新手,这是我的第一个问题。感谢你们对我的帮助。
Mehdi

Answers:


16

您不能简单地在Java中执行ping操作,因为它依赖于ICMP,可惜Java中不支持该功能。

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

使用套接字代替

希望能帮助到你


我现在可能已经脱离上下文了,但这实际上对我有用dnsjava.org 谢谢大家。
Ravindranath Akila 2014年

5
以下是更好的答案
Igor Zubchenok 2016年

@AhmadArslan您以前在该链接上发布的任何答案,现在都消失了。因此,该链接不再是真正有用的...您似乎已杀死了自己的链接...
forresthopkinsa

65

InetAddress.isReachable()根据javadoc

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

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


3
那么,为什么您通常可以在Java之外的大多数计算机上以非管理员/非root用户身份执行此操作?
罗杜维克

需要说明的是:命令行ping等命令是否不使用ICMP数据包?我相当确定他们做到了。ping是否在管理环境中运行?
Loduwijk 2015年

您是在说isReachable方法仅使用TCP端口7,而不会使用ICMP ECHO REQUEST吗?还是如果我以某种方式授予我的应用程序root特权,它将使用ICMP吗?如果是后者,那么如何允许我的应用程序以root用户身份运行?
迈克尔·西姆斯

9
pingLinux上的命令是set-uid root;这就是非root用户可以使用它的原因,即使它使用ICMP ECHO_REQUEST。
erickson

1
:这并没有真正很好地工作stackoverflow.com/questions/9922543/...
伊桑·米克

32

我认为这段代码将帮助您:

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

19

检查您的连接性。在我的计算机上,这两个IP都可以打印:

将Ping请求发送到127.0.0.1
主机可以访问将
Ping请求发送到173.194.32.38
主机可以访问

编辑:

您可以尝试修改代码以使用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()可能会绕过它。


我确定我已经连接了,并且甚至禁用了防火墙和防病毒软件,但仍然无法正常工作……
Mehdi 2012年

它可能仍然是您的机器。您在什么操作系统上?您是否尝试过使用getByAddress()而不是getByName()方法来确保不尝试进行反向DNS查找?
Durandal

@ Durandal我正在使用win7,是的!我尝试用getByAddress()代替getByName(),没有DNS查找尝试,请不要告诉我没有办法!
Mehdi

1
@Durandal:在您给出的第二个示例中,为什么我们需要将ipaddress类型转换为byte?
Vamsi Pavan Mahesh

3
@vamsi因为IP是作为文字提供的,并且编译器认为文字是int类型的。因为byte的值范围是-128到127,所以超出该范围的值需要显式转换(例如,文字173)。“为什么”源于正在签名的javas字节,并且IP地址通常以未签名的字节表示,以提高可读性。
Durandal

12

它肯定会工作

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

}

1
如果更改-c-n,则很有可能。
Codingale 2015年

2
@Supuhstar它仅适用于具有ping命令的操作系统。基本上,上面的操作是派生一个新进程,并使其ping从OS运行命令。
哈里·乔

9

您可以使用此方法对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。无论是否可以到达。
ssindelar'6

在Windows和Android上都取得了成功
Frederik Witte

4

简短的建议:不要使用isReachable(),而是按照上面的某些答案中的建议,调用系统ping。

详细说明:

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

3


只是其他人提供的东西,即使它们工作良好,但在某些情况下,如果互联网速度慢或存在一些未知的网络问题,某些代码将无法工作(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);
}
}

希望能有所帮助,干杯!!!


这可能容易受到命令注入的影响,请始终验证输入
间谍

3

即使这不依赖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);
}

1

在具有oracle-jdk的Linux上,OP提交的代码在非root用户时使用端口7,在root用户时使用ICMP。当以文档指定的root用户身份运行时,它确实会执行真正的ICMP回显请求。

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


1

下面是在执行ping IP地址的方法Java,应该在工作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上,还会出现“一般性故障”错误消息,并且可能还有其他消息
间谍

0

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

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

看到自己对类似问题的回答


0

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

0

我尝试了几种选择:

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

}

这被证明是最快,最可靠的方法


1
批处理示例不正确。输出可以轻松地“从xyza答复:目标主机不可达”,这将返回肯定答案。
间谍

0

我更喜欢这样:

   /**
     *
     * @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 ms。

它可以在MacOS,Android和Windows上很好地工作,但应在JDK 1.8中使用。

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


-3

这应该工作:

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

}


4
请添加有关代码工作方式的描述。这将有助于OP在应用代码时理解您的代码。
BusyProgrammer

不得不在“低质量队列”中对此进行审核...但是由于它是从一个小时开始的...所以可能很快就会得到解释的改进。急于发布2012年问题的答案是什么?好吧...我现在就跳过它。
Louys Patrice Bessette'Mar

感谢您的所有意见。首先,这是仅适用于Windows的类和方法。我需要花一些时间来完成一个项目,所以我想出了这是肮脏的,但是如果您在Windows上工作,那会很快。从代码本身可以看到,这是一个大约5分钟的超快速开发代码,用于ping IPv4主机。此类及其方法获取String作为IP地址,并返回Windows CMD中生成的ping的平均时间。对这些ping命令进行CMD,然后此代码读取输出以到达给出某些数字统计的行。
约翰·史密斯,

当给出最小值,最大值和平均值时,它将“标记”输出,并返回平均时间。一次ping一次就可以得到平均时间,这真是太疯狂了,但这是windows,而且还是可以做到的。
约翰·史密斯

在将其标记下来之前,请先在Windows上尝试一下。对于一个大问题,这是一个简单/肮脏的修复。
约翰·史密斯,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.