Java NIO Selector doesn't work when not using localhost

Viewed 400

I've been working on a program that uses networking with Java that uses the NIO Selector following this tutorial and for some reason when I try to test the program with my friends (that are far away in another network) it doesn't work, even though when I try to test it myself on only my computer it works perfectly.
Here is the relevant code for the question:

Class EchoServer (a Thread):

private Selector selector;
private ServerSocketChannel serverSocket;
private boolean stop = false;
private List<String> pendingStrings;

public EchoServer() throws IOException {
    // Get selector
    this.selector = Selector.open();
    System.out.println("Selector open: " + selector.isOpen());
    // Get server socket channel and register with selector
    this.serverSocket = ServerSocketChannel.open();
    InetSocketAddress hostAddress = new InetSocketAddress("", NetworkingSettings.PORT);
    serverSocket.bind(hostAddress);
    serverSocket.configur eBlocking(false);
    int ops = serverSocket.validOps();
    SelectionKey selectKy = serverSocket.register(selector, ops, null);
    this.pendingStrings = new ArrayList<>();
}

@Override
public void run() {
    while (!stop) {
        try {
            update();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void update() throws IOException {
    System.out.println("Waiting for select...");
    int noOfKeys = selector.select();

    System.out.println("Number of selected keys: " + noOfKeys);

    Set selectedKeys = selector.selectedKeys();
    Iterator iter = selectedKeys.iterator();

    while (iter.hasNext()) {

        SelectionKey ky = (SelectionKey) iter.next();
        if (ky.isAcceptable()) {
            acceptClient();
        }
        else if (ky.isReadable()) {
            readDataFromClient(ky);
        }
        iter.remove();
    }
}

Class EchoClient:

private SocketChannel client;
private InetSocketAddress hostAddress;
private boolean connected;

public EchoClient(String ip) {
    this.hostAddress = new InetSocketAddress(ip, NetworkingSettings.PORT);
    connected = false;
}

public void connect() throws IOException {
    if (!connected) {
        client = SocketChannel.open(hostAddress);
        connected = true;
    }
}

public void sendMessage(String message) throws IOException {
    try {
        byte[] messageBytes = message.getBytes();
        ByteBuffer buffer = ByteBuffer.wrap(messageBytes);
        client.write(buffer);
        buffer.clear();
    } catch (IOException e) {
        cleanUp();
    }
}

Now, it seems that the problem is in the server because I can't even connect to the server when my friend runs it (and I am the client). I suspect the source of the problem are those lines in EchoServer:

InetSocketAddress hostAddress = new InetSocketAddress("", NetworkingSettings.PORT);
serverSocket.bind(hostAddress);

But I can't seem to figure out what is it.

Important Note:NetworkingSettings.PORT is 80, I know it's a port used for http and maybe that is the problem, but I really want to avoid needing to use port forwarding and firewall settings.

1 Answers

The problem lies with the InetSocketAddress the ServerSocketChannel binds to. To allow connections on both localhost and remote network interfaces, you need to bind to the wildcard address. This is done by using the InetSocketAddress constructor that only takes a port number:

InetSocketAddress hostAddress = new InetSocketAddress(NetworkingSettings.PORT);
Related