0

The following code opens a UDP socket, sets up multicast, sends a message and starts a read loop. It uses Selector.select() to read with a timeout.

int TIMEOUT = 10000;
String id = "8154@Think420";

try {
    NetworkInterface iface = NetworkInterface.getByInetAddress(InetAddress.getByName(address));
    try (DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET).setOption(StandardSocketOptions.SO_REUSEADDR, true)) {
        channel.socket().bind(new InetSocketAddress(PORT));
        channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, iface);
        channel.configureBlocking(false);
        InetAddress group = InetAddress.getByName("225.4.5.6");
        MembershipKey key = channel.join(group, iface);

        InetSocketAddress mcast = new InetSocketAddress(key.group(), PORT);
        channel.send(ByteBuffer.wrap(id.getBytes()), mcast);
        Selector selector = Selector.open();
        channel.register(selector, SelectionKey.OP_READ);

        ByteBuffer buffer = ByteBuffer.allocate(4096);
        while (key.isValid()) {
            if (selector.select(TIMEOUT) == 0) {
                System.err.println("timeout");
                continue;
            }

            buffer.clear();
            InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
            buffer.flip();
            String message = Charset.forName("ASCII").decode(buffer).toString();
            System.err.format("From %s received: %s\n", address.getHostString(), message);
        }
    } catch(IOException e) {
        e.printStackTrace();
    }
} catch(UnknownHostException | SocketException e) {
    throw new IllegalArgumentException(e);
}

When I run the first instance of the application, it works correctly: receives a single message from itself and then prints "timeout" in a loop.

Here is a sample output:

From 127.0.0.1 received: 8154@Think420
timeout
timeout
timeout

The problem arises when I run another instance. This one works normally, but the first instance starts to report timeouts immediately, flooding its output. The expected behavior here is that when the second instance starts, both first and second receive one message and then report timeouts every ten seconds. What am I doing wrong?

Alexander Solovets
  • 2,447
  • 15
  • 22

1 Answers1

0

After selector.select() returns, selected keys must be cleared, so the modified loop body becomes

if (selector.select(TIMEOUT) == 0) {
  System.err.println("timeout");
  continue;
}

buffer.clear();
InetSocketAddress address = (InetSocketAddress) channel.receive(buffer);
buffer.flip();
String message = Charset.forName("ASCII").decode(buffer).toString();
System.err.format("From %s received: %s\n", address.getHostString(), message);
selector.selectedKeys().clear()

See Why the key should be removed in `selector.selectedKeys().iterator()` in java nio? for more information.

Alexander Solovets
  • 2,447
  • 15
  • 22