Working with Multicast Sockets

Enough theory. In Java, you multicast data using the java.net.MulticastSocket class. This is a subclass of java.net.DatagramSocket:

public class MulticastSocket extends DatagramSocket

As you would expect, MulticastSocket’s behavior is very similar to DatagramSocket’s: you put your data in DatagramPacket objects that you send and receive with the MulticastSocket. Therefore, I won’t repeat the basics; this discussion assumes that you already know how to work with datagrams. However, if you’re jumping around in this book rather than reading it cover to cover, now might be a good time to go back and read the previous chapter on UDP.

To receive data that is being multicast from a remote site, you first create a MulticastSocket with the MulticastSocket( ) constructor. Next, you join a multicast group using the MulticastSocket’s joinGroup( ) method. This signals the routers in the path between you and the server to start sending data your way and tells the local host that it should pass you IP packets addressed to the multicast group.

Once you’ve joined the multicast group, you receive UDP data just as you would with a DatagramSocket. That is, you create a DatagramPacket with a byte array that serves as a buffer for data, and enter a loop in which you receive the data by calling the receive( ) method inherited from the DatagramSocket class. When you no longer want to receive data, you leave the multicast group by invoking the socket’s leaveGroup( ) method. You can then close the socket with the close( ) method inherited from DatagramSocket.

Sending data to a multicast address is similar to sending UDP data to a unicast address. You do not need to join a multicast group to send data to it. You create a new DatagramPacket, stuff the data and the address of the multicast group into the packet, and pass it to the send( ) method. The one difference is that you must explicitly specify the packet’s TTL value.

There is one caveat to all this: multicast sockets are a security hole big enough to drive a small truck through. Consequently, untrusted applets are not allowed to do anything involving multicast sockets. An untrusted applet is allowed to send datagrams to or receive datagrams from the applet host. However, multicast sockets don’t allow this sort of restriction to be placed on the packets they send or receive. Once you send data to a multicast socket, you have very limited and unreliable control over which hosts do and do not receive that data. Consequently, most applet environments take the conservative approach of disallowing all multicasting.

The Constructors

The constructors are simple. Each one calls the equivalent constructor in the DatagramSocket superclass.

public MulticastSocket( ) throws SocketException

This constructor creates a socket that is bound to an anonymous port (i.e., an unused port assigned by the system). It is useful for clients (i.e., programs that initiate a data transfer), because they don’t need to use a well-known port: the recipient replies to the port contained in the packet. If you need to know the port number, you can find out with the getLocalPort( ) method inherited from DatagramSocket. This constructor throws a SocketException if the Socket can’t be created. For example:

try {
  MulticastSocket ms = new MulticastSocket(  );
  // send some datagrams...
}
catch (SocketException se) {
  System.err.println(se);
}

public MulticastSocket(int port) throws SocketException

This constructor creates a socket that receives datagrams on a well-known port. The port argument specifies the port on which this socket listens for datagrams. As with regular TCP and UDP unicast sockets, on a Unix system a program needs to be run with root privileges to create a MulticastSocket on a port numbered from 1 to 1,023.

This constructor throws a SocketException if the Socket can’t be created. A Socket can’t be created if you don’t have sufficient privileges to bind to the port, or that the port you’re trying to connect to is already occupied. Note that since, as far as the operating system is concerned, a multicast socket is a datagram socket, a MulticastSocket cannot occupy a port already occupied by a DatagramSocket, and vice versa. For example, this code fragment opens a multicast socket on port 4,000:

try {
  MulticastSocket ms = new MulticastSocket(4000);
  // receive incoming datagrams...
}
catch (SocketException se) {
  System.err.println(se);
}

Communicating with a Multicast Group

Once a MulticastSocket has been created, it can perform four key operations. These are:

  1. Join a multicast group.

  2. Send data to the members of the group.

  3. Receive data from the group.

  4. Leave the multicast group.

The MulticastSocket class has methods for operations 1, 2, and 4. No new method is required to receive data. The receive( ) method of the superclass, DatagramSocket, is all that’s needed for receiving. You can perform these operations in any order, with the exception that you must join a group before you can receive data from it (or, for that matter, leave it). You do not need to join a group to send data to it, and the sending and receiving of data may be freely interwoven.

public void joinGroup(InetAddress address) throws IOException

To receive data from a MulticastSocket, you must first join a multicast group. To join a group, pass an InetAddress object for the multicast group to the joinGroup( ) method. If you successfully join the group, you’ll receive any datagrams intended for that group. Once you’ve joined a multicast group, you receive datagrams exactly as you receive unicast datagrams, as shown in the previous chapter. That is, you set up a DatagramPacket as a buffer and pass it into this socket’s receive( ) method. For example:

try {
  MulticastSocket ms = new MulticastSocket(4000);
  InetAddress ia = InetAddress.getByName("224.2.2.2");
  ms.joinGroup(ia);
  byte[] buffer = new byte[8192];
  while (true) {
    DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
    ms.receive(dp);
    String s = new String(dp.getData(  ), "8859_1");
    System.out.println(s);
  }
}
catch (IOException ie) {
  System.err.println(ie);
}

If the address that you try to join is not a multicast address (that is, it is not from 224.0.0.0 to 239.255.255.255), the joinGroup( ) method throws an IOException.

A single MulticastSocket can join multiple multicast groups. Information about membership in multicast groups is stored in multicast routers, not in the object. In this case, you’d use the address stored in the incoming datagram to determine which address a packet was intended for.

Multiple multicast sockets on the same machine and even in the same Java program can all join the same group. If so, they’ll all receive all data addressed to that group that arrives at the local host.

public void leaveGroup(InetAddress address) throws IOException

The leaveGroup( ) method signals that you no longer want to receive datagrams from the specified multicast group. A signal is sent to the appropriate multicast router telling it to stop sending you datagrams. If the address you try to leave is not a multicast address (that is, it is not from 224.0.0.0 to 239.255.255.255), the method throws an IOException. However, no exception occurs if you leave a multicast group you never joined.

public void send(DatagramPacket packet, byte ttl) throws IOException

Sending data with a MulticastSocket is similar to sending data with a DatagramSocket. Stuff your data into a DatagramPacket object and send it off using the send( ) method inherited from DatagramSocket:

public void send(DatagramPacket p) throws IOException

The data is sent to every host that belongs to the multicast group to which your packet is addressed. For example:

try {
  InetAddress ia = InetAddress.getByName("experiment.mcast.net");
  byte[] data = "Here's some multicast data
".getBytes(  );
  int port = 4000;
  DatagramPacket dp = new DatagramPacket(data, data.length, ia, port);  
  MulticastSocket ms = new MulticastSocket(  );
  ms.send(dp);
}
catch (IOException ie) {
  System.err.println(ie);
}

However, the MulticastSocket class adds an overloaded variant of the send( ) method that lets you provide a value for the Time-To-Live field ttl. By default, the send( ) method uses a TTL of 1; that is, packets don’t travel outside the local subnet. However, you can change this for an individual packet by passing an integer from to 255 as the second argument to the send( ) method. For example:

DatagramPacket dp = new DatagramPacket(data, data.length, ia, port);  
  MulticastSocket ms = new MulticastSocket(  );
  ms.send(dp, 64);

public void setInterface(InetAddress address) throws SocketException

On a multihomed host, the setInterface( ) method chooses the network interface used for multicast sending and receiving. setInterface( ) throws a SocketException if the InetAddress you give it is not the address of a network interface on the local machine. It is unclear why the network interface is immutably set in the constructor for unicast Socket and DatagramSocket objects but is variable and set with a separate method for MulticastSocket objects. To be safe, you should set the interface immediately after constructing a MulticastSocket and not change it thereafter. Here’s how you might use setInterface( ):

MulticastSocket ms;
InetAddress ia;
try {
  ia = new InetAddress("metalab.unc.edu");
  ms = new MulticastSocket(2048);
  ms.setInterface(ia);
  // send and receive data...
}
catch (UnknownHostException ue) {
  System.err.println(ue);
}
catch (SocketException se) {
  System.err.println(se);
}

public InetAddress getInterface( ) throws SocketException

If you need to know the address of the interface you’re using, you can call getInterface( ) . It isn’t clear why this method would throw an exception; in any case, you must be prepared for it. For example:

try {
  MulticastSocket ms = new MulticastSocket(2048);
  InetAddress ia = ms.getInterface(  );
}
catch (SocketException se) {
  System.err.println(ue);
}

public void setTimeToLive(int ttl) throws IOException // Java 1.2

The setTimeToLive( ) method sets the default TTL value used for packets sent from the socket using the send(Datagrampacket dp) method inherited from DatagramSocket (as opposed to the send(Datagrampacket dp, byte ttl) method in MulticastSocket). This method is available only in Java 1.2 and later. In Java 1.1, you have to use the setTTL( ) method instead:

public void setTTL(byte ttl) throws IOException

The setTTL( ) method is deprecated in Java 2 and later because it allows you only to set TTL values from 1 to 127 rather than the full range from 1 to 255.

public int getTimeToLive( ) throws IOException // Java 1.2

The getTimeToLive( ) method returns the default TTL value of the MulticastSocket. It’s not needed very much. This method is also available only in Java 1.2 and later. In Java 1.1, you have to use the getTTL( ) method instead:

public byte getTTL(  ) throws IOException

The getTTL( ) method is deprecated in Java 1.2 and later because it doesn’t properly handle TTLs greater than 127. It truncates these to 127. The getTimeToLive( ) method can handle the full range from 1 to 255 without truncation because it returns an int instead of a byte.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.12.240