I was wondering how I could list all the TCP connections on my system which are open using Java. I am using CentOS.
I do not have any clue on where to start also. Any pointers would be helpful.
Thanks in advance
Thanks for the tips
I have to do something like this
Q) Identify any new established connections for all tcp ports that are currently listening
and continue to poll every 5 seconds. The script should terminate when there are no longer any established connections.
public class TCPConnections {
public HashSet<Integer> establishedConnections = new HashSet<Integer>();
public HashSet<Integer> listeningConnections = new HashSet<Integer>();
public static void main(String[] args) {
// TODO Auto-generated method stub
TCPConnections tcpConnections = new TCPConnections();
try{
do{
tcpConnections.getListeningConnections();
Thread.sleep(5000);
tcpConnections.getEstablishedConnections();
}while(!tcpConnections.establishedConnections.isEmpty());
}
catch(Exception ex){
ex.printStackTrace();
}
}
public void getEstablishedConnections(){
String netstat = new String();
try {
String line;
establishedConnections = new HashSet<Integer>();
String[] cmd = {
"/bin/sh",
"-c",
"netstat -atn | grep -w tcp | grep ESTABLISHED"
};
java.lang.Process p = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
String[] portNo = line.split("\\s+");
if(portNo[3] != null && !portNo[3].equalsIgnoreCase(" ")){
String str = portNo[3].split(":")[1];
if( str != null && str.matches("[0-9]+")){
establishedConnections.add(Integer.parseInt(str));
if(listeningConnections.contains(Integer.parseInt(str))){listeningConnections.remove(Integer.parseInt(str));
System.out.println(" New connection established on port : "+Integer.parseInt(str));
}
}
}
netstat = netstat + " \n" + line;
}
System.out.println(netstat);
input.close();
} catch (Exception err) {
err.printStackTrace();
}
}
public void getListeningConnections(){
String netstat = new String();
try {
String line;
listeningConnections = new HashSet<Integer>();
String[] cmd = {
"/bin/sh",
"-c",
"netstat -atn | grep -w tcp | grep LISTEN"
};
java.lang.Process p = Runtime.getRuntime().exec(cmd);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
String[] portNo = line.split("\\s+");
if(portNo[3] != null && !portNo[3].equalsIgnoreCase(" ")){
String str = portNo[3].split(":")[1];
if( str != null && str.matches("[0-9]+")){
listeningConnections.add(Integer.parseInt(str));
}
}
netstat = netstat + " \n" + line;
}
System.out.println(netstat);
input.close();
} catch (Exception err) {
err.printStackTrace();
}
}
}
The problem I face is that few ports are always in the established state and few are always in the Listen state so that the do-while loop runs forever. Kindly help me to solve this issue.
There doesn't seem to be anything built-in to Java to support this, which isn't surprising because netstat-like functionality is OS-dependent.
You have two other options:
1) Parse the output of netstat:
$ netstat -tn
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 192.168.1.140:48352 74.125.225.134:80 ESTABLISHED
2) Parse /proc/net/tcp (and tcp6, udp, udp6, unix, if you care):
$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 17120 1 ffff8800797c4700 100 0 0 10 0
1: 0100007F:0019 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 14821 1 ffff8800797c4000 100 0 0 10 0
2: 8C01A8C0:BCE0 86E17D4A:0050 01 00000000:00000000 00:00000000 00000000 1000 0 20164 1 ffff8800797c4e00 24 0 0 10 -1
This may appear more daunting, but would be the preferred method, as it doesn't rely upon netstat being present (and in your PATH, etc.)
You could use SNMP to get the TCPConnTable or TCPConnectionTable, whichever is supported.
There is a Java SNMP library called NetSNMP, no doubt others as well.
Related
So, I wrote this code on java and it's taking some 6 second times to execute and give output. As I am not from coding background I was expecting if someone from this expert's group could help me optimize this little.
Below is my code also the PowerShell command runs within seconds. only this while loop is taking much time.
What I want to achieve is just get the list of drives which is HDD and print it.
Process p = Runtime.getRuntime().exec("powershell.exe Get-Partition -disknumber 1 | select DriveLetter");
BufferedReader in = new BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
String line1 = "";
ArrayList<String> hddList = new ArrayList<String>();
while ((line1 = in.readLine()) != null) {
if (!line1.trim().isEmpty()) {
if (line1.contains("HDD")) {
hddList.add(line1.replaceAll(" +", "#").split("#")[0]+"#"+"HDD");
}
}
}
This seems to be an xy-problem, as you can easily get the drive letters in Java like
List<String> driveLetters = new ArrayList<>();
for(Path r: FileSystems.getDefault().getRootDirectories()) {
String s = r.toString();
if(s.length() == 3 && s.charAt(1) == ':') {
driveLetters.add(s.substring(0, 1));
}
}
since Java 7. This needs no interprocess communication and hence, has no such latency problems.
If you want to limit the result to fixed HDDs, you can use something like
List<String> driveLetters = new ArrayList<>();
for(Path r: FileSystems.getDefault().getRootDirectories()) {
String s = r.toString();
if(s.length() == 3 && s.charAt(1) == ':') try {
FileStore store = Files.getFileStore(r);
if(!Boolean.TRUE.equals(store.getAttribute("volume:isRemovable"))
&& !Boolean.TRUE.equals(store.getAttribute("volume:isCdrom"))) {
driveLetters.add(s.substring(0, 1));
}
}
catch(IOException ex) {} // no media in drive, obviously not an HDD then
}
As I said in my comments, I believe the issue is with the execution of the powerShell and not Java. See how quickly the following runs using the cmd.exe.
Here, all I'm doing is a directory listing and replacing <DIR> as though it was HDD.
Process p = Runtime.getRuntime().exec(
"cmd.exe /c dir".split("\\s+"));
System.out.println(p);
BufferedReader in = new BufferedReader(
new java.io.InputStreamReader(p.getInputStream()));
String line1 = "";
List<String> hddList = new ArrayList<String>();
while ((line1 = in.readLine()) != null) {
System.out.println(line1);
if (!line1.trim().isEmpty()) {
if (line1.contains("<DIR>")) {
hddList.add(line1.replaceAll(" +", "#").split("#")[0] + "#"
+ "HDD");
}
}
}
System.out.println(hddList);
You might be able to run cmd.exe as administrator and use related privileged commands to get the disk information. I have yet to determine how to do that without password input.
I am using this part of code to ping an ip address in java but only pinging localhost is successful and for the other hosts the program says the host is unreachable.
I disabled my firewall but still having this problem
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");
}
The output is:
Sending Ping Request to 127.0.0.1
Host is reachable
Sending Ping Request to 173.194.32.38
Host is NOT reachable
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.
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();
}
}
}
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
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;
}
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);
}
}
}
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)
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!!!
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);
}
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.
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.
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)
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
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;
}
I tried a couple of options:
Java InetAddress
InetAddress.getByName(ipAddress), the network on windows started misbehaving after trying a couple of times
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
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
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";
}
}
I want to run netstat -an | grep 12345 and retrieve the output to find out if a port is empty and ready to use. I have tried
TRY1:
System.out.println("RUNNING ==> "+command);
try
{
Process process = Runtime.getRuntime().exec("netstat -an | grep 4324");
InputStream in = process.getInputStream();
File tmp = File.createTempFile("allConnections","txt");
byte[] buf = new byte[256];
OutputStream outputConnectionsToFile = new FileOutputStream(tmp);
int numbytes = 0;
while ((numbytes = in.read(buf, 0, 256)) != -1)
{
outputConnectionsToFile.write(buf, 0, numbytes);
}
System.out.println("File is present at "+tmp.getAbsolutePath());
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
i see 12k results, like i was doing netstat -an without grep
TRY2:
public static ArrayList<String> exec_command_dont_wait(String command) throws IOException, InterruptedException
{
//String[] arrayExplodedArguments = command.split(" ");
ArrayList<String> returnHolder = new ArrayList<String>();
List<String> listCommands = new ArrayList<String>();
String[] arrayExplodedCommands = command.split(" ");
for(String element : arrayExplodedCommands)
{
listCommands.add(element);
System.out.println(element+"\n");
}
System.exit(0);
ProcessBuilder ps = new ProcessBuilder(listCommands);
ps.redirectErrorStream(true);
Process p = ps.start();
BufferedReader buffer = new BufferedReader(new InputStreamReader(p.getInputStream()));
//p.waitFor();
String line = new String();
while((line = buffer.readLine()) != null)
{
returnHolder.add(line);
//System.out.println(line);
}
return returnHolder;
}
i see 12k results, like i was doing netstat -an without grep , never to mention that i have to comment //p.waitFor(); and i don't know why.
How do i a simple netstat command with grep and retrieve the results?
Is there a simple command/function like in PHP and retrieve the results? Like 'exec()', really love that function.
What is the differance between running with p.waitFor() and without it. I mean i understand that JAVA waits for the process to finsish, but netstat seems to never finish, i waited 2 minutes. A simple curl finishes quicly.
Example
netstat -an | grep 4352
tcp 0 0 192.99.3.11:43529 118.32.42.29:22 ESTABLISHED
tcp 0 0 192.99.3.11:43522 15.139.118.57:22 ESTABLISHED
tcp 0 0 192.99.3.11:43521 116.322.199.10:22 ESTABLISHED
Thank you.
I am using this part of code to ping an ip address in java but only pinging localhost is successful and for the other hosts the program says the host is unreachable.
I disabled my firewall but still having this problem
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");
}
The output is:
Sending Ping Request to 127.0.0.1
Host is reachable
Sending Ping Request to 173.194.32.38
Host is NOT reachable
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.
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();
}
}
}
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
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;
}
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);
}
}
}
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)
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!!!
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);
}
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.
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.
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)
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
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;
}
I tried a couple of options:
Java InetAddress
InetAddress.getByName(ipAddress), the network on windows started misbehaving after trying a couple of times
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
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
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";
}
}
Is it possible to check the existence of process from Java in Windows.
I have its possible PID, I want to know if it is still running or not.
How to check if a pid is running on Windows with Java:
Windows tasklist command:
The DOS command tasklist shows some output on what processes are running:
C:\Documents and Settings\eric>tasklist
Image Name PID Session Name Session# Mem Usage
========================= ====== ================ ======== ============
System Idle Process 0 Console 0 28 K
System 4 Console 0 244 K
smss.exe 856 Console 0 436 K
csrss.exe 908 Console 0 6,556 K
winlogon.exe 932 Console 0 4,092 K
....
cmd.exe 3012 Console 0 2,860 K
tasklist.exe 5888 Console 0 5,008 K
C:\Documents and Settings\eric>
The second column is the PID
You can use tasklist to get info on a specific PID:
tasklist /FI "PID eq 1300"
prints:
Image Name PID Session Name Session# Mem Usage
========================= ====== ================ ======== ============
mysqld.exe 1300 Console 0 17,456 K
C:\Documents and Settings\eric>
A response means the PID is running.
If you query a PID that does not exist, you get this:
C:\Documents and Settings\eric>tasklist /FI "PID eq 1301"
INFO: No tasks running with the specified criteria.
C:\Documents and Settings\eric>
A Java function could do the above automatically
This function will only work on Windows systems that have tasklist available.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class IsPidRunningTest {
public static void main(String[] args) {
//this function prints all running processes
showAllProcessesRunningOnWindows();
//this prints whether or not processID 1300 is running
System.out.println("is PID 1300 running? " +
isProcessIdRunningOnWindows(1300));
}
/**
* Queries {#code tasklist} if the process ID {#code pid} is running.
* #param pid the PID to check
* #return {#code true} if the PID is running, {#code false} otherwise
*/
public static boolean isProcessIdRunningOnWindows(int pid){
try {
Runtime runtime = Runtime.getRuntime();
String cmds[] = {"cmd", "/c", "tasklist /FI \"PID eq " + pid + "\""};
Process proc = runtime.exec(cmds);
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
//Search the PID matched lines single line for the sequence: " 1300 "
//if you find it, then the PID is still running.
if (line.contains(" " + pid + " ")){
return true;
}
}
return false;
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Cannot query the tasklist for some reason.");
System.exit(0);
}
return false;
}
/**
* Prints the output of {#code tasklist} including PIDs.
*/
public static void showAllProcessesRunningOnWindows(){
try {
Runtime runtime = Runtime.getRuntime();
String cmds[] = {"cmd", "/c", "tasklist"};
Process proc = runtime.exec(cmds);
InputStream inputstream = proc.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String line;
while ((line = bufferedreader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Cannot query the tasklist for some reason.");
}
}
}
The Java code above prints a list of all running processes then prints:
is PID 1300 running? true
See if this can help:
http://blogs.oracle.com/vaibhav/entry/listing_java_process_from_java
That post explains how to get all PIDs running on a Windows machine: you'd have to compare the output of the cmd call with your PID, instead of printing it.
If you're on Unix-like systems you'd have to use with ps instead of cmd
Calling system commands from your java code is not a very portable solution; then again, the implementation of processes varies among operating systems.
Code:
boolean isStillAllive(String pidStr) {
String OS = System.getProperty("os.name").toLowerCase();
String command = null;
if (OS.indexOf("win") >= 0) {
log.debug("Check alive Windows mode. Pid: [{}]", pidStr);
command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";
return isProcessIdRunning(pidStr, command);
} else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr);
command = "ps -p " + pidStr;
return isProcessIdRunning(pidStr, command);
}
log.debug("Default Check alive for Pid: [{}] is false", pidStr);
return false;
}
boolean isProcessIdRunning(String pid, String command) {
log.debug("Command [{}]",command );
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
InputStreamReader isReader = new InputStreamReader(pr.getInputStream());
BufferedReader bReader = new BufferedReader(isReader);
String strLine = null;
while ((strLine= bReader.readLine()) != null) {
if (strLine.contains(" " + pid + " ")) {
return true;
}
}
return false;
} catch (Exception ex) {
log.warn("Got exception using system command [{}].", command, ex);
return true;
}
}
import jna from Maven to your project
after maven was update you can use:
int myPid = Kernel32.INSTANCE.GetCurrentProcessId();