Multicasting

What is multi cast.

Muticast in a datagram network is the transmission of the data packet to a subset of hosts.
The basic benefit of multicast is that any source can send down its data to required destination, which is not a single host but can be a group of hosts sharing a common address. So the sender sees the destination as a single host. Hence the duty of sender is completed, once it sends a single data packet destined to the abstract group. Even the intermediate routers have no idea regarding the exact set of hosts.
If multicast was not supposed to be used, then source has to send the data packets one for each host. Moreover multicast encapsulates the actual hosts.
The destination host should subscribe to receive the messages from a source to that group. The host can unsubscribe whenever it intends to do so.

Multicasting in Java

Sending multicast datagrams

In order to send any kind of datagram in Java, be it unicast, broadcast or multicast, one needs a java.net.DatagramSocket:

DatagramSocket socket = new DatagramSocket();

One can optionally supply a local port to the DatagramSocket constructor to which the socket must bind. This is only necessary if one needs other parties to be able to reach us at a specific port. A third constructor takes the local port AND the local IP address to which to bind. This is used (rarely) with multi-homed hosts where it is important on which network adapter the traffic is received. Neither of these is necessary for this example.

This sample code creates the socket and a datagram to send and then simply sends the same datagram every second:

DatagramSocket socket = new DatagramSocket();

byte[] b = new byte[DGRAM_LENGTH];

DatagramPacket dgram;

dgram = new DatagramPacket(b, b.length,

InetAddress.getByName(MCAST_ADDR), DEST_PORT);

System.err.println("Sending " + b.length + " bytes to " +

dgram.getAddress() + ':' + dgram.getPort());

while(true) {

System.err.print(".");

socket.send(dgram);

Thread.sleep(1000);

}

Valid values for the constants are:

  • DGRAM_LENGTH: anything from 0 to 65507 , eg 32
  • MCAST_ADDR: any class D address , eg 235.1.1.1
  • DEST_PORT: an unsigned 16-bit integer, eg. 7777

It is important to note the following points:

  1. DatagramPacket does not make a copy of the byte-array given to it, so any change to the byte-array before the socket.send() will reflect in the data actually sent;
  2. One can send the same DatagramPacket to several different destinations by changing the address and or port using the setAddress() and setPort() methods;
  3. One can send different data to the same destination by changing the byte array referred to using setData() and setLength() or by changing the contents of the byte array the DatagramPacket is referring to;
  4. One can send a subset of the data in the byte array by manipulating offset and length through the setOffset() and setLength() methods.
Receiving multicast datagrams

One can use a normal DatagramSocket to send and receive unicast and broadcast datagrams and to send multicast datagrams as seen in the section 2. In order to receive multicast datagrams, however, one needs a MulticastSocket. The reason for this is simple, additional work needs to be done to control and receive multicast traffic by all the protocol layers below UDP.

The example given below, opens a multicast socket, binds it to a specific port and joins a specific multicast group:

byte[] b = new byte[BUFFER_LENGTH];

DatagramPacket dgram = new DatagramPacket(b, b.length);

MulticastSocket socket =

new MulticastSocket(DEST_PORT); // must bind receive side

socket.joinGroup(InetAddress.getByName(MCAST_ADDR));

while(true) {

socket.receive(dgram); // blocks until a datagram is received

System.err.println("Received " + dgram.getLength() +

" bytes from " + dgram.getAddress());

dgram.setLength(b.length); // must reset length field!

}

Values for DEST_PORT and MCAST_ADDR must match those in the sending code for the listener to receive the datagrams sent there. BUFFER_LENGTH should be at least as long as the data we intend to receive. If BUFFER_LENGTH is shorter, the data will be truncated silently and dgram.getLength() will return b.length.

The MulticastSocket.joinGroup() method causes the lower protocol layers to be informed that we are interested in multicast traffic to a particular group address. One may execute joinGroup() many times to subscribe to different groups. If multiple MulticastSockets bind to the same port and join the same multicast group, they will all receive copies of multicast traffic sent to that group/port.

As with the sending side, one can re-use ones DatagramPacket and byte-array instances. The receive() method sets length to the amount of data received, so remember to reset the length field in the DatagramPacket before subsequent receives, otherwise you will be silently truncating all your incoming data to the length of the shortest datagram previously received.

One can set a timeout on the receive() operation using socket.setSoTimeout(timeoutInMilliseconds). If the timeout is reached before a datagram is received, the receive() throws a java.io.InterruptedIOException. The socket is still valid and usable for sending and receiving if this happens.