Java Tip 18: Implementing a timeout feature for the JDK 1.0.2 DatagramSocket

How to time and unblock the receiving of a datagram packet

If you have developed a Java application that uses the Datagram socket to send and receive messages, then you may have encountered the need to implement a timeout feature to unblock the DatagramSocket receive method. Without a timeout feature, your application would block until it receives a message, and since Datagram delivery is not guaranteed, your application could block for a really long time. This Java Tip will describe a technique for timing out and unblocking the DatagramSocket receive method.

You've probably already guessed that this technique will make use of threads. Thread programming in Java is quite enjoyable. One could compare it to the joys of skiing at Lake Tahoe or of sailing near the coast of Santa Cruz. (OK, maybe it's not that enjoyable, but it's still a lot of fun!)

When contemplating a method to accomplish the timeout feature, perhaps the first and most obvious scheme that comes to mind is to place the DatagramSocket receive functionality into a separate thread and then launch yet another thread as a timer that, upon expiration, would kill the receive thread if it is still alive. While this method will work, it is probably not the most graceful way to accomplish the task.

Instead of killing a thread that is blocked on the receive method, I wanted a more graceful solution -- one that would unblock the receive method. To accomplish this, I needed a thread that was capable of sending a datagram message to the receiving thread to unblock the receiving thread after a timeout period had expired. The timeout thread is implemented as its own class, and the receiving thread creates an instance of the timeout class just before blocking on the receive method. The following code shows the timeout class implementation. Note that, for brevity, exception handling is omitted.

import java.io.*;
import java.net.*;
import java.lang.*;
public class
DatagramWatchdogTimer implements Runnable
{
   DatagramWatchdogTimer( int timeoutSeconds ) throws SocketException
   {
      timeout = timeoutSeconds;
      socket = new DatagramSocket();
      datagramPort = socket.getLocalPort();
      Thread thisThread = new Thread( this );
      thisThread.start();
   }
   public int
   getPort()
   {
      return datagramPort;
   }
   public void
   run()
   {
      // create a standard reply message that indicates
      // the message came from the DatagramWatchdogTimer
      // in my case, a zero suffices.
      String replyStr = new Integer( 0 ).toString();
      byte[] replyBuf = new byte[ replyStr.length() ];
      replyStr.getBytes( 0, replyStr.length(), replyBuff, 0 );
      int replyLength = replyStr.length();
      // receive a message from the receiving thread.
      // this is necessary so we know how to send the unblocking
      // message back to it.
      byte[] buffer = new bute[128];
      DatagramPacket packet
            = new DatagramPacket( buffer, buffer.length );
      socket.receive( packet );
      // wait timeout number of seconds and then send an unblocking
      // message back.
      Thread.sleep( timeout*1000);
      int requestorPort = packet.getPort();
      InetAddress requestorAddress = packet.getAddress();
      DatagramPacket sendPacket
            = new DatagramPacket( replyBuff, replyLength,
                                  requestorAddress, requestorPort );
      DatagramSocket sendSocket
            = new DatagramSocket();
      sendSocket.send( sendPacket );
   }
   private int timeout;
   private int datagramPort;
   private DatagramSocket socket;
}

As mentioned above, whenever your application needs to receive a datagram message, it can create an instance of the DatagramWatchdogTimer class to set a timeout period. If the application does not receive a real message within timeout seconds, it will unblock by receiving an unblock message from the DatagramWatchdogTimer class.

Here is an example:

// application code
int timeoutSeconds = 5;
InetAddress myAddress = InetAddress.getByName("");
// create  an instance of the timer class
DatagramWatchdogTimer wdTimer = new DatagramWatchdogTimer( timeoutSeconds );
int wdPort = wdTimer.getPort();
// send a message to wdTimer to get the timer started
// msgBuff can be whatever you want.
String msgString = new String("time me");
byte[] msgBuff = new byte[ msgString.length() ];
msgString.getBytes( 0, msgString.length(), msgBuff, 0 );
DatagramSocket socket
      = new DatagramSocket();
DatagramPacket wdPacket
      = new DatagramPacket( msgBuff, msgLength, myAddress, wdPort );
socket.send( wdPacket );
// now you can read from the socket and have some assurance
// that you will only block for timeoutSeconds.
byte[] buffer = new byte[1024];
DatagramPacket packet =
      new DatagramPacket( buffer, buffer.length );
socket.receive( packet );
if(  myAddress.equals( packet.getAddress ) == true  )
{
      // received message from timer object
}
else
{
      // received a real message
}

When using this technique, be sure to use the same DatagramSocket for both sending to the DatagramWatchdogTimer object and for receiving datagrams. This ensures that the DatagramWatchdogTimer object knows where to send the unblock message. Also, in the sample code shown above a dynamically allocated port was used by instantiating the DatagramSocket() without any arguments. It would also work using a well-known port of your choice such as DatagramSocket( 8000 ). Finally, you may want the timer object to send more than one unblock message -- just to increase the chances of it getting received by the application. This should not be a problem since the timer object is running as a thread on the same machine as the application.

Albert Lopez was a member of the technical staff at Sun Microsystems from 1989 until 1995. He has recently joined the Information Systems staff at the Chicago Board of Trade, where he is a lead member of the Java development team that is developing the next-generation electronic trading system using Java.