Multicast Sockets in Java

1. MULTICASTING

In all the programs that we have developed so far, the data is destined to only one target. In other words, the number of receivers in all those cases was only one. This type of communication is known as uni-cast. Though many applications use this style of communication, there are instances, where a sender application wants to send data to multiple receivers. Multicasting allows sending packets from one host to many other hosts. Packets are sent to a group having an address called multicast address. The hosts who are interested to receive the packet must join the group.

Note that one of the possible alternatives of multicasting is to send a packet to each of the intended receivers using UDP or TCP. However, this solution has some inherent problems. For example, the sender should have enough processing power as it sends packets to every receiver. The solution also consumes a significant network bandwidth as packets are duplicated needlessly.

Multicasting handles this problem intelligently. In this method, only one packet is created specifying an address. This address does not represent a specific address. Rather, it essentially represents a group of recipients. To send the packet to multiple intended receivers, the packet is placed on to the network. This packet reaches every host in the network, but only interested hosts accept the packet. Other hosts get the packet but reject it.

2. MULTICAST SOCKETS

Java provides MuiticastSocket class that implements the idea of multicasting and allows an application to send a single datagram to a group of recipients in a network (see figure below). The hosts in the group may reside in the same subnet or different subnets connected by multicast-capable routers.

Multicast usually refers to IP Multicast, which is a method for efficiently sending packets to multiple receivers at the same time on TCP/IP networks, using multicast addresses.

2.1. Multicast Addresses

A multicast address is a single IP address that represents multiple network devices forming a group. In other words, many network devices may use a single multicast address. The meaning of using a multicast address is to express its willingness to belong to a group. The multicast address can then be used to identify the group (hence all the devices of that group).

We know that IPv4 addresses are categorized into 5 (five) classes [Figure 13.27:] depending on the higher order bits. The addresses that start with 1110 are said to belong to class D and are known as multicast addresses. Class D IP addresses are in the range 224.0.0.0 to 239.255.255.255

The assignment of IP multicast addresses differs from assignment of unicast IP addresses. Note that IP unicast blocks of addresses are delegated to regional entries. However, multicast addresses are assigned by the Internet Assigned Numbers Authority (IANA) directly. Table 13.2 summarizes the current assignments.

2.2. MulticastSocket Class

Remember that DatagramSocket class itself allows exchanging of packets between exactly two programs. Java provides another class MulticastSocket which is a direct subclass of DatagramSocket class. Note that this class provides all the functionalities of DatagramSocket class. However, it provides a few additional facilities so that a packet can be received by many programs belonging to a common group having an address called multicast address. It also provides methods for joining and leaving a multicast group.

Note that multicasting also allows us to send data across networks. In order to control the scope of multicast (i.e. how far a datagram is allowed to traverse), MulticastSocket allows us to specify a value of Time-To-Live (TTL) field in the IP datagram header. Note that TTL is used to avoid a datagram being looped forever. Routers, upon receiving a packet, decrements the TTL by one and discards the packet if the value becomes 0 (zero).

For multicasting, the TTL field is used to avoid a multicast datagram being traversed forever. and works as follows: A TTL threshold is specified for each interfaces of a router (called multicast capable router). The sender of the packet also specifies a TTL value. The multicast capable router forwards only those multicast datagrams having a TTL value greater than the threshold. A list of TTL threshold with their meaning is shown in Table 15.2:

In the next few sections, we shall develop a simple multicasting application. Our first application consists of two programs:

  • A sender program that sends a single packet containing the message “Hello!” to a group having a multicast address 224.0.0.1.
  • A receiver program that joins the group and listens on port 83 7 9 to receive the hello packet.

Note that the receiver must be started first and must be ready to accept packets. Once the receiver is ready, sender program may be started.

2.3. Sending Data

Note that a normal DatagramSocket may be used to send any kind of datagram, be it unicast, broadcast or multicast. Since, in our first example, server program will only send packets, a DatagramSocket is sufficient to do that. However, a MuiticastSocket may be created if it is required to send as well as to receive packets. In our first application, we shall use DatagramSocket. Later, we shall develop more complex applications where programs will use MuiticastSocket to send and receive multicast packets.

To send data, let us create a DatagramSocket as follows:

DatagramSocket socket = new DatagramSocket();

An optional port number may be specified if one needs other parties to be able to reach this socket. Since our socket is not intended to receive any packets, port is not specified. This socket is now ready to deliver packets. Let us create a DatagramPacket that contains a buffer (byte array) containing a string “Hello!”. The following code creates such a buffer:

String msg = “Hello!”;

byte[] out = msg.getBytes();

The DatagramPacket may then be created as follows:

InetAddress group = InetAddress.getByName(“224.0.0.1”);

int port = 8379;

DatagramPacket packet = new DatagramPacket(out, out.length, group, port);

Note that the multicast address 224.0.0.1 indicates a group consisting of all hosts within the network. We shall use this address so that a receiver program on a remote host within the subnet may also receive packet. We assume that the receiver listens on port 83 7 9. To send the packet we call send() method on the DatagramSocket object specifying the packet to be sent.

socket.send(packet);

2.4. Receiving Data

We have mentioned in the previous section that a normal DatagramSocket may be used to send any kind of datagram, be it unicast, broadcast or multicast. However, DatagramSocket can only receive unicast and broadcast packets. Since our client wants to receive multicast packets (i.e. packets having multicast address in its header), a MuiticastSocket must be created.

Note that receiving broadcast packets is easier than multicast packets. To receive broadcast packets, processes need not do any extra thing. This is because, broadcast packets are always accepted by the underlying layers and forwarded to the proper applications. However, to receive multicast packets, processes must inform the underlying layer which multicast groups they are interested in. Multicast datagrams are then filtered by underlying MAC or IP (or sometimes both) and datagrams having a previously registered destination group are only accepted and forwarded to the registered processes. When a socket joins a group having an address addr, essentially it tells the kernel as follows:

Hey kernel, I know that you reject all multicast datagrams by default. However, I am interested in receiving multicast packets having address addr. So, if you get any datagram having destination address addr, don’t reject them and instead kindly forward them to me (as well as other sockets who are interested in them). Since, a normal DatagramSocket does not have any such functionality, we used MulticastSocket which provided this additional facility.

The following code creates a MulticastSocket that is bound to the port 83 7 9.

MulticastSocket socket = new MulticastSocket(8379);

The joinGroup() method of a MulticastSocket can inform the underlying protocol layers that it is interested in receiving multicast packets having a particular multicast address in the header. To join the group having address 224.0.0.1, the following code is used.

socket.joinGroup(InetAddress.getByName(”224.0.0.1”));

To join the different groups, this method may be called repeatedly with a different multicast address. The socket will then receive all the packets destined to groups to which it was registered. Similarly, all the sockets of a group will receive copies of multicast packets sent to that group. The only difference between a multicast receiver and a normal receiver is that a multicast receiver joins a group. The remaining part is exactly same as a normal receiver. So, to receive a packet, we create a DatagramPacket object as follows:

byte[] in = new byte[256];

DatagramPacket packet = new DatagramPacket(in, in.length);

Finally the packet is received using received method.

socket.receive(packet);

2.5. Complete Example

Here is the complete source code of the sender stored in the file HelloSender.java.

//HelloSender.java

import java.net.*;

public class HelloSender {

public static void main(String[] args) {

try

{

//Create a DatagramSocket

DatagramSocket socket = new DatagramSocket();

//Fill the buffer with data String msg = “Hello!”;

byte[] out = msg.getBytes();

//Muticast group where packet has to sent

InetAddress group = InetAddress.getByName(”224.0.0.1”);

//Port the receiver listens on int port = 8379;

//Create a DatagramPacket with buffer, address and port

DatagramPacket packet = new DatagramPacket(out, out.length, group, port);

//Send to multicast IP address and port

System.out.println(”Sending a packet…”);

//Send the packet now socket.send(packet);

System.out.println(”Sent : ” + msg);

}

catch (Exception e) { e.printStackTrace();

}

}

}

Here is the complete source code of the receiver stored in the file HelloReceiver.java.

//HelloReceiver.java

import java.net.*;

public class HelloReceiver {

public static void main(String[] args) {

try {

//Create a MulticastSocket and bind it to port 8379

MulticastSocket socket = new MulticastSocket(8379);

//Join to multicast group

socket.joinGroup(InetAddress.getByName(”224.0.0.1”));

//Construct a DatagramPacket to receive packet byte[] in = new byte[256];

DatagramPacket packet = new DatagramPacket(in, in.length);

System.out.println(“Waiting to receive a packet…”);

//Receive the packet now and display socket.receive(packet);

String msg = new String(in, 0, packet.getLength());

System.out.println(“Received : ” + msg);

} catch (Exception ioe) {

System.out.println(ioe);

}

}

}

Compile these programs. To run this application, we started three receivers in three separate computers. The sender was then started in one computer. A sample output is shown in Figure 13.28:

2.6. Another Multicasting Example

In this application, a program continuously multicasts the score (runs) of a cricket match going on between two teams. The score is generated artificially. Any program that wants to know the current score may join the group and get the score. Since, the sender multicasts the score continuously, the receiver of the score may be started at any time.

Here is the complete source code of the program that multicasts the score stored in the file.

ScoreSendor.j ava.

import aava.io.*;

import aava.not.*;

import aava.util.Randsm;

public class rcorodondor {

public static void main(dtring[] args) {

long scoro = 0, run;

Random r = now Random();

try {

int port = 8379;

InotAddross group = InotAddross.gotByNamo(args[0]);

//Croato a Datagramdockot

Datagramdockot sockot = now Datagramdockot();

whilo (truo) {

//Fill tho buffor with scoro gonoratod artificially

do {

Throad.sloop(1000+r.noxtInt(1000));

}whilo((run = r.noxtInt(7)) == 0);

scoro += run;

String msg = “scoro: ” + scoro; byto[] out = msg.gotBytos();

//Croato a DatagramPackot

DatagramPacket pkt = new DatagramPacket(out, out.length, group, port);

//Send the pkt

socket.send(pkt);

System.out.println(“Sent–>” + msg);

}

} catch (Exception e) { e.printStackTrace();

}

}

}

Here is the complete source code of the program that receives the score stored in the file.

ScoreReceiver.java. import java.io.*;

import java.net.*;

public class ScoreReceiver {

public static void main(String[] args)

{ byte[] inBuffer = new byte[256];

try {

InetAddress address = InetAddress.getByName(“224.0.0.1”);

//Create a MulticastSocket

MulticastSocket socket = new MulticastSocket(8379);

//Join to the multicast group socket.joinGroup(address);

while (true) {

DatagramPacket packet = new DatagramPacket(inBuffer, inBuffer.length);

socket.receive(packet);

String msg = new String(inBuffer, 0, packet.getLength());

System.out.println(“Received<–” + msg);

}

} catch (IOException ioe) {

System.out.println(ioe);

}

}

}

A sample output is shown in Figure 13.29:

2.7. A Text Conference Example

Text mode conferencing and bulletin-board are the oldest models of communication. In these models of communications, text messages are exchanged among two or more people using a terminal. They have some distinct advantages over their counterpart audio/video conferencing.

  • They require the least bandwidth as only plain text messages are exchanged.
  • Developing applications supporting this model is very easy.

In this section, we shall develop a simple application that supports text conferencing. The application deals with two issues: i) sending text messages supplied by the member to all other participating members of the conference and ii) receiving those text messages. Since a message may arrive, while one is typing a message, we create two child threads from the main thread. One takes the responsibility to send the message being supplied through the keyboard and another one receives the message and displays in the terminal window. Here is the complete source code of the program stored in the file MulticastSenderReceiver.java.

//MulticastSenderReceiver.java

import java.io.*;

import java.net.*;

public class MulticastSenderReceiver

{

String name;

InetAddress addr; int port = 3456;

MulticastSocket group;

public static void main(String[] args){ new MulticastSenderReceiver(args[0]);

}

MulticastSenderReceiver(String name) { this.name = name; try {

addr = InetAddress.getByName(“224.0.0.1”);

group = new MulticastSocket(port);

new Receiver().start();

new Sender().start();

}catch(Exception e){e.printStackTrace( );}

}

private class Sender extends Thread

{ public void run()

{

try {

BufferedReader fromUser = new BufferedReader(new

InputStreamReader(System.in));

while(true) {

String msg = name + ”:” + fromUser.readLine();

byte[] out = msg.getBytes();

DatagramPacket pkt = new DatagramPacket(out, out.length, addr, port);

group.send(pkt);

}

}catch(Exception e ) {e.printStackTrace();}

}

}

private class Receiver extends Thread

{

public void run()

{

try {

byte[] in = new byte[256];

DatagramPacket pkt = new DatagramPacket(in, in.length);

group.joinGroup(addr);

while(true) {

group.receive(pkt);

System.out.println(new String(pkt.getData(), 0, pkt.getLength()));

}

}catch(Exception e ) {e.printStackTrace();}

}

}

}

A snapshot of the text conference involving four people is shown in Figure 13.30:

Source: Uttam Kumar Roy (2015), Advanced Java programming, Oxford University Press.

Leave a Reply

Your email address will not be published. Required fields are marked *