javaudpnettyniomulticast

Multiple Netty clients listening on the same multicast group


I am trying to get multiple Netty clients listening on the same multicast group address.

The issue with running these clients on the same machine is that each client is bound to the same port (group port) which results in port clash.

It is generally possible to run multiple clients listening on the same address so how can this be achieved with Netty?

Here is code of the client:

package com.something.tools.udp;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;

public class SimpleMulticastClient {
    public static void main(String[] args) throws InterruptedException, SocketException {
        String groupAddress = args[0];
        int groupPort = Integer.parseInt(args[1]);
        String interfaceName = args[2];

        Bootstrap b = new Bootstrap();
        b.option(ChannelOption.SO_RCVBUF, 1048576);
        b.group(new NioEventLoopGroup())
                .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                    @Override
                    public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) {
                        System.out.println("Received: " + msg);
                    }
                })
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1000))
                .option(ChannelOption.SO_REUSEADDR, Boolean.TRUE);

        NetworkInterface networkInterface = NetworkInterface.getByName(interfaceName);
        DatagramChannel channel = (DatagramChannel)b
                .channelFactory(() -> new NioDatagramChannel(InternetProtocolFamily.IPv4))
                .localAddress(0)
                .bind(groupPort).sync().channel();
        System.out.println("UDP client bound to: " + channel.localAddress());
        channel.joinGroup(new InetSocketAddress(groupAddress, groupPort), networkInterface).sync();
    }
}

If I run a single client I can receive multicast traffic OK:

UDP client bound to: /0.0.0.0:19000
Received: DatagramPacket(/192.168.0.4:57335 => /0.0.0.0:19000, PooledUnsafeDirectByteBuf(ridx: 0, widx: 4, cap: 1000))
Received: DatagramPacket(/192.168.0.4:57335 => /0.0.0.0:19000, PooledUnsafeDirectByteBuf(ridx: 0, widx: 4, cap: 1000))
...

If I try to start a second client on the same machine (with the same arguments), I get this exception:

Exception in thread "main" java.net.BindException: Address already in use

I've also tried to change this line:

    .bind(groupPort).sync().channel();

to:

    .bind(0).sync().channel();

and that allows to run both clients simultaneously (i.e. no port clash). However the clients then stop seeing the multicast traffic.

Is there a way to make this working with Netty?


Solution

  • I've found the answer in this post: multicast bind - Address already in use

    I need to bind on the multicast port and use SO_REUSEADDR option which allows multiple clients bind on the same address. With this change I'm able to run more than one client and see multicast traffic.

    I've updated the code in original post to reflect this.