Sockets: Discover Port Availability Using Java

How to find an available port?

If you don't mind the port used, specify a port of 0 to the ServerSocket constructor and it will listen on any free port.

ServerSocket s = new ServerSocket(0);
System.out.println("listening on port: " + s.getLocalPort());

If you want to use a specific set of ports, then the easiest way is probably to iterate through them until one works. Something like this:

public ServerSocket create(int[] ports) throws IOException {
for (int port : ports) {
try {
return new ServerSocket(port);
} catch (IOException ex) {
continue; // try next port
}
}

// if the program gets here, no port in the range was found
throw new IOException("no free port found");
}

Could be used like so:

try {
ServerSocket s = create(new int[] { 3843, 4584, 4843 });
System.out.println("listening on port: " + s.getLocalPort());
} catch (IOException ex) {
System.err.println("no available ports");
}

How would I choose in java that which port is free to use for ServerSocket or Socket?

Use Try catch to find a free port

private static int port=9000;
public static int detectPort(int prt)
{
try{
//connect to port
}
catch(Exception e)
{
return detectPort(prt+1);
}
return prt;
}

// Write detectPort(port); inside main

Fastest way to scan ports with Java

If you need 200ms for each of the 65536 ports (in the worst case, a firewall is blocking everything, thus making you hit your timeout for every single port), the maths is pretty simple: you need 13k seconds, or about 3 hours and a half.

You have 2 (non-exclusive) options to make it faster:

  • reduce your timeout
  • paralellize your code

Since the operation is I/O bound (in contrast to CPU bound -- that is, you spend time waiting for I/O, and not for some huge calculation to complete), you can use many, many threads. Try starting with 20. They would divide the 3 hours and a half among them, so the maximum expected time is about 10 minutes. Just remember that this will put pressure on the other side, ie, the scanned host will see huge network activity with "unreasonable" or "strange" patterns, making the scan extremely easy to detect.

The easiest way (ie, with minimal changes) is to use the ExecutorService and Future APIs:

public static Future<Boolean> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
return es.submit(new Callable<Boolean>() {
@Override public Boolean call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
});
}

Then, you can do something like:

public static void main(final String... args) {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<Boolean>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.shutdown();
int openPorts = 0;
for (final Future<Boolean> f : futures) {
if (f.get()) {
openPorts++;
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}

If you need to know which ports are open (and not just how many, as in the above example), you'd need to change the return type of the function to Future<SomethingElse>, where SomethingElse would hold the port and the result of the scan, something like:

public final class ScanResult {
private final int port;
private final boolean isOpen;
// constructor
// getters
}

Then, change Boolean to ScanResult in the first snippet, and return new ScanResult(port, true) or new ScanResult(port, false) instead of just true or false

EDIT: Actually, I just noticed: in this particular case, you don't need the ScanResult class to hold result + port, and still know which port is open. Since you add the futures to a List, which is ordered, and, later on, you process them in the same order you added them, you could have a counter that you'd increment on each iteration to know which port you are dealing with. But, hey, this is just to be complete and precise. Don't ever try doing that, it is horrible, I'm mostly ashamed that I thought about this... Using the ScanResult object is much cleaner, the code is way easier to read and maintain, and allows you to, later, for example, use a CompletionService to improve the scanner.

Test if remote port is in use

FWIW, a Java solution I use from times to times (better than telnet: supports timeout).

package com.acme.util;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

public class CheckSocket {

public static void main(String[] args) {
int exitStatus = 1 ;
if (args.length != 3) {
System.out.println("Usage: CheckSocket node port timeout");
} else {
String node = args[0];
int port = Integer.parseInt(args[1]);
int timeout = Integer.parseInt(args[2]);

Socket s = null;
String reason = null ;
try {
s = new Socket();
s.setReuseAddress(true);
SocketAddress sa = new InetSocketAddress(node, port);
s.connect(sa, timeout * 1000);
} catch (IOException e) {
if ( e.getMessage().equals("Connection refused")) {
reason = "port " + port + " on " + node + " is closed.";
};
if ( e instanceof UnknownHostException ) {
reason = "node " + node + " is unresolved.";
}
if ( e instanceof SocketTimeoutException ) {
reason = "timeout while attempting to reach node " + node + " on port " + port;
}
} finally {
if (s != null) {
if ( s.isConnected()) {
System.out.println("Port " + port + " on " + node + " is reachable!");
exitStatus = 0;
} else {
System.out.println("Port " + port + " on " + node + " is not reachable; reason: " + reason );
}
try {
s.close();
} catch (IOException e) {
}
}
}
}
System.exit(exitStatus);
}
}


Related Topics



Leave a reply



Submit