zeromq / jeromq

JeroMQ is a pure Java implementation of the ZeroMQ messaging library, offering high-performance asynchronous messaging for distributed or concurrent applications.
https://zeromq.org
Mozilla Public License 2.0
2.36k stars 485 forks source link

bindToRandomPort is binding to ports already used by other processes in Mac OS X #313

Open pmalipio opened 8 years ago

pmalipio commented 8 years ago

I have a port range defined for multiple purposes used by several processes. At this point, these ports are used both for RMI and also for Jeromq. Running my application in Linux it works ok. Nonetheless, when I run it on a Mac, it fails because bindToRandomPort binds the socket to a port already used by a RMI Server. The RMI Server binds the socket to any address ("tcp://*") while Jeromq socket binds to localhost. If, instead of binding the socket to localhost I use any address, then it works but I don't want to expose the port in other addresses rather than the localhost. This problem seems to be related with the socket option reuseAddress being set to true. Shouldn't this socket option be configurable?

daveyarwood commented 7 years ago

The implementation of bindToRandomPort seems a little bit brittle. We're looping through all the ports in a certain range (which may or may not be truly available) and trying to bind to them until we find one that works.

I wonder if something like this might be a more robust solution?

public static int findOpenPort() throws IOException
{
    ServerSocket tmpSocket = new ServerSocket(0);
    int portNumber = tmpSocket.getLocalPort();
    tmpSocket.close();
    return portNumber;
}

int port = findOpenPort();
socket.bind("tcp://127.0.0.1:" + port);

new ServerSocket(0) is a tried-and-true way to find an available port in the dynamic range.

daveyarwood commented 7 years ago

Information needed: a second opinion on the above.

sigiesec commented 7 years ago

The current implementation is not really good, but the proposed new solution is subject to a race condition: The port may be used by someone else between tmpSocket.close and the subsequent bind.

The tmpSocket should rather not be closed, but directly be used for communication.