0

I have Java code that sets up a server on a particular port, some code is run in python that uses this server, and then the port is closed. I've set it up so that after each python run, the java loops and repeats this process (setting up a new server, serving, then closing).

I notice that when the python call is short (about <10s), that the next time Java tries to set up this port, it will fail. Are there rules about how long you must wait between successively setting up the same port on Java?

Chris Nauroth
  • 8,804
  • 1
  • 29
  • 37
  • 2
    This is probably os dependent. – Robert Jul 26 '17 at 04:31
  • 2
    Typically, you would leave the server socket open and just accept and then close the incoming connection. Then wait for the next incoming connection on the same server socket. – Henry Jul 26 '17 at 04:38

2 Answers2

1

Ports can be finicky with this type of thing. They're not meant to be opened and closed all the time. You should leave the socket open and just handle each connection within, like this:

    ServerSocket listener = new ServerSocket(9090);
    try {
        while (true) {
            Socket socket = listener.accept();
            try {
                PrintWriter out =
                    new PrintWriter(socket.getOutputStream(), true);
                out.println(new Date().toString());
            } finally {
                socket.close();
            }
        }
    }
    finally {
        listener.close();
    }

(credit: http://cs.lmu.edu/~ray/notes/javanetexamples/)

Daniel Centore
  • 2,968
  • 1
  • 15
  • 35
  • 1
    No, you should start a separate thread for each incoming connection. If you don't then your server cannot do anything else while your socket handler is running. – Jim Garrison Jul 26 '17 at 04:49
  • 2
    @JimGarrison OP implied only a single client at a time. I see no reason to introduce complexity if it's not necessary. – Daniel Centore Jul 26 '17 at 04:50
  • @DanielCentore It *is* nessary. Any I/O to the accepted socket can block, which holds up the next connection if it is done in the accept thread. – user207421 Jul 26 '17 at 05:30
  • @EJP I understood it as the python script having exited already before a new connection is made. You might get, what, 1 second of blocking as it closes? Hardly justification for multithreaded complexity in a simple application, especially since the new connection will block, not fail. If OP clarifies their high level goals then it might invite revisitation. – Daniel Centore Jul 26 '17 at 05:38
  • @DanielCentore You *can* get an *infinite* block as it *reads* or *writes.* There is no evidence in the question that the interaction is as simple as your tiny example. – user207421 Jul 26 '17 at 10:06
1

In general, it is better to maintain a long-running ServerSocket that serves multiple requests, as others have already answered and commented. However, I have found that sometimes there is a legitimate need to stop and start a server in rapid succession. One example is an integration test suite that involves stopping and restarting the server in different configurations to repeat test runs.

If you really have this need, then you might be interested in ServerSocket#setReuseAddress(boolean).

Enable/disable the SO_REUSEADDR socket option. When a TCP connection is closed the connection may remain in a timeout state for a period of time after the connection is closed (typically known as the TIME_WAIT state or 2MSL wait state). For applications using a well known socket address or port it may not be possible to bind a socket to the required SocketAddress if there is a connection in the timeout state involving the socket address or port.

Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even though a previous connection is in a timeout state.

This ultimately enables the SO_REUSEADDR socket option. One source of information for more details on these socket options is the Linux socket man page.

However, please be aware that the exact perceived behavior can very greatly across different platforms. In particular, beware of the extremely different and dangerous behavior of this setting on Windows, as documented in the MSDN article Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE. Basically, SO_REUSEADDR on Windows can allow any arbitrary process to "steal" a socket already in use by another process, resulting in indeterminate behavior.

The SO_REUSEADDR socket option allows a socket to forcibly bind to a port in use by another socket. The second socket calls setsockopt with the optname parameter set to SO_REUSEADDR and the optval parameter set to a boolean value of TRUE before calling bind on the same port as the original socket. Once the second socket has successfully bound, the behavior for all sockets bound to that port is indeterminate. For example, if all of the sockets on the same port provide TCP service, any incoming TCP connection requests over the port cannot be guaranteed to be handled by the correct socket — the behavior is non-deterministic. A malicious program can use SO_REUSEADDR to forcibly bind sockets already in use for standard network protocol services in order to deny access to those service. No special privileges are required to use this option.

I advise people to think carefully and make sure you're confident with this setting rather than blindly turning it on. There is also a phenomenal prior question and answer about the relevant socket options:

Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?

Chris Nauroth
  • 8,804
  • 1
  • 29
  • 37
  • Hard to see why Microsoft don't fix their SO_REUSEADDR implementation to agree with everyone else's, instead of having to scatter warnings about it all over the place. The following paragraph about a client and then a server binding to the same port doesn't even make sense. – user207421 Jul 26 '17 at 05:34
  • @EJP , great question! Perhaps they keep the behavior for the almighty backward-compatibility? I don't know. – Chris Nauroth Jul 26 '17 at 05:37
  • I suspect they may have some in-house 'feature' that relies on this bug. – user207421 Jul 26 '17 at 10:04