2

I try to check if port 80 is available using the following method :

Sockets: Discover port availability using Java

I have a Java application that checks if port 80 is available, if so, it runs a small web server listening on port 80. It works great to detect if another Java application listens on port 80, e.g. if I run my application two times, the second instance will correctly tell me that the port 80 is being used.

The problem is that I have WAMP running and listening on port 80, and that if I run my Java application after I started WAMP, it won't tell me that the port 80 is busy. It seems that it only tells me if another Java application uses the port 80.

That goes beyond my understanding ... any help is greatly appreciated!

Code snippet:

int port = 80;
if(!Connection.isPortAvailable(port)) {
    logger.info("Port " + port + " is already in use");
}
// in Connection class
public static boolean isPortAvailable(int port) {
    ServerSocket ss = null;
    DatagramSocket ds = null;
    try {
        ss = new ServerSocket(port);
        ss.setReuseAddress(true);
        ds = new DatagramSocket(port);
        ds.setReuseAddress(true);
        return true;
    } catch (IOException e) {
    } finally {
        if (ds != null) {
            ds.close();
        }

        if (ss != null) {
            try {
                ss.close();
            } catch (IOException e) {
                /* should not be thrown */
            }
        }
    }

    return false;
}
Community
  • 1
  • 1
Matthew
  • 10,988
  • 11
  • 54
  • 69
  • "It seems that it only tells me if another Java application uses the port 80." I highly doubt that. Are you sure? – leonbloy Mar 30 '13 at 13:19
  • Which solution are you using (the Apache camel example)? Can you provide a brief code snippet? – Kevin Tonon Mar 30 '13 at 13:22
  • @leonbloy to prove you: I have WAMP opened. If I access e.g. localhost, WAMP is serving the request. Then I start my Java application, and it doesn't say that the port 80 is busy. Only when I run the application again (I have two isntances now), then the port is busy. – Matthew Mar 30 '13 at 13:25
  • @KevinTonon I added the code snippet, also read my comment above for leonbloy – Matthew Mar 30 '13 at 13:27
  • In the linked question, there are comments about that logic failing in some cases (OS-X, Java 7...) Weird. Suggestion: if you just need to find an unused port for opening a listening server, use `new ServerSocket(0)` instead. – leonbloy Mar 30 '13 at 13:48
  • Have you tried the other approach of opening a connection to localhost :80 to see if there is something on the other side? – Jorge Cardoso Mar 30 '13 at 13:53
  • You're calling setReuseAddress() too late in the code for it to have any effect, but given what you're trying to do, you shouldn't be calling it at all. – user207421 Mar 30 '13 at 23:55
  • Is the web server you're launching in the same java process? If so, see @EJP's response about 'try to use it and catch the exception'. – seand Mar 31 '13 at 00:59

2 Answers2

2

The correct answer to all questions of this nature is to try to use it and catch the exception. Not try to see if it's available and then try to use it and still have to handle the exception, which has several obvious problems:

  1. There is a timing window between 'see' and 'try' during which the situation can change (both ways).
  2. You still have to catch failures in the 'use' part anyway.
  3. It is basically just trying to predict the future. This is supposed to be computer science, not fortune-telling.

This applies to most values of 'it', including network ports, files, any resource really.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • good point wrt the timing window issue. The port availability test itself briefly ties up a listening port so it can *cause* connectivity issues. This test is probably ok for general use but I wouldn't uses it in a nuclear power plant control system :) – seand Mar 31 '13 at 00:44
  • I wouldn't use it at all. It is poor programming, it is extra programming, 100% redundant, and you have to write two lots of error handling instead of one. – user207421 Mar 31 '13 at 00:55
1

I was able to reproduce your problem by running WampServer (verified that it was running by visiting localhost:80) and running a minimal java program given your example code.

The code in the try block did not throw an exception when WampServer was running. However, modify the first few lines of the try block like this

ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));

and isPortAvailable will properly detect when WampServer is running and when it is not. Using "0.0.0.0" instead of "127.0.0.1" didn't work with WampServer, but did properly detect when IIS was running. You can check both by closing the first socket

ss = new ServerSocket();
ss.bind(new InetSocketAddress("0.0.0.0", port));
ss.close();

ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));
Kevin Tonon
  • 965
  • 10
  • 18
  • The call to getReuseAddress() should be removed. It's already too late after the bind(), but in any case it is contrary to the intention of the code. – user207421 Mar 30 '13 at 23:56
  • VG good investigation. +1. It's surprising that the OP's bind to 0.0.0.0 apparently succeeds after WAMP's bind to 127.0.0.1. IP-specific binds to the same port can coexist if the IPs are different, but a bind to 0.0.0.0 can't coexist with any of them. I'm sure that's what it says in Stevens, *TCP/IP Illustrated,* somewhere. – user207421 Mar 31 '13 at 00:43