HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

When developing Java network applications in a stable and controlled environment, it's easy to become complacent and ignore the possibility of network timeouts. After all, with the perfect client and server running over a local area network, timeouts won't occur to stall your application. But when your users run clients or servers over the Internet (an environment where networks can go down, badly written software can stall or communication sessions can deviate from the ideal path of a communications protocol), timeouts can cause problems if there isn't a mechanism to recognize and deal with it.

In this article, I'll present two approaches to dealing with network timeouts. The first approach, writing a multi-threaded application, is backwards compatible with JDK1.02, at the expense of increased complexity. The second approach is by far the easiest. In most cases it involves adding only a few lines of code to your application but requires a JDK1.1 virtual machine. As an example, I'll show how the two approaches can be applied to a simple finger client.

Multi-threaded Applications
Designing a multi-threaded client or server offers a solution to the problem of timeouts. When one thread becomes blocked, waiting for network input or to send more data, a second timer thread can still perform other operations when a timeout occurs, such as terminating the connection. If you've never written a multi-threaded application before, consult the sidebar "Overview of Threads."

Listing 1 introduces the Timer class which is a subclass of java.lang.Thread. When an application creates an instance of Timer, it specifies the number of milliseconds that can elapse before a network timeout occurs. Once the timer is started, it will begin to decrement an internal counter. When the counter has no more milliseconds remaining, the timeout action occurs which, by default, is to exit the application. If necessary, subclasses of Timer can override the timeout method to provide custom functionality.

For the sample finger client, we will use the Timer class to terminate the application if a network timeout occurs (for example, a server that stalls). Listing 2 shows a multi-threaded finger client and Listing 3 shows a sample finger server. The client and server will communicate via port 79 (defined in the public int FINGER_PORT). However, on some systems the server may be unable to bind to this port, in which case an ephemeral port in the range 1024 to 5000 should be used instead for both client and server.

The finger server reads data from files matching the format 'user-name.info' where name is a valid username. For testing purposes, you can create a single user file and have the finger client request information. To simulate timeouts, the server maintains a counter and stalls after the first line of input on every second connection.

The finger client starts by checking its command line arguments and creating a new instance of itself. The client then opens a socket connection and gets input and output streams. It sends the name of a user to the finger server and then begins reading in data.

At some point in the connection, our finger server will stop sending data and our client will be stalled while it waits for input. Without some means of reconciliation, our client would remain blocked - this is where our Timer class solves the problem.

It is the responsibility of the application to repeatedly reset the timer to prevent a "false" timeout from occurring. While it is looping, the timer is reset; if the loop stops for some reason, the timer can continue uninterrupted and generate a timeout. When this occurs, the program can terminate rather than being locked.

If we wanted our timer to have different properties (for example, re-establishing a connection), we could simply extend the timer to create a custom timer class and to override the timeout method. Were we to write a server that supported timeouts, we would need a different timer thread for every single connection (which could cause considerable overheads if a large number of concurrent connections were generated). A much more efficient method is to use the new socket features introduced in JDK1.1, as we'll see in the next section.

Timeouts Made Easy
While the multi-threaded approach works well and is backwards compatible with JDK1.02, it does introduce a great deal of complexity, even for simple applications such as a finger client. If it is important to run your application on older virtual machines, use multi-threading. However, if you have the luxury of a JDK1.1 platform, you can add timeout code to your application with ease.

As part of the new features of JDK1.1, support for socket options have been introduced. One of these allows developers to specify the number of milliseconds that must elapse before a timeout occurs, throwing a java.io.InterruptedIOException. For Socket connections, this means that operations reading from the socket input stream can timeout if no data is received within a given period of time. With only a few lines of code, we can introduce support for timeouts, without moving to a multi-threaded design in our clients and without launching a Timer thread for our servers.

Simple Finger Client
Listing 4 shows a simple finger client which can be run against the server from Listing 3. You'll notice how simple it is to set a timeout value. The setSoTimeout method accepts an integer value as a parameter, representing the number of milliseconds for a timeout.

// Set SO_TIMEOUT for five seconds
socket.setSoTimeout ( 5000 );

All you need to do now is catch the java.io.InterruptedIOException that is thrown when a timeout occurs while reading from a Socket's input stream and your application will handle timeouts.

Timeouts in Servers
Timeouts can occur in servers as well. If you're writing a multi-threaded server, it's important to set and detect timeouts in the socket connections to clients. Otherwise, badly behaved clients can use up memory by stalling and leaving threads open, or use up all your available connections if your server has a limit to the number of connections it supports. A good design would be to call the setSoTimeout method on every socket you accept and to catch InterruptedIOExceptions if thrown.

The most important case for using the setSoTimeout method is when your server uses DatagramSockets. DatagramSockets allow Java applications and applets to communicate via UDP, which doesn't offer guaranteed packet delivery or ordering. It's critical that applications using UDP recognize and provide for situations in which timeouts occur. Previously, this meant creating a separate thread to monitor packet arrivals (and often re-sending packets when no response was issued). Now, however, your application can easily cater to this situation with a few lines of code using the setSoTimeout method.

To illustrate this, I've written an example program that implements a stop-and-wait delivery mechanism. One application (the sender) sends small packets of data containing a sequence number and then waits for an acknowledgement packet to be sent by the receiver. If no acknowledgement arrives, then one of two situations could have occurred:

  1. The original packet never arrived at the receiver's end.
  2. The original packet arrived and was acknowledged, but the acknowledgement never arrived at the sender.
Listing 5 shows the code for the sender and Listing 6 shows the code for the receiver. The sender uses a DatagramSocket to send packets, and receive acknowledgements. Likewise, the receiver uses a DatagramSocket to receive packets and send acknowledgements. Both sender and receiver should check for timeouts and respond accordingly.

Timeouts can occur for a variety of reasons; there may be times when the sender is forced to send more than one instance of a data packet, or when the receiver sends more than one acknowledgement. It is important in this situation for both sender and receiver to check the sequence number and handle inappropriate packets gracefully. It is even more important when your application sends many packets and expects the receiver to maintain sequence integrity.

Figure 1
Figure 1:  Lost packet causes timeout

Conclusion
The decision to use a timer thread, or to use socket options instead, is largely up to the individual circumstances of the application. Some applications will require backwards compatibility with JDK1.02, in which case timers may be the only option. Wherever possible though, due consideration should be given to setting socket options for timeouts.

Setting socket options for timeouts and catching InterruptedIOExceptions allows developers to place code close to the point at which input and output takes place. This reduces complexity and saves placing control of your connections in an external class. For clients that are not already multi-threaded, setting a socket option timeout is by far the better choice and with only a few lines your application can support network timeouts.

About the Author
David Reilly has worked on network protocols and Web-related programming at Bond University, Australia. Since his conversion to Java in 1996, he has worked almost exclusively with the language, finding it both a joy to use and the most productive way to produce portable applications. David can be contacted at [email protected]

	

Listing 1.
  
// Timer - thread which counts down to a network timeout,  
//         which prompts a call to timeout() method  
//   
// Written by : David Reilly  
// Last modification date : March 8, 1998  
//  
//  
public class Timer extends Thread  
{  
 // Public consts  
 public static final int REFRESH_RATE = 100;  

 // Private member variables  
 private int m_timeoutValue; // Length of timeout  
 private int m_remainingTime; // Remaining time  
 private boolean m_timeReset;  // time reset  

 // Constructor  
 public Timer ( int milliseconds )  
 {  
  // Assign to member variable  
  m_timeoutValue = milliseconds;  
  m_remainingTime = milliseconds;  
  m_timeReset = false;  
 }  

 public synchronized void resetTimer()  
 {  
  m_remainingTime = m_timeoutValue;  
 }  

 // Thread run method  
 public void run()  
 {  
  // Repeat forever, until program terminates  
  for (;;)  
  {  
   try  
   {  
    // Sleep for the default time refresh rate  
    Thread.sleep(REFRESH_RATE);  

    // Check to see if timer was reset while sleeping  
    if (m_timeReset == true)  
    {  
     // Timer has been reset, so clear our flag  
     m_timeReset = false;  
    }  
    else  
    {  
     // Decrease remaining time  
     m_remainingTime -= REFRESH_RATE;  

     // Has a timeout occured  
     if (m_remainingTime < 0)  
     {  
      // Trigger a timeout  
      timeout();  
     }  
    }  
   }  
   catch (InterruptedException interrupted)  
   {  
    // Disregard - if we are interupted, then  
    // we will simply sleep on the next loop  
   }  
  }  
 }  

 // Override this to provide custom functionality  
 public void timeout()  
 {  
  System.err.println ("Network timeout occured.... terminating");  
  System.exit(1);  
 }  
}  
   

Listing 2.

import java.net.*;  
import java.io.*;  

// MultiThreadedFingerClient  
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname username  
//  
//  
public class MultiThreadedFingerClient extends Thread  
{  
 // Public constants  
 public static final int FINGER_PORT = 79; 
 // may need to set this to an ephemeral port  

 // Private member variables  
 private String m_hostname;  
 private String m_username;  
 private Timer m_timer;  

 // Constructor :  
 public MultiThreadedFingerClient(String hostname, String username)  
 {  
  // Assign to member variables  
  m_hostname = hostname;  
  m_username = username;  

  // Five seconds timeout  
  m_timer = new Timer ( 5000 );  
 }  

 // MAIN :  
 public static void main(String args[])  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("MultiThreadedFingerClient hostname user");  
   System.exit(1);  
  }  

  // Create a new   
  new MultiThreadedFingerClient(args[0], args[1]).start();  
 }  

 // connect to server : thread run method  
 public void run()  
 {  
  // Local variables  
  Socket socket = null;  
  int data;  

  // Prompt user  
  System.out.println ("Connecting to " + m_hostname);  

  // Start the timer  
  m_timer.start();  

  try  
  {  
   // Create a socket to the server  
   socket = new Socket ( m_hostname , FINGER_PORT );  

   // Only proceed if connection was established  
   if (socket == null)  
    return;  

   // Get input and output streams to socket  
   BufferedInputStream bufin = new BufferedInputStream
   ( socket.getInputStream() );  
   PrintStream pout = new PrintStream( socket.getOutputStream() ); 
   // deprecated in JDK1.1  
    
   // Print user name  
   pout.println (m_username);  

   // Read in information from server  
   for (;;)  
   {  
    // Read a byte of data  
    data = bufin.read();  

    // Check for end of input stream  
    if (data != -1)  
    {  
     // Cast data to a character and display it  
     System.out.print ( (char) data );  
    }  
    else  
     break; // no more data to be read  

    // Reset our timer  
    m_timer.resetTimer();  
   }  
  }  
  catch (IOException e)  
  {  
   System.err.println ("I/O - " + e);  
  }  

 }  
}  

Listing 3.  

import java.net.*;  
import java.io.*;  

// FingerTimeoutServer  
//   
// Written by : David Reilly  
// Last modification date : March 8, 1998  
//  
//  
public class FingerTimeoutServer extends Thread  
{  
 public static final int FINGER_PORT = 79; 
 // may need to set this to an ephemeral port  

 // Private member vars  
 private Socket m_socket;  

 // Instance count  
 private static int instanceCount = 0;  

 public FingerTimeoutServer ( Socket sock )  
 {  
  // Assign to member variable  
  m_socket = sock;  

  // Increment instanceCount  
  instanceCount++;  
 }  

 public static void main( String args[] )  
 {  
  System.out.println ("Finger Server with simulated timeout");  
    
  try  
  {  
   // Create a server socket, bound to FINGER_PORT  
   ServerSocket serverSocket = new ServerSocket ( FINGER_PORT );  

   // Loop forever, accepting new connecitons  
   for (;;)  
   {  
    Socket sock = serverSocket.accept();  

    // Create an instance of server to process socket  
    FingerTimeoutServer connection = new FingerTimeoutServer ( sock );  
      
    // Start connection thread  
    connection.start();  
   }  
  }  
  catch (IOException ie)  
  {  
   System.err.println ("I/O Error - " + ie);  
   System.exit(0);  
  }  
 }  

 // Main 'work' method  
 public void run()  
 {  
  try  
  {  
   DataInputStream din = new DataInputStream ( m_socket.getInputStream() );  
   PrintStream pout = new PrintStream ( m_socket.getOutputStream() ); 
   // deprecated in JDK1.1  

   // Read a single line of text  
   String username = din.readLine();  

   // Check for presence of user-name.info  
   File userFile = new File ("user-" + username + ".info");  

   // Check if user exists  
   if (userFile.exists())  
   {  
    FileInputStream fin = new FileInputStream( userFile );  

    DataInputStream dfin = new DataInputStream( fin );  

    // Read first line, and send to client  
    String line = dfin.readLine();  
    pout.println (line);  
      
    // Check instance count (if not even, then send data and terminate)  
    if (instanceCount % 2 != 0)  
    {  
     for (;;)  
     {        
      line = dfin.readLine();  

      if (line != null)  
       pout.println (line);  
      else   
       break;  
     }  

     // Close socket  
     m_socket.close();  
    }  
    else  
    {  
     // Simulate timeout by not closing socket  
     pout.println ("Simulating timeout.... 
	 if your client doesn't handle timeouts it will stall");  
    }  
   }  
   else  
   {  
    pout.println ("Invalid username");  

    // Close socket  
    m_socket.close();  
   }  
  }  
  catch (IOException ie)  
  {  
   System.out.println ("I/O Error - " + ie);  
  }  
 }  
}  

Listing 4.  

import java.net.*;  
import java.io.*;  

// FingerClient - demonstrates new JDK1.1 networking features  
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname username  
//  
//  
public class FingerClient   
{  
 // Public constants  
 public static final int FINGER_PORT = 79; 
 // may need to change to an ephemeral port  

 // Private member variables  
 private String m_hostname;  
 private String m_username;  

 // Constructor :  
 public FingerClient(String hostname, String username)  
 {  
  // Assign to member variables  
  m_hostname = hostname;  
  m_username = username;  

  // Make a connection  
  connect();    
 }  

 // MAIN :  
 public static void main(String args[])  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("FingerClient hostname user");  
   System.exit(1);  
  }  

  new FingerClient(args[0], args[1]);  
 }  

 // connect to server :  
 private void connect()  
 {  
  // Local vars  
  Socket socket = null;  
  int data;  

  // Prompt user  
  System.out.println ("Connecting to " + m_hostname);  

  try  
  {  
   // Create a socket to the server  
   socket = new Socket ( m_hostname , FINGER_PORT );  

   // Only proceed if connection was established  
   if (socket == null)  
    return;  

   // Set SO_TIMEOUT for five seconds  
   socket.setSoTimeout ( 5000 );  

   // Get input and output streams to socket  
   BufferedInputStream bufin = new BufferedInputStream
   ( socket.getInputStream() );  
   PrintStream pout = new PrintStream( socket.getOutputStream() ); 
   // deprecated in JDK1.1  
    
   // Print user name  
   pout.println (m_username);  

   // Read in information from server  
   for (;;)  
   {  
    // Read a byte of data  
    data = bufin.read();  

    // Check for end of input stream  
    if (data != -1)  
    {  
     // Cast data to a character and display it  
     System.out.print ( (char) data );  
    }  
    else  
     break; // no more data to be read  
   }  
  }  
  catch (IOException e)  
  {  
   System.err.println ("I/O - " + e);  
  }  
 }  
}  

Listing 5.  

import java.net.*;  
import java.io.*;  
import java.util.Random;  

// Sender - demonstrates timeouts on a stop-and-wait protocol   
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
// Syntax : hostname port  
//  
//  
public class Sender   
{  
 // Priavet member variables  

 // Internet address for receiver  
 private InetAddress m_addr;  

 // Receiver port  
 private int m_port;  

 // Socket to receiver  
 private DatagramSocket m_datagramSocket = null;    

 // Psuedo-random number generator for random sleep interval  
 private Random random;  

 // Default packet size  
 public static final int packetSize = 20;  

 // Constructor for Sender  
 public Sender(String hostname, String port)  
 {  
  // Create a psuedo-random number generator  
  random = new Random();  

  // Obtain an InetAddress object for hostname  
  try  
  {  
   m_addr = InetAddress.getByName ( hostname );  
  }  
  catch (UnknownHostException unknownHost)  
  {  
   System.out.println ("Unknown hostname : " + hostname);  
  }  

  // Convert string into an int  
  try  
  {  
   // Create an integer object and get it's int value  
   m_port = new Integer(port).intValue();  
  }  
  catch (Exception e)  
  {  
   System.out.println ("Invalid port number : " + port);  
   System.exit(1);  
  }  
 }  

 // MAIN method  
 public static void main( String args[] )  
 {  
  if (args.length != 2)  
  {  
   System.out.println ("Sender hostname port");  
   System.exit(1);  
  }  

  // Create an instance of sender  
  Sender sender = new Sender(args[0], args[1]);  

  // Send packets to a receiver  
  sender.transmit();  
 }  

 // Transmit packets to a receiver  
 public void transmit()  
 {    
  // Sequence number  
  int sequenceNumber =0;  

  // Create a datagram socket  
  try  
  {  
   m_datagramSocket = new DatagramSocket();  

   // Set the timeout to two seconds  
   m_datagramSocket.setSoTimeout( 2000 );  
  }  
  catch (SocketException se)  
  {  
   System.err.println ("Error creating a datagram socket - " + se);  
   System.exit(1);  
  }  

    
  for (;;)  
  {  
   // Packets for receiving a response  
   DatagramPacket response = new DatagramPacket(new byte[packetSize], packetSize);  

   try  
   {  
    // Read a packet, and check if its an acknowledgement  
    m_datagramSocket.receive(response);  

    int responseNumber = getSequenceNumber(response);  

    // Does the response ACK match our sequence  
    if (responseNumber == sequenceNumber)  
    {  
     System.out.println ("ACK : " + sequenceNumber);  

     // Increment sequence number  
     sequenceNumber++;  

     System.out.println ("Sending packet " + sequenceNumber);  

     // Send next packet to receiver  
     sendPacket(sequenceNumber, m_addr, m_port);  

    }  
    else  
     System.out.println ("ACK : " + responseNumber 
	 + " (expecting" + sequenceNumber + ")");  

    // Sleep for a random length of time... so some timeouts are generated  
    randomSleep();  
   }  
   catch (InterruptedIOException iioe)  
   {  
    // Timeout occured... must resend packet  
    System.out.println ("TIMEOUT : " + sequenceNumber);  

    System.out.println ("Re-sending packet " + sequenceNumber);  

    // Send packet to receiver  
    sendPacket(sequenceNumber, m_addr, m_port);  

   }  
   catch (IOException ioe)  
   {  
    System.out.println ("I/O Error occured - " + ioe);  
   }  
  }  
 }  

 private int getSequenceNumber( DatagramPacket packet )  
 {  
  // Create a byte input stream to read the data  
  ByteArrayInputStream bin = new ByteArrayInputStream (packet.getData());  

  // Create a datainput stream to read sequence number  
  DataInputStream din = new DataInputStream (bin);  

  int sequenceNumber;  

  try  
  {  
   sequenceNumber = din.readInt();  
  }  
  catch (IOException ioe)  
  {  
   sequenceNumber = 0;  
  }  

  return sequenceNumber;  
 }  

 private void sendPacket(int sequenceNumber, InetAddress addr, int port)  
 {  
  try  
  {  
   // Byte array containing response  
   byte[] sendBuffer;  

   // Create output stream to a byte array  
   ByteArrayOutputStream bout = new ByteArrayOutputStream ();  
   DataOutputStream dout = new DataOutputStream (bout);  

   // Write sequence number to packet  
   dout.writeInt(sequenceNumber);  

   // Get data and put in packet  
   sendBuffer = bout.toByteArray();  

   // Create packet for response  
   DatagramPacket response = new DatagramPacket
   (sendBuffer, sendBuffer.length, addr, port);  
     
   // Send packet through out datagram socket  
   m_datagramSocket.send(response);  
  }  
  catch (IOException ioe)  
  {  
   System.err.println ("Error sending packet - " + ioe);  
  }  
 }  
   

 private void randomSleep()  
 {    
  try  
  {  
   // Generate a random number between five hundred and 
   two thousand five hundred milliseconds  
   int randomValue = (random.nextInt() % 2000) + 500;  
   if (randomValue < 0 ) randomValue = -randomValue;  

   // Sleep for a random length of time  
   Thread.sleep( randomValue );  
  }  
  catch (InterruptedException interrupt)  
  {  
   // Ignore - sleeping is for a random length, so  
   // if we are interrupted that is fine  
  }  
 }  
}  

Listing 6.  

import java.net.*;  
import java.io.*;  

// Receiver - demonstrates timeouts on a stop-and-wait protocol   
//   
// Written by : David Reilly  
// Last modification date : March 1, 1998  
//  
//  
public class Receiver   
{   
 // Private member variables  

 // Internet address of sender  
 private InetAddress m_addr;  
   
 // Port of sender  
 private int m_port;  

 // DatagramSocket to communicate with sender  
 private DatagramSocket m_datagramSocket;  
   
 // Public constants  

 // Default packet size  
 public static final int packetSize = 20;  

 // Port for communication  
 public static final int port = 8000;  

 // Number of re-tries before terminating  
 public static final int maxRetry = 10;  

 // Constructor for receiver  
 public Receiver( )  
 {  
  try  
  {  
   // Create a datagram socket bound to a specific port  
   m_datagramSocket = new DatagramSocket ( port );  
  }  
  catch (IOException e)  
  {  
   System.err.println ("Error binding to socket - " + port);  
   System.exit(1);  
  }  
 }  

 public void receive()  
 {  
  // Local variables  
  int retryCount = 0;  
  int sequenceNumber = 0;  
  boolean messageArrived;  

  // Datagram packet for messages  
  DatagramPacket message = new DatagramPacket 
  ( new byte[packetSize], packetSize);  

  try  
  {  
   // Receive the first message  
   m_datagramSocket.receive(message);  

   // Set a timeout for future communications  
   m_datagramSocket.setSoTimeout ( 5000 );  

   // Use the address and port of this packet's sender  
   m_addr = message.getAddress();  
   m_port = message.getPort();  

   System.out.println ("Packet received from " + m_addr.getHostName() 
   +":" + m_port);  
  }  
  catch (IOException e)  
  {  
   System.err.println ("Error reading packet - " + e);  
   System.exit(1);  
  }  

  // Wait for the first message  
  for (;;)  
  {  
   try  
   {  
    // Every twelfth packet, simulate a delay  
    // This will cause timeouts at sender, and  
    // packets will be re-sent by sender.  
    if ( sequenceNumber % 12 == 0)  
     try  
     {  
      // Sleep for ten seconds  
      Thread.sleep(10000);  
     }  
     catch (InterruptedException e)  
     {  
      // Ignore, as timeout is only for simulation purposes  
     }  

    // Send response  
    sendPacket(sequenceNumber, m_addr, m_port);  

    // Receive messages  
    m_datagramSocket.receive(message);  
   }  
   catch (InterruptedIOException iioe)  
   {  
    // Notify user  
    System.out.println ("TIMEOUT : " + sequenceNumber);  
    continue;  
   }  
   catch (IOException ioe)  
   {  
    // Notify user  
    System.err.println ("IOException -" + ioe);  

    // Terminate  
    System.exit(1);  
   }  

   // Get sequence number of message  
   int packetNumber = getSequenceNumber(message);  
    
   // Is it an older packet  
   if ( packetNumber <  sequenceNumber )  
   {  
    sendPacket ( getSequenceNumber ( message ) , m_addr, m_port );  

    System.out.println ("Old packet (" + getSequenceNumber(message) + ") 
	acknowledged");  
   }  
   else  
   if ( packetNumber > sequenceNumber )  
   {  
    System.out.println ("Future packet (" + getSequenceNumber(message) + ") 
	received... ignoring");  
   }  
   // Packet number matches sequence number  
   else  
   {  
    // Print to screen  
    System.out.println ( "DATA : " + packetNumber );  

    // Increment sequence number  
    sequenceNumber++;  
   }     
  }  
 }  

 // Gets the sequence number from a packet  
 private int getSequenceNumber( DatagramPacket packet )  
 {  
  // Create a byte input stream to read the data  
  ByteArrayInputStream bin = new ByteArrayInputStream (packet.getData());  

  // Create a datainput stream to read sequence number  
  DataInputStream din = new DataInputStream (bin);  

  int sequenceNumber;  

  try  
  {  
   sequenceNumber = din.readInt();  
  }  
  catch (IOException ioe)  
  {  
   sequenceNumber = 0;  
  }  

  return sequenceNumber;  
 }  

 // Sends a packet  
 private void sendPacket(int sequenceNumber, InetAddress addr, int port)  
 {  
  try  
  {  
   // Byte array containing response  
   byte[] sendBuffer;  

   // Create output stream to a byte array  
   ByteArrayOutputStream bout = new ByteArrayOutputStream ();  
   DataOutputStream dout = new DataOutputStream (bout);  

   // Write sequence number to packet  
   dout.writeInt(sequenceNumber);  

   // Get data and put in packet  
   sendBuffer = bout.toByteArray();  

   // Create packet for response  
   DatagramPacket response = new DatagramPacket(sendBuffer, sendBuffer.length, addr, port);  
     
   // Send packet through out datagram socket  
   m_datagramSocket.send(response);  
  }  
  catch (IOException ioe)  
  {  
   System.err.println ("Error sending packet - " + ioe);  
  }  
 }  

 // MAIN method  
 public static void main (String args[])  
 {  
  Receiver receiver = new Receiver();  

  receiver.receive();  
 }  
}
  
      

Download Source Code Assoicated Files (Zip file format - 8.54 KB)
 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.