User Datagram Protocol (UDP)

   

User Datagram Protocol (UDP)

For many Internet developers, UDP (User Datagram Protocol) is used much less often than TCP. UDP does not isolate you as neatly from the details of implementing a continuous network communication. For many Java applications, however, choosing UDP as the tool to create a network linkage might be the most prudent option.

Programming with UDP has significant ramifications . Understanding these factors will guide and educate your network programming efforts.

UDP is a good choice for applications in which communications can be separated into discrete messages, where a single query from a client might invoke a single response from a server. Time-dependent data is particularly suited to UDP. UDP requires much less overhead, but the burden of engineering any necessary reliability into the system is your responsibility. For instance, if clients never receive responses to their queries, it's perfectly possible and legitimate with UDP; you might want to program the clients to retransmit the request or perhaps display an informative message indicating communication difficulties.

UDP Socket Characteristics

UDP behaves very differently than TCP. UDP is described as unreliable, connectionless, and message-oriented. A common analogy that explains UDP is that of communicating with postcards.

A dialogue with UDP must be translated into small messages that fit within a small packet of a specific size , although some packets can hold more data than others. When you send out a message, you can never be certain that you will receive a return message. Unless you do receive a return message, you have no idea if your message was received. Your message could have been lost en route, the recipient's confirmation could have been lost, or the recipient might be ignoring your message.

The postcards you will be exchanging between network programs are referred to as datagrams. Within a datagram, you can store an array of bytes. A receiving application can extract this array and decode your message, possibly sending a return datagram response.

As with TCP, you program in UDP using the socket programming abstraction. However, UDP sockets are very different from TCP sockets. Extending the postcard analogy, UDP sockets are much like creating a mailbox.

A mailbox is identified by your address, but you don't construct a new one for each person to whom you will be sending a message. (However, you might create a new mailbox to receive newspapers, which shouldn't go into your normal mailbox.) Instead, you place an address on the postcard that indicates to whom the message is being sent. You place the postcard in the mailbox, and it is (eventually) sent on its way.

When receiving a message, you could potentially wait forever until one arrives in your mailbox. After one arrives, you can read the postcard. Meta-information appears on the postcard that identifies the sender through the return address.

With UDP, you can also address a datagram to a subnet instead of a specific machine on the network. This will cause the datagram to be sent to everyone on the subnet. This might be an easy to send a broadcast message that a server is going down.

As the previous analogies suggest, UDP programming involves the following general tasks :

  • Creating an appropriately addressed datagram to send

  • Setting up a socket to send and receive datagrams for a particular application

  • Inserting datagrams into a socket for transmission

  • Waiting to receive datagrams from a socket

  • Decoding a datagram to extract the message, its recipient, and other meta-information

Java UDP Classes

The java.net package has the tools that are necessary to perform UDP communications. For sending and/or receiving datagrams, Java provides the DatagramPacket class.

To create a datagram to send to a remote system, there are two constructors that can be used:

 DatagramPacket(byte[] buf, int length, InetAddress addr, int port); DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port); 

The buf argument is an array of bytes that encodes the data of the message, while length is the length of the byte array to place into the datagram. This factor determines the size of the datagram. The address argument is an InetAddress object, which stores the IP address of the intended recipient. The port argument identifies which port the datagram should be sent to on the receiving host.

To receive a datagram, you must use another one of two of the other DatagramPacket constructors in which the incoming data will be stored. The two constructors are

 DatagramPacket(byte[] buf, int offset, int length); DatagramPacket(byte[] buf, int length); 

The buf argument is the byte array into which the data portion of the datagram will be copied . The length argument is the number of bytes to copy from the datagram into the array corresponding to the size of the datagram. If length is less than the size of the UDP datagram received by the machine, the extra bytes will be silently ignored by Java.

Programming with TCP sockets relieves you from breaking your data down into discrete chunks for transmission over a network. When creating a UDP-based client/server protocol, you must specify some expected length of the datagrams or create a means for determining this at runtime.

According to the TCP/IP specification, the largest datagram possible contains 65,507 bytes of data. However, a host is only required to receive datagrams with up to 548 bytes of data. Most platforms support larger datagrams of at least 8,192 bytes in length.

Large datagrams are likely to be fragmented at the IP layer. If, during transmission, any one of the IP packets that contains a fragment of the datagram is lost, the entire UDP datagram will be silently lost.

Note

You must design your application with the datagram size in mind. It is prudent to limit this size to a reasonable length. The actual length will vary according to the platform, network bandwidth available, and your particular application.


After a datagram has been received, you can read that data. Other methods allow you to obtain meta-information regarding the message:

 public int getLength(); public byte[] getData(); public InetAddress getAddress(); public int getPort(); 

The getLength method is used to obtain the number of bytes contained within the data portion of the datagram. The getData method is used to obtain a byte array containing the data received. getAddress provides an InetAddress object identifying the sender, whereas getPort indicates the UDP port used.

Performing the sending and receiving of these datagrams is accomplished with the DatagramSocket class, which creates a UDP socket. Three constructors are available:

 public DatagramSocket() throws IOException; public DatagramSocket(int port) throws IOException; public DatagramSocket(int port, InetAddress localAddr) throws IOException; 

The first constructor allows you to create a socket at an unused ephemeral port, generally used for client applications. The second constructor allows you to specify a particular port, which is useful for server applications. As with TCP, most systems require super-user privileges to bind UDP ports below 1024. The final constructor is useful for machines with multiple IP interfaces. You can use this constructor to send and listen for datagrams from one of the IP addresses assigned to the machine. On such a host, datagrams sent to any of the machine's IP addresses are received by a DatagramSocket created with the first two constructors, whereas the last constructor obtains only datagrams sent to the specific IP address.

Just as regular sockets rely on the SocketImpl class for the implementation of the socket behavior, the DatagramSocket class relies on the DatagramSocketImplFactory class for its implementation.

You can use this socket to send properly addressed DatagramPacket instances created with the first constructor described by using this DatagramSocket method:

 public void send(DatagramPacket p) throws IOException; 

After a DatagramPacket has been created with the second constructor described, a datagram can be received:

 public synchronized void receive(DatagramPacket p) throws IOException; 

Note that the receive method blocks until a datagram is received. Because UDP is unreliable, your application cannot expect receive ever to return unless a timeout is enabled. Such a timeout, named the SO_TIMEOUT option from the name of the Berkeley sockets API option, can be set with this method from the DatagramSocket class:

 public synchronized void setSoTimeout(int timeout) throws SocketException; 

The timeout argument is a value in milliseconds . If set to 0, the receive method exhibits an infinite timeout ”the default behavior. When greater than 0, a subsequent receive method invocation waits only the specified timeout before an InterruptedIOException is thrown.

Your host's UDP implementation has a limited queue for incoming datagrams. If your application cannot process these datagrams rapidly enough, they are silently discarded. Neither the sender nor the receiver is notified when datagrams are dropped from a queue overflow. Such is the unreliable nature of UDP.

After communications through the UDP socket are completed, that socket should be closed:

 public synchronized void close(); 

A Datagram Example

In this section, you learn how to create a basic UDP client and server that broadcasts and received messages to one another. The idea here a simple tool that where network users can send messages out to everyone on the network or to specific users. However, for this example you are just going to start up a client program and then send messages to the client program from a server program. The reason for this is you don't want to send messages out to the entire Internet. Remember that it was said earlier that if you send a message to a subnet, then everyone might possibly receive that message. You don't want that to happen. Of course if they don't have the client program, it wouldn't happen anyone . You do have to be careful of this sort of accident when dealing with network applications.

The BroadcasterClient application in Listing 23.13 starts up and listens for UDP messages on a certain port. When it receives a message, it prints out who sent it and what the message is.

Listing 23.13 shows the Java code used to implement the BroadcasterClient.

Listing 23.13 Source Code for BroadcasterClient.java
 import java.io.*; import java.net.*; import java.util.*; import java.text.*; public class BroadcasterClient extends Thread {   // Set a default listener port   private int listenerPort = 59;   private DatagramSocket listenerSocket = null;   private static int MAX_PACKET_SIZE = 1000;   // Default Constructor   public BroadcasterClient()   {     super();   }   // Alternate Constructor to Override Port   public BroadcasterClient(int newPort)   {     // overide port setting     listenerPort = newPort;   }   public void run()   {     byte[] buffer = new byte[ MAX_PACKET_SIZE ];     // Create a packet to hold the data when it arrives    DatagramPacket infoPacket =         new DatagramPacket(buffer, MAX_PACKET_SIZE);     try     {       listenerSocket = new DatagramSocket(this.listenerPort);     }     catch(Exception ex)     {       System.out.println("Problem creating socket on port: " + listenerPort);       System.exit(-1);     }     // do an infinite loop     while(true)     {       try       {         System.out.println("Waiting on broadcasts");         // Setting this value to 0 causes it to be an infinite timeout         listenerSocket.setSoTimeout(0);         listenerSocket.receive(infoPacket);         // What address sent the packet         InetAddress fromAddress = infoPacket.getAddress();         // Get the message within the packet         byte[] msg = infoPacket.getData();         System.out.println("Received broadbast from " + fromAddress);         System.out.println(new String(msg));       }       catch(IOException ex)       {         // Print the exception and try to keep going         ex.printStackTrace();       }     }   }   public static void main(String[] args)   {     BroadcasterClient client = null;     int argLength = args.length;     // Make sure the correct number of args were passed     if (argLength > 1)     {       System.out.println("Usage: java BroadcasterClient <port>");       System.exit(0);     }     if (argLength == 0)       client = new BroadcasterClient();     if (argLength == 1)     {       int port = 0;       String arg = args[0];       try       {         port = Integer.parseInt(arg);       }       catch(Exception ex)       {         System.out.println("Invalid port specified on the command line:arg");         System.exit(-1);       }       client = new BroadcasterClient(port);     }     // Listen for messages     client.start(); } 

One thing to notice in Listing 23.13 is the use of the setSoTimeout method. This causes the BroadcasterClient to wait infinitely and not timeout while waiting for a broadcast message.

Starting the BroadcasterClient Application

The BroadcasterClient class uses a default port in which to listen for UDP messages on. You can use this default or pass in another port if the default port is in use by another application. For running our example, the default port should be fine.

The BroadcasterClient will sit and listen for broadcasts indefinitely. You'll notice an infinite loop in the run method in Listing 23.13. To stop the BroadcasterClient application, you'll need to press Ctrl+C. When a broadcast message is received, it is printed out and then the application goes back to listening for more.

Now you will need the application that initiates the broadcasts. Listing 23.14 shows the BroadcasterServer class. This class sends a message in the form of a DatagramPacket. Once the message is broadcasted out, the BroadcasterServer ends. Again, for this example, the messages will only be broadcasted to the localhost.

Listing 23.14 shows the BroadcasterServer application.

Listing 23.14 Source Code for BroadcasterServer.java
 import java.io.*; import java.net.*; import java.util.*; import java.text.*; public class BroadcasterServer {   // Set a default listener port   private int senderPort = 59;   // set a 10 second UDP timeout   private static final int TIMEOUT = 10000;   private DatagramSocket senderSocket = null;   private static int MAX_PACKET_SIZE = 255;   // Default Constructor   public BroadcasterServer()   {     super();   }   // Alternate Constructor to Override Port   public BroadcasterServer(int newPort)   {     // overide port setting     senderPort = newPort;   }   public void sendBroadcast(String msg)   {     // Determine the actual size of the message     int msgSize = msg.length();     // Create a byte to hold the message     byte[] buffer = new byte[ msgSize ];     buffer = msg.getBytes();     try     {       // For this example, just send it to the local host       InetAddress addr = InetAddress.getLocalHost();       // Create the packet of information       DatagramPacket infoPacket =         new DatagramPacket(buffer, msgSize, addr, this.senderPort);       senderSocket = new DatagramSocket();       // Send the packet and clean up the resources       senderSocket.send(infoPacket);       senderSocket.close();     }     catch(Exception ex)     {       System.out.println("Problem creating socket on port: " + senderPort);       System.exit(-1);     }   }   public static void main(String[] args)   {     BroadcasterServer server = null;     int argLength = args.length;     // Make sure the correct number of args were passed in     if (argLength != 2)     {       System.out.println("Usage: java BroadcasterClient <port> <message>");       System.exit(0);     }     int port = 0;     String arg = args[0];     String msg = args[1];     try     {       // Try to parse the port string into an int       port = Integer.parseInt(arg);     }     catch(Exception ex)     {       System.out.println("Invalid port specified on the command line:arg");       System.exit(-1);     }     server = new BroadcasterServer(port);     // Broadcast the data out     server.sendBroadcast(msg);   } } 
Starting BroadcasterServer

To broadcast a message to the clients, just start the application and pass in the port number and the message on the command line. Remember, the message will probably have to have double quotes around it when you pass it in on the command line. Here's an example of starting the BroadcasterServer:

 java BroadcasterServer 59 "What time are we going to lunch?" 

Multicasting

Internet Protocol (IP) is the means by which all information on the Internet is transmitted. UDP datagrams are encapsulated within IP packets to send them to the appropriate machines on the network.

Most uses of IP involve unicasting . Unicasting is sending a packet from one host to another. However, IP is not limited to this mode and includes the capability to multicast. With multicasting, a message is addressed to a targeted set of hosts . One message is sent, and the entire group can receive it.

Multicasting is particularly suited to high-bandwidth applications, such as sending video and audio over the network, because a separate transmission need not be established (which could saturate the network). Other possible applications include chat sessions, distributed data storage, and online, interactive games . A client searching for an appropriate server on the network can use multicasting. It can send a multicast solicitation, and any listening servers could contact the client to begin a transaction.

To IP multicasting, a certain range of IP addresses is set aside solely for this purpose. These IP addresses are class D addresses, those within the range of 224.0.0.0 and 239.255.255.255. Each of these addresses is referred to as a multicast group. Any machine that has joined that group receives any IP packet addressed to that group. Group membership is dynamic and changes over time. To send a message to a group, a host need not be a member of that group.

When a machine joins a multicast group, it begins accepting messages sent to that IP multicast address. Extending the previous analogy from the "User Datagram Protocol (UDP)" section, joining a group is similar to constructing a new mailbox that accepts messages intended for the group. Each machine that wants to join the group constructs its own mailbox to receive the same message. If a multicast packet is distributed to a network, any machine that is listening for the message has an opportunity to receive it. That is, with IP multicasting, there is no mechanism for restricting which machines on the same network can join the group.

Multicast groups are mapped to hardware addresses on interface cards. Thus, IP multicast datagrams that reach an uninterested host can usually be rapidly discarded by the interface card. However, more than one multicast group maps to a single hardware address, making for imperfect hardware-level filtering. Some filtering must still be performed at the device driver or IP level.

Multicasting has its limitations, however ”particularly the task of routing multicast packets throughout the Internet. A special TCP/IP protocol, Internet Group Management Protocol (IGMP), is used to manage memberships in a multicast group. A router that supports multicasting can use IGMP to determine if local machines are subscribed to a particular group; such hosts respond with a report about groups they have joined using IGMP. Based on these communications, a multicast router can determine if it is appropriate to forward on a multicast packet.

Caution

Realize that there is no formal way of reserving a multicast group for your own use. Certain groups are reserved for particular uses, assigned by the Internet Assigned Numbers Authority (IANA).


Other than avoiding a reserved group, there are few rules to choosing a group. The groups from 224.0.0.0 through 224.0.0.225 should never be passed on by a multicast router, restricting communications using them to the local subnet. Try picking an arbitrary address between 224.0.1.27 and 224.0.1.225.

If you happen to choose a group already being used, those other machines will disrupt your communications. Should this occur, quit your application and try another address.

Besides the multicast group, another important facet of a multicast packet is the time-to-live (TTL) parameter. The TTL is used to indicate how many separate networks the sender intends the message to be transmitted over. When a router forwards a packet on, the TTL within the packet is decremented by one. When a TTL reaches zero, the packet is not forwarded further.

Choose a TTL parameter as small as possible. A large TTL value can cause unnecessary bandwidth use throughout the Internet. Furthermore, you are more likely to disrupt other multicast communications in diverse areas that happen to be using the same group.

If your communications should be isolated to machines on the local network, choose a TTL of 1. When communicating with machines that are not on the local network, try to determine how many multicast routers exist along the way and set your TTL to one more than that value.

The Multicast Backbone , or MBONE, is an attempt to create a network of Internet routers that are capable of providing multicast services. However, multicasting today is by no means ubiquitous. If all participants reside on the same physical network, routers need not be involved, and multicasting is likely to prove successful. For more distributed communications, you might need to contact your network administrator.

Java Multicasting

The Java MulticastSocket class is the key to using this powerful Internet networking feature. MulticastSocket allows you to send or receive UDP datagrams that use multicast IP. To send a datagram, you use the default constructor:

 public MulticastSocket() throws IOException; 

Then you must create an appropriately formed DatagramPacket addressed to a multicast group between 224.0.0.0 and 239.255.255.255. After it is created, the datagram can be sent with the send method, which requires a TTL value. The TTL indicates how many routers the packets should be allowed to go through. Avoid setting the TLL to a high value, which could cause the data to propagate through a large portion of the Internet. Here is an example:

 int multiPort = 2222; int ttl = 1; InetAddress multiAddr = InetAddress.getByName("239.10.10.10"); byte[] multiBytes = new byte[256]; DatagramPacket multiDatagram = new DatagramPacket(multiBytes, multiBytes.length, graphics/ccc.gif multiAddr,multiPort); MulticastSocket multiSocket = new MulticastSocket(); multiSocket.send(multiDatagram, ttl); 

To receive datagrams, an application must create a socket at a specific UDP port. Then, it must join the group of recipients. Through the socket, the application can then receive UDP datagrams:

 MulticastSocket recei7veSocket = new MulticastSocket(multiPort); receiveSocket.joinGroup(multiAddr); receiveSocket.receive(multiDatagram); 

When the joinGroup method is invoked, the machine now pays attention to any IP packets transmitted along the network for that particular multicast group. The host should also use IGMP to appropriately report the usage of the group. For machines with multiple IP addresses, the interface through which datagrams should be sent can be configured:

 receiveSocket.setInterface(oneOfMyLocalAddrs); 

To leave a multicast group, the leaveGroup method is available. A MulticastSocket should be closed when communications are done:

 receiveSocket.leaveGroup(multiAddr); receiveSocket.close(); 

As is apparent, using the MulticastSocket is similar to using the normal UDP socket class DatagramSocket. The essential differences are

  • The DatagramPacket must be addressed to a multicast group.

  • The send method of the MulticastSocket class takes two arguments: a DatagramPacket and a TTL value.

  • To begin listening for multicast messages after creating the MulticastSocket instance, you must use the joinGroup method.

  • The receive method is used just as with the DatagramSocket to obtain incoming messages; however, there is no method to set a timeout, such as setSoTimeout in DatagramSocket.

   


Special Edition Using Java 2 Standard Edition
Special Edition Using Java 2, Standard Edition (Special Edition Using...)
ISBN: 0789724685
EAN: 2147483647
Year: 1999
Pages: 353

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net